Use gh release create instead of ghalactic action - #212
Open
garrison wants to merge 3 commits into
Open
Conversation
The ghalactic action's main feature is turning a rich annotated tag message into the release title and body. Our tags carry only the bare version as their message, so that never applied; the action was only being used to attach `dist/*` and request GitHub's autogenerated notes, both of which `gh` does directly. Replacing it removes a third-party action from the one job that holds a token with `contents: write`, and lets that permission be scoped explicitly rather than inherited from the repository default of `write`. `checksums.sha256` was generated by the action, so it is now produced by a `sha256sum` step to keep it on the release. The action's `checksums.json` is dropped. The `Checkout tag` step is removed since `gh` reads the tag through the API rather than from a local clone, and `--verify-tag` makes it fail rather than create a tag that is missing on the remote. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Coverage Report for CI Build 32528232949Coverage remained the same at 96.524%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
A PyPI upload is irreversible: a version can be yanked, but the filename can never be reused. A GitHub release, by contrast, can be deleted and recreated freely. The previous ordering gated the irreversible step on the reversible one. That ordering had a bad partial-failure mode. If the GitHub release succeeded and PyPI then failed, the repository advertised a release whose version was not installable, and re-running the workflow could not recover on its own, because the `github` job would fail on the already-existing release before `pypi` was reached. With the order flipped, a PyPI failure leaves nothing to clean up, and a GitHub failure leaves the installable package in place with only the release page missing, which can be created by hand or by a re-run. Also drops the unused `Checkout tag` step from the `pypi` job; it publishes downloaded artifacts and never reads the repository. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
garrison
added a commit
to Qiskit/sbd-eigensolver-python
that referenced
this pull request
Aug 20, 2026
This is based on the revised workflow at Qiskit/qiskit-addon-utils#212.
Member
Author
|
A modified version of this workflow was used to generate the first release of sbd-eigensolver-python: https://github.com/Qiskit/sbd-eigensolver-python/releases/tag/1.6.0 So I think it is safe to merge here and use for the next release of qiskit-addon-utils. |
garrison
marked this pull request as ready for review
August 20, 2026 18:52
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.
This PR drops a dependency on a third-party GitHub Action in the release workflow. It follows the example of qiskit-quimb, which creates the release using the
ghtool.This PR was generated by Claude Opus 5.
Replaces
ghalactic/github-release-from-tag@v6with a plaingh release createcall.Why
The ghalactic action is actively maintained, so this isn't a migration away from something broken. The reason is that we were using almost none of it.
Its headline feature is parsing a rich annotated tag message into the release title and body. Our tags don't have one:
So the tag-message parsing, the
.github/github-release-from-tag.ymlconfig file, and the discussion/reaction features were all dormant. What we actually used was "attachdist/*, and ask GitHub to autogenerate the notes" — whichghdoes directly, with no third-party action.That matters most in this job specifically, because it is the one that holds a token with
contents: write.Changes
ghalactic→gh release create.ghis preinstalled on GitHub-hosted runners.--generate-notesreproducesgenerateReleaseNotes: "true"; a non-prerelease is the default, soprerelease: falseneeds no equivalent.permissions: contents: write. The job previously declared no permissions and inherited the repository default, which iswriteacross all scopes. Now it's scoped to what a release actually needs.checksums.sha256kept. The action generated this automatically and it's present on existing releases, so it's now produced by asha256sumstep rather than silently disappearing.checksums.jsondropped. Also generated by the action. It's the same data as the.sha256file in a different format; happy to add it back if it's used somewhere.Checkout tagstep removed. It existed because the action read the tag annotation from a local clone.ghgoes through the API, so no checkout is needed.--verify-tagadded. Without it,gh release createwill create a missing tag. This makes the job fail instead, which is the behavior we want for a tag-triggered release.--title '${{ github.ref_name }}'is technically redundant with--generate-notes, but pins the title to the bare version to match the existing releases (e.g.0.4.0).Second commit: publish to PyPI before the GitHub release
A separate fix, prompted by the PyPI job having failed on a past release.
A PyPI upload is irreversible — a version can be yanked, but the filename can never be reused. A GitHub release is fully reversible — delete it, fix, recreate. The old ordering (
pypineedsgithub) gated the irreversible step on the reversible one, which is backwards.The partial-failure matrix makes the case:
github→pypi)pypi→github)githubjob fails on the already-existing release beforepypiis reached.If exactly one of the two succeeds, it should be the one that can't be redone. PyPI is also the step with more moving parts — OIDC trusted publishing plus the
pypienvironment gate — which is presumably why it's the one that has failed before.The job blocks are also swapped in the file so it reads in execution order, and the
pypijob's unusedCheckout tagstep is dropped (it publishes downloaded artifacts and never reads the repository).Verification
actionlintpasses clean on the workflow, including its shellcheck pass over the newrun:steps, and the job graph resolves with no cycle (pypi←build_*,github←build_*+pypi).The release path itself can't be exercised without pushing a tag, so the first real test will be the next release — the failure modes to watch are the token/permission pair and the
dist/*glob.