Skip to content

ci: tag each crates.io release as v<version> (port consensus Create git tag) - #1

Merged
secsovereign merged 1 commit into
mainfrom
ci/tag-releases
Oct 22, 2026
Merged

secsovereign merged 1 commit into
mainfrom
ci/tag-releases

Conversation

@secsovereign

Copy link
Copy Markdown
Member

The publish job runs cargo publish but has never created a tag; this repo has 0 tags and 0 releases. This PR adds blvm-consensus's Create git tag step to that job.

Change

A new last step in publish, Create git tag. It's the consensus step with the following differences:

  • Gate: it runs only when steps.gate.outputs.do_release == 'true' && steps.publish.outputs.published == 'true', so nothing is tagged after a skipped or failed publish.
  • Tag name and commit: VERSION_TAG="v${{ steps.version.outputs.version }}", because this job has no version_tag output. The tag goes on HEAD, which is the rebased Bump version commit that Commit version bump pushes before publishing, i.e. the exact tree that was published.
  • Error hints: the Workflows-permission hint prints the manual tag command at that HEAD sha, not github.sha. The generic push-failure message prints the same command.

Unchanged from consensus: it skips if the tag already exists on origin, errors if REPO_ACCESS_TOKEN is missing, unsets the extraheader/includeIf credentials, and pushes with x-access-token.

REPO_ACCESS_TOKEN is available to this repo as an org secret. With that token, node's Release pushed v0.1.73 at 8f4aba5, a commit that itself changed ci.yml, so a workflow-touching range wasn't rejected there.

No GitHub Release step. Consensus builds one from a release-notes generator plus attestation steps in the same job (~250 lines); that isn't cheap enough for this PR.

What changes once tags exist

All of this was run in a scratch clone against live crates.io data, using the job's own Determine version and breaking-change scripts pulled from this YAML.

  • Next version: USED_VERSIONS = tags ∪ crates.io. Tags are only created after a successful publish, so tags ⊆ crates.io and the next version doesn't change. It computed 0.1.28 with no tags, with only the backfilled v0.1.27, and with every historical version tagged.
  • No refuse or skip on the first run: the first post-merge run publishes 0.1.28 and tags v0.1.28. Nothing skips because of a tag: the version loop only steps past versions that already exist, and the new tag step only skips when that exact tag is already on origin.
  • crates.io API down: today, with no tags and the API unreachable, USED_VERSIONS=$(… | grep -v '^$') has no matches, so grep exits 1 and the default bash -e fails Determine version. This is an existing failure mode, and it fails safe. Once tags exist, the step instead picks max(tag)+1, which was 0.1.28 in the simulation. The one risk: if a publish succeeded but its tag push failed, an API outage could make it pick an already-published number. Publish would then hit "already exists", which this job treats as published=false / exit 0, and the bump commit would already be on main. This is unlikely, and it isn't worse than the current API-down behaviour; I left that logic alone.
  • Breaking-change scan (advisory only): git describe --tags --abbrev=0 now returns the last tag, so the range becomes <last tag>..HEAD instead of the HEAD~20..HEAD fallback. That's just the commits since the last release.
  • actions/checkout with fetch-depth: 0 fetches tags, so both lookups see them.

Post-merge: backfill (not pushed by this PR)

Evidence: run 37875314624 (job 113644160368), 2026-10-08 10:45 PM ET (02:45Z Oct 9).

  • Log line 731: de97c80..7b27888 HEAD -> main (the bump commit pushed).
  • Log line 913: Published blvm-primitives v0.1.27.
  • Cargo.toml at 7b27888 has version = "0.1.27", and crates.io's max_version is 0.1.27.

Run as a human, ideally before the first post-merge release:

git fetch origin
git tag -a v0.1.27 7b2788819d1c9b074f12a8090f74d6d30eb53a9b -m 'Release v0.1.27'
git push origin v0.1.27
Optional: full history. Each crates.io version mapped to its "Bump version to X" commit on main (subject plus Cargo.toml at that commit; only v0.1.27 is also confirmed by a run log)
git tag -a v0.1.1 b4002b6aec5e4db92b43fc4739d4b3df2a843580 -m 'Release v0.1.1'
git tag -a v0.1.2 7f5714db2e6d6f1b6b5298a4706c587aa5292394 -m 'Release v0.1.2'
git tag -a v0.1.3 b3124fda714bed3ff161eaae3ffd582d7234b684 -m 'Release v0.1.3'
git tag -a v0.1.4 dfb09c56756e64511a4af70b1f9a2a6f927e72be -m 'Release v0.1.4'
git tag -a v0.1.7 f9ea369ba253169bdc3b784e4393e40f1b385a44 -m 'Release v0.1.7'
git tag -a v0.1.8 02e8a15a99525f39027a294833c1c520a53db5a6 -m 'Release v0.1.8'
git tag -a v0.1.9 ce5ef7b3a4ebe760f2d5dfd99b4a1bf8b0338816 -m 'Release v0.1.9'
git tag -a v0.1.11 9a84fa7f7a86519cd5ed9ffd8d5d9481a7639bff -m 'Release v0.1.11'
git tag -a v0.1.12 d843c834074aee52b6c210c7b923cd1179824127 -m 'Release v0.1.12'
git tag -a v0.1.13 b965e6f1dff9de5c0c83cfcd1ad40371bd9f9622 -m 'Release v0.1.13'
git tag -a v0.1.14 78a258d6fda9dd08a531f3fb36d501f0684c7172 -m 'Release v0.1.14'
git tag -a v0.1.15 bac287608f5b0ecce0c88978d8170a07fb3e5e80 -m 'Release v0.1.15'
git tag -a v0.1.16 ca0411125dec75f34845b44964b0444277c4aa64 -m 'Release v0.1.16'
git tag -a v0.1.17 2585f0aeb0880cec9d0930d2f745d079cd4995ca -m 'Release v0.1.17'
git tag -a v0.1.18 e86bc5f98d8839e4a3238bc946d643f5a4f345b4 -m 'Release v0.1.18'
git tag -a v0.1.19 0e616afd6ce6bf05e39f60d93328332b96679d34 -m 'Release v0.1.19'
git tag -a v0.1.20 9e3bae27f13d32e0c3a67ad1a8587cfad05aa59c -m 'Release v0.1.20'
git tag -a v0.1.21 2a3313c498a2838773bcf7ab303e3f6df54ef7c1 -m 'Release v0.1.21'
git tag -a v0.1.22 536fbafafa3214531ace0067fb68288cd858406a -m 'Release v0.1.22'
git tag -a v0.1.23 7643a56a69aacfc3d0fd0cf3f5e5531c5390acd5 -m 'Release v0.1.23'
git tag -a v0.1.24 9b736df60c6881c74af23abec1d40c0fabe08273 -m 'Release v0.1.24'
git tag -a v0.1.25 6665d3d27ab77ebbd0ffcd6b165bde5cbe48ff33 -m 'Release v0.1.25'
git tag -a v0.1.26 57c3530c7affea7ef7fbabc1a6f59c36804ab0f1 -m 'Release v0.1.26'
git tag -a v0.1.27 7b2788819d1c9b074f12a8090f74d6d30eb53a9b -m 'Release v0.1.27'

Push with git push origin --tags, after checking that no stray local tags exist.

Does pushing a tag trigger anything? No. ci.yml runs on push: branches: [ main, develop ] with no tags: filter, and a branch-only filter doesn't match tag pushes.

Checks run

  • actionlint: no new findings compared with main (shellcheck isn't installed on the box).
  • The YAML parses, and the step is last in publish.
  • The step's script was run against a local bare remote, with set-url stubbed out:
    • it creates an annotated tag at HEAD;
    • a rerun skips because the tag already exists;
    • a push failure exits 1 and prints the manual command with the HEAD sha;
    • a missing token exits 1.
  • Merging this PR starts a release: merging is a normal push to main, so it publishes 0.1.28 and creates the first automatic tag.

Port the blvm-consensus 'Create git tag' step to the publish job: after a
successful publish, create an annotated v<version> tag at HEAD (the pushed
'Bump version' commit, i.e. the published tree) and push it with
REPO_ACCESS_TOKEN. Skips if the tag already exists on origin. The
Workflows-permission hint and the generic failure message print the manual
tag command at that commit.

Until now this repo published without tagging, so the describe-based
breaking-change scan always fell back to HEAD~20 and the version step
relied on crates.io alone. No GitHub Release step (consensus builds notes
and attestations for that; out of scope here).
@secsovereign
secsovereign merged commit a8dabe2 into main Oct 22, 2026
2 checks passed
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