Skip to content

fix(release): publish every package version missing from PyPI - #35

Open
Kevin-Liu-01 wants to merge 1 commit into
mainfrom
k/publish-missing-versions
Open

Kevin-Liu-01 wants to merge 1 commit into
mainfrom
k/publish-missing-versions

Conversation

@Kevin-Liu-01

@Kevin-Liu-01 Kevin-Liu-01 commented Oct 12, 2026 •

Copy link
Copy Markdown

Summary

PyPI still serves gt-i18n, gt-flask and gt-fastapi 0.1.0, generaltranslation 0.0.4, and generaltranslation-intl-messageformat and generaltranslation-supported-locales 0.0.4. Every release-PR merge from 2026-03-09 to 2026-03-19 failed in the publish job's tag step, and that failure stopped the run before the build and publish steps. The tags for 0.1.1 to 0.3.0 exist on GitHub, but no GitHub release or PyPI upload was made from them.

This PR changes .github/workflows/release.yml:

  • The workflow also runs by hand (workflow_dispatch). The sampo release job runs only on a push, and the publish job runs only from main.
  • On a version-bump push to main, or on a manual run, the publish job builds every package version that PyPI does not have. The build step runs even when tagging or the release notes failed (!cancelled()).
  • For each package, it asks PyPI first. A 404 builds the version, a 200 skips it, and any other status fails the run. curl retries three times.
  • It refuses to build a version whose package folder changed since that version's tag, ignoring README.md and CHANGELOG.md, and the whole run stops with an error that names the package.
  • It publishes only when every build succeeded, and logs a message when every version is already on PyPI.
  • Checkout uses fetch-depth: 0, so the tags and the diff against them are available.

Size: 1 file, +40/-8.

Decisions

  • A run can build only each package's current version, so 0.1.1 to 0.3.0 stay unpublished.
  • A version must be published from the code it was tagged with. A package whose code changed without a version bump stops the run before anything is uploaded.
  • Merging this PR publishes nothing. The build step runs only when a pyproject.toml version changed in the pushed commit, or on a manual run.
  • A manual run before the release PR would upload gt-i18n, gt-flask and gt-fastapi 0.3.0, which still expire translations after 60 s. After the SDK PRs merge and before the release PR bumps the versions, a manual run fails the guard for gt-fastapi, gt-flask or gt-i18n and uploads nothing. The release PR's merge is the intended first run.

Test plan

Run on this branch (k/publish-missing-versions at 6eaeb03, on origin/main c3fe22b, still the latest main on 2026-10-11):

  • The workflow parses with PyYAML 6.0.3. Its triggers are push and workflow_dispatch, and the job and step conditions are the ones listed above.
  • Dry run of the new build step on this branch, with uv build replaced by an echo and real PyPI lookups: it would build generaltranslation-intl-messageformat 0.0.5, generaltranslation-supported-locales 0.0.6, generaltranslation 0.1.0, gt-fastapi 0.3.0, gt-flask 0.3.0 and gt-i18n 0.3.0. It skipped generaltranslation-icu-messageformat-parser 0.0.3, which is already on PyPI.
  • The same dry run on fix(gt-i18n): keep translations loaded after the cache expires #36 (k/gt-i18n-cache-expiry), which changes gt-i18n without a version bump, stopped with "gt-i18n changed since gt-i18n@0.3.0; bump its version before publishing" and exit code 1.
  • uv sync --all-packages --locked, ruff check ., ruff format --check ., mypy . (163 files) and pytest (1,399 passed): clean. This PR does not change Python code.

Not run: the workflow on GitHub Actions itself, and actionlint, which is not installed on this machine.

Merge order

  1. This PR. It must merge before the release PR. Under the old workflow, the release would build only the newly tagged gt-* 0.3.1, and pip install gt-flask==0.3.1 would then fail because generaltranslation 0.1.0 is not on PyPI.
  2. The SDK fix, as two stacked PRs: fix(gt-i18n): keep translations loaded after the cache expires (fix(gt-i18n): keep translations loaded after the cache expires #36 (k/gt-i18n-cache-expiry)), then fix(gt-flask,gt-fastapi): load translations for every configured locale (fix(gt-flask,gt-fastapi): load translations for every configured locale #37 (k/flask-fastapi-configured-locales)).
  3. sampo's release PR, chore(release): bump versions and changelogs. It bumps gt-i18n, gt-flask and gt-fastapi to 0.3.1. When it merges, one publish run uploads those three and the catch-up versions generaltranslation 0.1.0, generaltranslation-intl-messageformat 0.0.5 and generaltranslation-supported-locales 0.0.6.
  4. The docs PR (generaltranslation/content, docs(python): match the quickstart to the fixed SDK content#622 (k/python-quickstart-loads-translations)), after 0.3.1 is on PyPI.

Ernest McCarter wrote most of gt-python. He, or whoever holds the PyPI token, should review this PR and merge the release PR.

🤖 Generated with Claude Code

RetriggerConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking improvement needed to recover incomplete uploads.

Fix All in Claude CodeFindings

  1. P2 Retries leave release files missing ▶
Fix with agent prompt
### Issue 1
.github/workflows/release.yml:112
If an upload stops after only one file reaches PyPI, the `200` branch skips that version on every later run. `uv build` creates a wheel and a source archive, so a manual retry can leave either file missing. Check the files returned by PyPI, then build incomplete releases and skip files that were already uploaded.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Updates .github/workflows/release.yml to recover current package versions missing from PyPI.

  • Release runs catch up package versions that PyPI is missing.

Kevin-Liu-01 explicitly limits recovery to current versions, permits publishing after tagging fails, and requires changed package code to receive a version bump before any upload.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Push to main or manual run] --> B{Version changed or manual run?}
  B -->|No| C[Skip build and upload]
  B -->|Yes| D[Check each current version on PyPI]
  D -->|200| E[Skip version]
  D -->|404| F{Package differs from its existing tag?}
  D -->|Other status| G[Stop without uploading]
  F -->|Yes| G
  F -->|No| H[Build package]
  E --> I{All packages checked and builds succeeded?}
  H --> I
  I -->|Yes| J[Upload built files, if any]
  I -->|No| G
Loading

Reviews (1) · Last reviewed commit: "fix(release): publish every package vers..." · Reviewed by Greptile

Every release-PR merge from 2026-03-09 to 03-19 failed in the publish
job's tag step, which stopped the run before the build and publish
steps. The 0.1.1 to 0.3.0 tags exist, but PyPI still serves gt-i18n
0.1.0 and generaltranslation 0.0.4.

On a version-bump run on main, or a manual run, the publish job now
builds every package version that PyPI does not have, even when tagging
or the release notes failed. It asks PyPI first: a 404 builds the
version, a 200 skips it, and any other status fails the run. It refuses
to build a version whose package code changed since that version's tag.
It publishes only when every build succeeded, and only from main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
version=$(grep '^version = ' "$pkg/pyproject.toml" | head -1 | sed 's/.*"\(.*\)".*/\1/')
status=$(curl -sS -o /dev/null -w '%{http_code}' --retry 3 --retry-all-errors "https://pypi.org/pypi/$name/$version/json" || true)
case "$status" in
200) echo "$name $version is already on PyPI"; continue ;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Retries leave release files missing

If an upload stops after only one file reaches PyPI, the 200 branch skips that version on every later run. uv build creates a wheel and a source archive, so a manual retry can leave either file missing. Check the files returned by PyPI, then build incomplete releases and skip files that were already uploaded.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 112

Comment:
**Retries leave release files missing**

If an upload stops after only one file reaches PyPI, the `200` branch skips that version on every later run. `uv build` creates a wheel and a source archive, so a manual retry can leave either file missing. Check the files returned by PyPI, then build incomplete releases and skip files that were already uploaded.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant