Repository navigation
Publish from GitHub Releases, deriving the version from the tag - #180
Merged
Merged
Conversation
The previous workflow had the ownership backwards. It treated lib/janus-ar/version.rb as the source of truth and required the tag to agree with it, which only works if the version is bumped by hand before tagging. Releases here are cut from the GitHub Releases UI, so the tag is created first and nothing bumps the file -- every release would fail the version guard, as v8.1.0 did. Invert it: the tag is now the source of truth. On `release: published` the workflow reads the version off the tag, writes it into version.rb, refreshes Gemfile.lock (which records the gem's own version), commits that bump to main as "Release vX.Y.Z", moves the tag onto that commit, and then publishes. Nothing needs bumping by hand, and `rake release` gets the clean tree it insists on. Moving the tag keeps it honest: a checkout of vX.Y.Z is the code that was actually published, rather than the commit before the bump. It uses --force-with-lease against the SHA validated earlier in the run, so it cannot clobber a tag that moved underneath us. Because the bump lands on main, the release has to be cut from its head; the workflow checks this and says so plainly if not. bin/release.sh is removed -- it cut releases the old way and would now conflict with the workflow doing its own bumping. Co-Authored-By: Claude Opus 5 (1M context) <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.
Follow-up to #179, which fixed the mechanics of publishing but got the ownership backwards.
The problem
#179 treated
lib/janus-ar/version.rbas the source of truth and made the tag prove it agreed:That only works if you bump the file by hand before tagging. Releases here are cut from the GitHub Releases UI, so the tag comes first and nothing bumps the file — meaning every release would fail that guard, exactly as
v8.1.0did. The guard was right; the model behind it was wrong.Worth noting the old workflow would not have saved this either:
version.rbandGemfile.lockalready agreed at 8.0.1, soguard_cleanwould have passed andrake releasewould have tried to push janus-ar 8.0.1 under av8.1.0tag, which RubyGems would have rejected as an existing version.The fix — invert the ownership
The tag is now the source of truth. On
release: publishedthe workflow:github.event.release.tag_name(v8.1.0→8.1.0), rejecting anything that is not a valid gem version.main— the bump has to land there.version.rb, runsbundle installto moveGemfile.lock(it records the gem's own version in itsPATHsection), and asserts the generated file actually reports the expected version.Release vX.Y.Ztomainand moves the tag onto that commit.rubygems/release-gem— the tree is clean by now, andrake releaseskips tag creation because the tag already exists.Nothing is bumped by hand, ever.
bin/release.shis removed, since it cut releases the old way and would now fight the workflow.Two calls worth reviewing
Moving the tag keeps it honest — checking out
v8.1.0gives you the code that was actually published, not the commit before the bump. It uses--force-with-leasepinned to the SHA validated in step 2, so it cannot clobber a tag that moved underneath the run. If you would rather the tag stayed put, deleting those three lines is the whole change; the cost is that tags point one commit behind the version they name, which is the drift that caused this mess in the first place.Requiring the tag at
main's head is what makes the commit-back safe. It rules out releasing from an older commit or a maintenance branch. Nothing in this repo does that today, and the error message says exactly what to do if you hit it.Verification
I extracted each
run:block straight from the YAML (so it is dedented exactly as bash will receive it) and executed them:v8.1.0,v8.1.0.rc1,v10.0.2, bare8.1.0; rejectsv8.1,v8.1.0-beta1(RubyGems needs a dot, not a dash),vfoo.v8.1.0(atmainhead) and capturesTAG_OBJECT=84d08cc; correctly rejectsv8.0.1with the diagnostic naming both SHAs.version.rbbyte-identical in shape to the current one, movesGemfile.locktojanus-ar (8.1.0), and passes RuboCop. Pre-release path verified too:v8.2.0.rc1→PRE = 'rc1',Janus::VERSION.to_s == "8.2.0.rc1".rubocop --parallelclean (28 files); all three workflow/config YAMLs parse; gemspec still ships 19 files and no executables.What I could not test locally is the end-to-end run — the commit-back, the tag move, and the RubyGems push only happen on a real
release: publishedevent. The first actual release is the proof.Before the next release
The orphan
v8.1.0tag from the failed attempt is still on the remote, pointing at the #179 merge commit. It needs deleting before you re-release, otherwise the Releases UI will reuse the existing tag, which will no longer be atmain's head once this merges, and the workflow will correctly refuse:Then create the
v8.1.0release from the UI as normal.🤖 Generated with Claude Code