Release Automation#
Decant's release process is entirely tag-driven. The just release VERSION recipe is the single local entry point: it validates the repository state and creates and pushes a signed, annotated tag that triggers the full CI pipeline.
just release VERSION#
The recipe accepts a semver string without a leading v (e.g., just release 0.2.0). Before touching git, it enforces three guards in sequence:
- Clean working tree β fails immediately if
git status --porcelainproduces any output. - On
mainβ rejects any non-mainbranch. - Up to date with
origin/mainβ runsgit fetch origin mainand comparesHEADtoorigin/main; fails if they diverge.
If all guards pass, it runs git tag -s "v<VERSION>" -m "v<VERSION>" and git push origin "v<VERSION>" . Run just check first if you want a local quality gate before tagging .
CI pipeline triggered by the tag#
Pushing a v* tag fires .github/workflows/release.yml. The job graph is :
meta (guard) β verify β build (+sign +attest) β smoke-darwin
β npm (OIDC) β npm-smoke β github-release
β homebrew-formula β homebrew-smoke β tap-update (stable latest only)
β docker (fans out in parallel, once smoke-darwin passes)
meta is the upstream guard for the entire pipeline :
- Strips the leading
vand validates the remainder as semver; any mismatch fails immediately. - Re-fetches the tag from origin and peels it to a commit; requires that commit to equal
$GITHUB_SHA, blocking manual dispatches that target a different ref. - Computes
is_latestvia a livegit ls-remoteβ a transient failure kills the job rather than silently marking a non-latest version aslatest. - Versions containing
-are treated as prereleases and never receive thelatestnpm dist-tag,:latestDocker tag, or a Homebrew tap update.
smoke-darwin is a hard gate β nothing publishes until both Apple architectures pass . npm-smoke gates the GitHub Release on all four OS/arch targets; homebrew-smoke covers three.
Failure recovery#
Every downstream job is idempotent . On failure:
- Re-run the failed workflow run directly (reuses the original tag's commit), or
- Dispatch fresh:
gh workflow run release.yml --ref vX.Y.Z -f version=X.Y.Z
Do not delete the tag β meta rejects any dispatch whose ref doesn't match the tagged commit, so accidental republishing of a stale version as current is not possible.
Key references#
| Resource | Link |
|---|---|
just release recipe | justfile:58-69 |
| Full release runbook | docs/releasing.md |
| Release workflow | .github/workflows/release.yml |