Release workflow (xberg-io/actions)
This repo publishes reusable composite actions and workflows consumed by every other xberg-io repo as uses: xberg-io/actions/<action>@v1 and uses: xberg-io/actions/.github/workflows/<wf>.yml@v1. Consumers pin the floating major tag v1, so a release is only visible to them once v1 is moved to the new commit.
Tag scheme
- Immutable version tags —
vX.Y.Z(annotated). Never re-pointed once pushed. Latest at time of writing:v1.10.2. - Floating major tag —
v1(annotated). Deliberately force-updated on every release to point at the newest release commit. This is the ref consumers pin.
Both are annotated tag objects (git cat-file -t v1 → tag), so create/move them with -a.
Preconditions (must pass before releasing)
Run from a clean checkout of main:
git switch main
git fetch origin
git status --porcelain # must be EMPTY — no uncommitted/untracked changes
git log --oneline origin/main -1 # confirm local main == remote tip
poly fmt --check . # formatting clean
poly lint . # lint clean (also: task lint)
task test # unit tests — runs `uv run pytest -v` across configured testpaths
Do not proceed if the tree is dirty or any check fails. task validate (== task lint) runs actionlint + shellcheck + shfmt via poly; the action test workflows in .github/workflows/test-*.yml are the CI gate — they must be green on main.
1. Roll the CHANGELOG and commit
CHANGELOG.md is hand-maintained with a ## [Unreleased] section. Move the accumulated Unreleased entries under a new dated version heading:
## [Unreleased]
## [vX.Y.Z] - YYYY-MM-DD
### Added
- ... (entries that were under Unreleased)
Then commit and push the release commit to main (direct commit if you have rights, otherwise land it via PR and pull the merged main):
git add CHANGELOG.md
git commit -m "chore(release): vX.Y.Z"
git push origin main
Re-run git fetch origin && git log --oneline origin/main -1 and make sure local main is exactly the commit you just pushed — the tags below must point at the pushed release commit.
2. Create the new immutable version tag (AFTER pushing)
Pick the next version by bumping the latest v1.Y.Z (patch for fixes, minor for new actions/inputs). Create it at the release commit and push it:
git tag -a vX.Y.Z -m "vX.Y.Z" # tags current HEAD (the pushed release commit)
git push origin vX.Y.Z
3. Move the floating major tag v1 to the new release
Force-update v1 to point at the same commit/tag, then force-push the v1 ref so @v1 consumers pick up the release:
git tag -f -a v1 -m "v1 -> vX.Y.Z" vX.Y.Z # re-point annotated v1 at the new version tag
git push origin v1 --force
git tag -f v1 <ref> + git push origin v1 --force is the established method for advancing the floating major. <ref> can be the new version tag (vX.Y.Z) or the release commit SHA — both resolve to the same commit.
This force-update is a deliberate, expected tag move, not a branch force-push — it is the one sanctioned exception to the repo's "never force-push" rule, and it only ever touches the
v1tag ref (never a branch). If you prefer the lease-guarded variant,git push origin v1 --force-with-leasealso works for the tag ref. Never force-move anyvX.Y.Zimmutable tag.
4. Verify
git fetch origin --tags --force
git rev-parse v1 # must equal:
git rev-parse vX.Y.Z # ... the new version tag / release commit
Both must resolve to the release commit. Consumers pinning @v1 now resolve to vX.Y.Z.