Skip to content

ci: publish a uniquely versioned dev build to TestPyPI - #703

Open
eltociear wants to merge 1 commit into
unitaryfoundation:mainfrom
eltociear:fix-testpypi-version-collision
Open

ci: publish a uniquely versioned dev build to TestPyPI#703
eltociear wants to merge 1 commit into
unitaryfoundation:mainfrom
eltociear:fix-testpypi-version-collision

Conversation

@eltociear

Copy link
Copy Markdown

Fixes #350.

The problem

python-publish.yml builds once and sends that same artifact to both TestPyPI and PyPI. On a workflow_dispatch run, pyproject.toml still carries the version of the last release, and TestPyPI never allows a filename to be reused:

400 File already exists ('ucc-0.4.5-py3-none-any.whl', with blake2_256 hash ...). See https://test.pypi.org/help/#file-name-reuse

The change

release-build now produces a second artifact, testpypi-dists, built after appending a PEP 440 dev segment to the version, and testpypi-publish uploads that instead:

DEV_SUFFIX=".dev$(date -u +%Y%m%d)${{ github.run_number }}"
sed -i -E "s/^version = \"([^\"]+)\"$/version = \"\1${DEV_SUFFIX}\"/" pyproject.toml
  • release-dists is built and uploaded first and is left untouched, so what pypi-publish sends to real PyPI is still exactly the tagged version.
  • The run number is included alongside the date so that two manual runs on the same day do not collide with each other either.

Note on the suggested reference

@jordandsullivan suggested following mitiq's publish-testpypi.yml, which appends the date directly to the version (\1${DATE}). Applied here that yields 0.4.1220260729, which sorts above the real 0.4.12 release — a test build would look newer than the release it was testing. A .devN segment sorts below the release instead, and is the "pre-release specific naming convention" the issue asks for.

Out of scope

On workflow_dispatch the pypi-publish job also runs (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') and would hit the same "file already exists" wall on real PyPI, since the release build deliberately keeps the unchanged version. Whether a manual dispatch should reach real PyPI at all felt like a maintainer call, so I have left that behaviour alone — happy to follow up if you would like it gated.

Verification

The workflow YAML parses, and the version-rewrite step was run against the current pyproject.toml: it produces version = "0.4.12.dev<date><run>" and leaves every other line untouched (version = appears exactly once in the file). I could not exercise the workflow end to end, since that needs the repo's testpypi environment.

🤖 Generated with Claude Code

TestPyPI permanently refuses a filename it has already accepted, so a manual
run of this workflow -- where pyproject.toml still carries the version of the
last release -- failed with "400 File already exists" (unitaryfoundation#350).

Build a second, separately named copy for TestPyPI carrying a PEP 440 dev
segment (.devYYYYMMDD<run_number>), and publish that instead. The release-dists
artifact is untouched, so the build that reaches real PyPI is still the exact
version that was tagged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Test pypi builds broken on manual runs

1 participant