Releasing a new version¶
Step-by-step guide for maintainers publishing a MKurator release. Consumers install published artifacts via INSTALL_AND_USE.md.
Related: CONTRIBUTING.md (commits), CICD.md (CI behaviour), ADR-0008, ADR-0016.
On this page¶
| Section | |
|---|---|
| π | Overview |
| β | Pre-release checklist |
| π·οΈ | Version and changelog |
| π | Tag and publish |
| π¦ | What CI publishes |
| π§ | Rebuild or fix a failed release |
| βοΈ | Verify after release |
Overview¶
Releases are tag-driven: push an annotated-style lightweight tag vX.Y.Z on
main and .github/workflows/release.yaml
builds, scans, signs, and publishes artifacts. Version numbers are not bumped
by CI β you commit Chart.yaml and CHANGELOG.md on main first.
Semver on 0.y.z while the API is v1alpha1: use minor (0.3.0) for
user-visible features or breaking operator/API behaviour; patch (0.2.3)
for fixes only. Breaking commits use ! in the subject (see
CONTRIBUTING.md).
Pre-release checklist¶
Record the commit you will tag (after the prepare commit, if any):
git checkout main && git pull
RELEASE_SHA="$(git rev-parse HEAD)"
echo "Tagging: ${RELEASE_SHA}"
Run from the repository root on that commit:
task verify
task lint
task test:run
Before publishing a release tag, also run (or confirm green on GitHub for
${RELEASE_SHA}):
task ci:integration # Docker MQ + mqweb β workflow integration.yaml
task ci:e2e # kind + IBM MQ β workflow e2e.yaml (slow)
task vuln:check # same as CI test job
Before tag: confirm E2E and Integration (and full CI) are green on
${RELEASE_SHA} β not only βlatest green on mainβ from an older push.
Automated release gate workflow¶
Use .github/workflows/release-gate.yaml
(Actions β Release gate β Run workflow) on the commit you will tag:
| Input | Meaning |
|---|---|
sha |
Full or short commit (empty = latest main HEAD) |
poll_timeout_minutes |
How long to wait for external check-runs (default 120) |
The workflow re-runs task verify, task test:run, and Docker MQ integration on
that SHA, then polls GitHub check-runs until CI, Integration, and E2E
(kustomize) jobs succeeded on the same SHA. E2E is not run inside this workflow
(~90 min); you must already have (or wait for) a green E2E workflow run whose
headSha matches ${RELEASE_SHA}. Record the E2E run ID or URL when tagging.
If polling fails (timeout, skipped workflows, API limits), the manual e2e
checklist job fails with gh run list / gh run view commands β do not tag
until E2E is green on the exact SHA.
CI gate on the exact SHA¶
Do not tag until all three workflow runs succeeded on ${RELEASE_SHA}
(the commit at HEAD when you create the tag), not merely βlatest green on
mainβ from an older push.
| Workflow | File | What it proves |
|---|---|---|
| CI | .github/workflows/ci.yaml |
verify, lint, test (+ Codecov upload), build, docker-build, helm-lint |
| Integration | .github/workflows/integration.yaml |
Live mqweb: queues, topics, channels, CHLAUTH, AUTHREC |
| E2E | .github/workflows/e2e.yaml |
Operator on kind + IBM MQ (Kustomize deploy) |
On GitHub: Actions β select the workflow β open the latest run on main β
confirm the commit SHA matches ${RELEASE_SHA} (copy from git rev-parse or
the run header). With the GitHub CLI:
gh run list --workflow ci.yaml --branch main --limit 5
gh run list --workflow integration.yaml --branch main --limit 5
gh run list --workflow e2e.yaml --branch main --limit 5
# Inspect a run: gh run view <run-id> --json headSha,conclusion,status
Ensure:
- [ ] All intended PRs are merged;
mainis at${RELEASE_SHA}. - [ ] CI, Integration, and E2E workflows show success for
${RELEASE_SHA}(re-run workflows on that commit if needed before tagging). - [ ] Commits since the last tag follow Conventional Commits + gitmoji.
- [ ] No accidental secrets in the tree (
task secrets:scanif unsure). - [ ] If CRDs/webhooks/RBAC changed:
task manifestsandtask verifyalready clean.
Version and changelog¶
1. Preview unreleased notes¶
task changelog
Review grouping (Features, Bug Fixes, Breaking Changes). Skipped types: docs,
test, chore, ci, build, style β see cliff.toml.
2. Choose the version¶
| Change | Example bump |
|---|---|
Breaking (feat!, refactor!, CRD contract) |
0.2.2 β 0.3.0 |
| New feature, non-breaking | 0.2.2 β 0.3.0 or 0.2.3 |
| Bug fixes only | 0.2.2 β 0.2.3 |
3. Bump the Helm chart¶
Edit charts/mkurator/Chart.yaml:
version: 0.3.0
appVersion: "0.3.0"
Keep version and appVersion aligned with the git tag (v0.3.0 β 0.3.0).
4. Regenerate CHANGELOG.md¶
task changelog:write
Commit chart bump and changelog together:
git add charts/mkurator/Chart.yaml CHANGELOG.md
git commit -m "chore(release): :bookmark: prepare v0.3.0"
Use a conventional subject; the release tag itself does not need to be in this commit.
Land the prep commit on main via pull request β direct pushes to main
are blocked by the protect-main ruleset. Tags are not covered by the branch
ruleset, so tag pushes still work.
Tag and publish¶
Create and push the tag on the merged main HEAD (triggers CI):
git tag v0.3.0
git push origin v0.3.0
CI runs only when the tag matches v*.*.* (see workflow on.push.tags).
Do not move or force-push release tags once consumers may have pulled them. Fix forward with a new patch tag instead.
What CI publishes¶
The release workflow (on tag push):
| Output | Location |
|---|---|
| Container image | ghcr.io/platformrelay/mkurator:0.3.0 (and :v0.3.0), multi-arch |
| OCI SBOM + SLSA provenance | GHCR attestations on the image |
| GitHub Release | Notes from git-cliff + install section; attached files below |
install-crds.yaml |
Kustomize CRD bundle |
install.yaml |
Full operator install (image pinned to tag) |
mkurator-0.3.0.tgz |
Helm chart tarball |
sbom.spdx.json |
SPDX SBOM |
checksums.txt |
SHA256 of release files |
| Helm chart (OCI) | oci://ghcr.io/platformrelay/mkurator |
Release notes are assembled by
hack/assemble-release-notes.sh (git-cliff
section from git-cliff-action output content, not the changelog path +
.github/release-notes-install.md).
Committed history lives in repo-root CHANGELOG.md.
Local dry-run of install manifests (without pushing):
bash hack/release-assets.sh 0.3.0 ghcr.io/platformrelay/mkurator
ls -la dist/
Rebuild or fix a failed release¶
Trivy or build failed on tag¶
- Fix the issue on
main(dependency bump,.trivyignorewith rationale, Dockerfile). - Bump patch version if the tag was never successfully consumed, or publish
a new tag (e.g.
v0.3.1). - Do not delete the failed tag on a public repo unless you are certain no one pulled it.
Rebuild assets for an existing tag (testing)¶
Use workflow_dispatch on the Release workflow with the existing tag name
(e.g. v0.3.0). This rebuilds and re-uploads GitHub Release assets without a new commit.
The tag input reaches the shell only as an env: variable (TAG_INPUT) and is
validated against the vX.Y.Z regex before any asset is built, signed, or published, so a
malformed or malicious tag fails fast with the literal value echoed and nothing is
published. (The initial checkout resolves refs/tags/<tag> as a git ref via format(),
not a shell command β a non-existent tag simply fails to check out.) See the
"No expression injection" principle in CICD.md.
Changelog wrong on GitHub Release¶
Edit cliff.toml or commit messages on main only affect future releases.
For a published release, edit release notes manually on GitHub or re-run
workflow_dispatch after fixing generation on the tagged commit.
Verify after release¶
- Open GitHub Releases β notes, attachments, tag.
- Pull the image:
docker pull ghcr.io/platformrelay/mkurator:0.3.0 - Optional cosign verify on the container image (substitute digest from GHCR):
cosign verify \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/platformrelay/MKurator/.+' \
ghcr.io/platformrelay/mkurator@sha256:<digest>
- Optional verify signed release assets (Sigstore bundle):
VERSION=0.6.0 # replace with the tag you published
curl -sLO "https://github.com/platformrelay/MKurator/releases/download/v${VERSION}/checksums.txt"
curl -sLO "https://github.com/platformrelay/MKurator/releases/download/v${VERSION}/checksums.txt.sigstore.json"
cosign verify-blob --bundle checksums.txt.sigstore.json --certificate-oidc-issuer \
https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/platformrelay/MKurator/.+' \
--checksum checksums.txt
- Smoke install from release YAML (see INSTALL_AND_USE.md):
VERSION=0.5.2 # replace with the tag you just published
curl -sLO "https://github.com/platformrelay/MKurator/releases/download/v${VERSION}/install-crds.yaml"
curl -sLO "https://github.com/platformrelay/MKurator/releases/download/v${VERSION}/install.yaml"
kubectl apply -f install-crds.yaml
kubectl apply -f install.yaml
- Confirm
CHANGELOG.mdonmainno longer lists released items under Unreleased (regenerate was done pre-tag; post-tag commits may add new unreleased).
Quick reference¶
task changelog
# edit charts/mkurator/Chart.yaml β version + appVersion
task changelog:write
git add charts/mkurator/Chart.yaml CHANGELOG.md
git commit -m "chore(release): :bookmark: prepare vX.Y.Z"
# land the prep commit via PR β main blocks direct pushes (protect-main ruleset)
git tag vX.Y.Z # on the merged main HEAD
git push origin vX.Y.Z