Skip to content

Release a version bump when it merges, and add a Prepare release workflow - #214

Merged
jasperblues merged 5 commits into
mainfrom
release-automation
Oct 27, 2026
Merged

jasperblues merged 5 commits into
mainfrom
release-automation

Conversation

@jasperblues

Copy link
Copy Markdown
Member

Follow-up to #158. Releases now happen on merge, and a "Prepare release" button opens the bump PR. The same change is going into drivine4j, drivine and drivine-python, and the new controller repo, liberation-data/drivine-release, can drive all three as a dated release train.

A release, end to end (RELEASING.md):

  1. Actions → Prepare release → Run. Pick patch, minor, major or prerelease, or give an exact version. The workflow bumps pyproject.toml (and uv.lock), commits on release/v<version> and opens a PR titled "Release v". The PR lists the commits since the last release.
  2. Review and merge the PR. That push to main changes the version, and release.yml releases it. CI runs as the gate, then build, publish (in the release environment) and github-release, which creates the v<version> tag and the GitHub Release on the merged commit.
  3. Pushing a vX.Y.Z tag by hand still releases it, as a fallback.

release.yml: the branch-push path. check reads the version and publishes only when v<version> isn't tagged yet and the version is later than the newest release tag, by semver precedence. Otherwise:

  • A push to main that changes pyproject.toml (and uv.lock) without a new version, or that reverts to a lower one, runs only check, and its notice says why. Nothing is built or published.
  • A version that isn't X.Y.Z(-suffix) fails the run.

Dry runs get their own concurrency group. A dry run queued behind a release could otherwise cancel a release that was waiting.

prepare-release.yml

  • Triggers: workflow_dispatch, and also workflow_call for the train controller.
  • Input checks: an exact version is checked against X.Y.Z(-suffix) before any tool reads it. It must be later than the newest tag, not tagged, not the current version, and have no existing release/v… branch.
  • Prereleases: bumped as npm version --preid rc does.
  • Concurrency: each repository has its own group.
  • Token: the PR is opened with RELEASE_PR_TOKEN if set, else GITHUB_TOKEN. With GITHUB_TOKEN, CI doesn't start on the PR by itself (a GitHub rule); the run's notice and the PR say how to start it.
  • Cross-repository calls: a call from another repository without RELEASE_PR_TOKEN fails at the first step.

drivine-python specifics: scripts/release_version.py (standard library only, tested in tests/unit/test_release_version.py) does the semver ordering and bumps. It sets [project].version and checks it with tomllib before saving. Prepare release first refuses a uv.lock that is not up to date (uv lock --check), so the PR changes only the version.

Settings for the maintainer

  • release environment: add required reviewers, the human checkpoint now that merging publishes. If its deployment rules are limited, allow the branch main as well as the tags v*.
  • Settings → Actions → General: turn on "Allow GitHub Actions to create and approve pull requests".
  • Optional RELEASE_PR_TOKEN secret: a fine-grained token with Contents and Pull requests read/write, so CI runs on the release PR.

Review. Four review passes. Among the bugs fixed:

  • an exact version reached npm/uv before it was checked;
  • prerelease bumps didn't match npm's;
  • tag ordering wasn't semver precedence;
  • the version setter could edit the wrong line;
  • a stale lock file could slip into the release PR;
  • a dry run could cancel a waiting release;
  • the concurrency group was shared across repositories when the workflow is called.

Checked locally in a sandbox, with stub gh and git push: the check cases (bump, no bump, lower, existing tag, rc ordering, tag push match and mismatch, dispatch, PR), the bump cases, and the version arithmetic against npm's semver. The real merge release, tag creation and PR opening can only be tested on GitHub.

…ase workflow that opens the bump PR.

A push to main that changes pyproject.toml now runs release.yml, which releases the version when its tag doesn't
exist yet and it is greater than the newest vX.Y.Z tag by semver, and tags the merge commit with the GitHub release.
A pushed tag still releases, as the fallback. Prepare release bumps pyproject.toml and uv.lock on release/vX.Y.Z and
opens "Release vX.Y.Z". scripts/release_version.py does the semver arithmetic both use.

Follow-up to #158.
…e a stale uv.lock, and word errors as drivine does
…fuse an exact version equal to the current one
@jasperblues
jasperblues merged commit e7121de into main Oct 27, 2026
16 checks passed
@jasperblues jasperblues mentioned this pull request Oct 28, 2026
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