Repository navigation
Fix release workflow: full-history tag checkout and manual release of existing tags - #11
Merged
Merged
Conversation
…isting tags The v1.2.0 tag-push run failed in validation (20 failed) because the validate job used the default shallow checkout (fetch-depth 1, no tags). The test suite checks historical tags and commits such as v0.1.0-baseline, which a shallow checkout lacks. The tagged code itself passes: CI on aa7ba70 uses full history. - validate and build check out refs/tags/<tag> with fetch-depth 0, so all history and tags are present, and without persisted credentials. - Add workflow_dispatch with a required `tag` input, so an existing tag can be released with the current workflow definition instead of the one stored in the tag. Dispatch is accepted only from main. The tag must match vX.Y.Z[aN|bN|rcN][.postN], exist, and point to a commit on main. - validate verifies HEAD equals the tag commit (and the pushed commit for tag pushes) and exports it. build refuses to build anything but that commit. - Version validation and artifact checks use the release tag from either event (RELEASE_TAG), passed to scripts only through the environment. - Serialise runs per tag with a concurrency group. Unchanged: tag-push trigger, read-only validate/build permissions, publish needs validate and build, id-token: write only in publish, pypi environment, REPONEEDLE_FAIL_ON_SKIP strict suites, twine --strict, artifact version checks and SHA-256 checksums. tests/test_release_workflow.py checks these invariants. docs/pypi_trusted_publishing.md describes the three-job pipeline and the manual release path, and notes that a pypi environment branch rule must allow main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the release workflow failure for
v1.2.0and adds a safe way to release an existing tag with the fixed workflow. Thev1.2.0tag is left exactly where it is (aa7ba70).This PR does not publish anything. It changes only
.github/workflows/release.yml, adds a test for it and updatesdocs/pypi_trusted_publishing.md.Root cause
Release run 43172834000 (tag push
v1.2.0→aa7ba70): validation failed with 454 passed, 20 failed and 10 skipped. Build and publish were skipped.validatejob usedactions/checkout@v4with its defaults:fetch-depth: 1and no tags.tests/test_stage3_*, the history and provenance tests. They callgit rev-parse v0.1.0-baseline^{commit},git merge-base --is-ancestor 4f78cc3 …and similar, and fail with exit 128 because those objects aren't in the checkout.ci.ymland the releasebuildjob already usefetch-depth: 0. That is why CI onaa7ba70passed.Reproduced locally with Python 3.11 and
.[dev,mcp,api]installed, as in the release job:v1.2.0The 13 skips are the 6 seen in CI for missing external benchmark data and corpus, plus 7 because Windows doesn't allow file-symlink creation. On Linux those 7 run, and the 4 Windows-only junction tests skip instead.
Workflow design
RELEASE_TAG(workflowenv) isinputs.tagfor a dispatch andgithub.ref_namefor a tag push. Shell steps read it only through the environment, never through${{ }}inside a script.validateBefore checkout: checks the tag format (
vX.Y.Z, optionallyaN/bN/rcNand.postN), then checks the trigger:GITHUB_REFmust equalrefs/tags/$RELEASE_TAG;GITHUB_REFmust equalrefs/heads/main;Checks out
refs/tags/$RELEASE_TAGwithfetch-depth: 0andpersist-credentials: false.Checks that the tag exists and that
HEADis the tag's commit, then:GITHUB_SHA);origin/main.It exports the commit SHA as a job output.
Checks that the tag version,
pyproject.tomlandreponeedle.__version__agree, then runs the full suite and the strictREPONEEDLE_FAIL_ON_SKIP=1suites. These steps are unchanged except that they readRELEASE_TAG.buildrefs/tags/$RELEASE_TAGwithfetch-depth: 0.HEADequals both the tag commit and the commitvalidatetested.twine check --strict, the artifact file-name version check (now usingRELEASE_TAG) and SHA-256 checksums are unchanged.publish: unchanged. It needs[validate, build], uses thepypienvironment, and is the only job withid-token: write. It does not check out code; it downloads the build artifacts.concurrency: release-<tag>(no cancellation) stops a tag-push run and a manual run of the same tag from overlapping.v*is preserved.v0.1.0-baselinealready failed the version check; they now fail earlier.mainrequirement applies to manual dispatch only.Why a dispatch from
main, not a re-runRe-running run 43172834000 would reuse the workflow file stored at the tag, which still has the shallow checkout. A dispatch from
mainruns the fixed workflow frommainbut builds the tag's code. Every check is written inline in the workflow, not in a repository script, because the tag's tree doesn't contain new scripts.Trusted Publishing compatibility
{repository: krishika08/RepoNeedle, workflow: release.yml, environment: pypi}. A dispatched run sends the same repository, workflow file and environment in its OIDC token. PyPI's GitHub publisher does not restrict the event or ref, so no trust setting needs to change or be relaxed.pypienvironment currently has a required reviewer (krishika08) and no branch or tag rule, so a run frommaincan reach the deployment gate and still waits for approval.v*rule, which would block dispatches.v*tags and themainbranch.Validation
actionlint1.7.12 onrelease.ymlandci.ymltests/test_release_workflow.py(new, 11 tests)RELEASE_TAGexpression, tag checkout with full history in both jobs, guard ordering and patterns, validated-commit handoff, version checks, no${{ }}in scripts, permissions,needs,pypienvironment, strict suites, twine, checksums, and publish not checking out codebash -eo pipefailagainst a fresh clone of this repositoryv1.2.0checkoutRELEASE_TAG=v1.2.0passes (1.2.0 = 1.2.0 = 1.2.0).RELEASE_TAG=v1.1.0is rejected (mismatch)v1.2.0→twine check --strict→ artifact-name stepreponeedle-1.2.0wheel and sdist; PASSED; PASSED (wheelVersion: 1.2.0)Guard scenarios (20/20)
v1.2.0v1.2.0frommainmust be dispatched from main)main,1.2.0,v1.2.0;idor emptyv0.1.0-baselineGITHUB_REF≠ tagaa7ba70…v1.2.0: HEAD = tag, onmainaa7ba70…v9.9.9does not exist)main(local-only test tag)is not on main)Not done: no live dispatch was run. Before merge, a dispatch would run the old definition or need an untested ref, and
mainis the only ref allowed to publish. The live checks are the CI run on this PR and, after merge, the manual release itself.After merge (not part of this PR)
It then needs approval at the
pypienvironment gate.Not changed
v1.2.0tag: not moved, deleted, recreated or force-updated.1.2.0, the retrieval code, benchmarks,ci.yml, the Hugging Face Space and the demo API.🤖 Generated with Claude Code