chore: backport auto-release.yaml polish from migration PRs - #17
Merged
Conversation
Two adjustments needed by repos with stricter yamllint configs (line length 120 vs test-release-please's 200, or the comments-indentation warning enabled). Discovered when muster's CI rejected the file copied straight from here. Mirrors the same change applied to klausctl #258, muster #792, mcp-kubernetes #450, klaus-operator #135. Net effect on test-release-please itself: nothing — our yamllint allows 200 chars and the comment-restructure is purely cosmetic. This is "source of truth" maintenance: future copies (and the eventual devctl template) start from the polished version. Changes: - Restructure the trailing pull-requests permission comment so the explanation sits ABOVE the line rather than wrapping after it. - Add inline `# yamllint disable-line rule:line-length` immediately above the git-cliff download_url (143 chars). URLs don't have natural wrap points; the inline disable is the standard escape hatch.
Defensive fix from teemow's review of muster#792. If `git-cliff --unreleased --bump --context` ever returns an empty array (e.g., theoretical no-bump-warranted-and-nothing-since-last-tag case), the current `jq -r '.[0].version'` would output the literal string "null", which slips past both the `[ -z ]` empty-string check and the `[ = last ]` equality check, and we'd end up attempting `gh release create null --target SHA`. Cheap insurance: `// empty` makes jq output nothing (empty string) instead of "null" when the field is missing. The `[ -z "$NEXT" ]` guard then catches it correctly. I couldn't empirically reproduce the empty-array case locally — git-cliff returned 1 element for every scenario I tried (HEAD at latest tag, HEAD at root commit, chore-only / style-only / non- conventional unreleased commits) — but the fix costs us nothing if the case never happens and saves us from a noisy "null" tag if it ever does. Trusting the reviewer.
fiunchinho
added a commit
to giantswarm/klausctl
that referenced
this pull request
Jun 3, 2026
From teemow's review of muster#792. If git-cliff ever returns an empty array (no unreleased commits / no bumpable commits) the current `jq -r '.[0].version'` would output the literal "null", slipping past the [ -z ] / [ = last ] skip guards and attempting `gh release create null`. `// empty` makes jq output nothing instead, which [ -z ] catches. Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/muster
that referenced
this pull request
Jun 3, 2026
From teemow's review of muster#792. If git-cliff ever returns an empty array (no unreleased commits / no bumpable commits) the current `jq -r '.[0].version'` would output the literal "null", slipping past the [ -z ] / [ = last ] skip guards and attempting `gh release create null`. `// empty` makes jq output nothing instead, which [ -z ] catches. Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/mcp-kubernetes
that referenced
this pull request
Jun 3, 2026
From teemow's review of muster#792. If git-cliff ever returns an empty array (no unreleased commits / no bumpable commits) the current `jq -r '.[0].version'` would output the literal "null", slipping past the [ -z ] / [ = last ] skip guards and attempting `gh release create null`. `// empty` makes jq output nothing instead, which [ -z ] catches. Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/klaus-operator
that referenced
this pull request
Jun 3, 2026
From teemow's review of muster#792. If git-cliff ever returns an empty array (no unreleased commits / no bumpable commits) the current `jq -r '.[0].version'` would output the literal "null", slipping past the [ -z ] / [ = last ] skip guards and attempting `gh release create null`. `// empty` makes jq output nothing instead, which [ -z ] catches. Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/muster
that referenced
this pull request
Jun 3, 2026
* ci: migrate to push-based release flow
Replaces all the existing release-related workflows / configs with the
push-based auto-release flow validated end-to-end in
giantswarm/test-release-please.
Removed: release-please workflow/config/manifest, .goreleaser.yaml, .goreleaser.ci.yaml, and the colleague-PoC auto-release.yaml.
Added:
- .github/workflows/auto-release.yaml (single workflow: git-cliff
decides bump, creates tag + GitHub Release atomically via
'gh release create')
- cliff.toml (Keep-a-Changelog sections, PR-link + author rendering
via [remote.github] integration, '(?m) (#N)$' preprocessor for
squash-merge suffixes, Full Changelog footer, --unreleased --bump
flag combo to filter to the bumped release only)
CHANGELOG.md left alone — historical reference; future releases publish
notes only to the GitHub Releases page.
CircleCI unchanged: it already had architect/upload-release-assets for the muster binary.
* fix: address muster-specific lint failures from the migration
Two issues surfaced when this PR hit muster's CI:
1. Makefile.custom.mk referenced the now-deleted .goreleaser.yaml /
.goreleaser.ci.yaml in three release-* targets and the lint-yaml
target. The release-* targets (release-dry-run, release-dry-run-fast,
release-local) are dead with goreleaser gone; remove them entirely.
Also drop the test-auto-release target (act-based simulation of the
old goreleaser auto-release.yaml shape — doesn't apply to the new
workflow). Trim the lint-yaml file list to just the surviving
workflow YAMLs.
2. auto-release.yaml line 62 (the git-cliff download_url) was 143 chars,
over muster's 120-char yamllint limit (vs. test-release-please's 200).
Add `# yamllint disable-line rule:line-length` immediately above it —
URLs don't have natural break points and this is the standard escape
hatch.
Also tidied a small comment-indentation warning in the same file: the
trailing comment on `pull-requests: read` had a wrapped second line that
yamllint flagged as misaligned. Restructured the comment block so the
explanation sits above the permission line instead of trailing it.
Verified locally with the same yamllint config muster's CI uses
(.yamllint, line-length max 120) — both files lint clean.
* ci: drop goreleaser dry-run step from ci.yaml + CLAUDE.md mention
ci.yaml still installed goreleaser and ran `make release-dry-run-fast`
on PRs as a "release smoke test". With goreleaser gone, both the
target and the test no longer apply. Drop the two steps.
Also removed the now-stale "Release" section from CLAUDE.md's
make-targets list — referenced the deleted release-dry-run-fast
target and would mislead anyone reading the docs.
* fix: jq '// empty' guard against null version slipping through
From teemow's review of muster#792. If git-cliff ever returns an
empty array (no unreleased commits / no bumpable commits) the current
`jq -r '.[0].version'` would output the literal "null", slipping
past the [ -z ] / [ = last ] skip guards and attempting
`gh release create null`. `// empty` makes jq output nothing
instead, which [ -z ] catches.
Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/klausctl
that referenced
this pull request
Jun 3, 2026
* ci: migrate to push-based release flow
Replaces two overlapping release pipelines (release-please + colleague's
goreleaser-based auto-release.yaml) with a single push-based flow built on
git-cliff + architect's existing CircleCI orbs. See the giantswarm/test-release-please
PoC for the design discussion.
Replaced:
- .github/workflows/auto-release.yaml (PR-closed trigger, always-patch,
goreleaser builds + creates the
GitHub Release)
- .github/workflows/zz_generated.release-please.yaml (release-please PR-based;
had been silently stale —
manifest pinned at 0.0.102
while real tags reached
v0.0.110 via the goreleaser
flow)
- .goreleaser.yaml (full goreleaser config)
- release-please-config.json
- .release-please-manifest.json
Added:
- .github/workflows/auto-tag.yaml — push to main / release-* triggers git-cliff,
which reads conventional commits since the
last reachable v*.*.* tag, decides the bump
(feat → minor, fix → patch, ! → major),
pushes the new tag, and creates the matching
GitHub Release with cliff-rendered notes
grouped into Added/Fixed/Changed/Security.
- cliff.toml — bump rules + release-notes template, mirrors
the section structure release-please used.
Modified:
- .circleci/config.yml — added linux/amd64,linux/arm64,darwin/amd64,darwin/arm64
to go-build (was implicit default: linux only), plus the
architect/upload-release-assets job that attaches the
built binaries to the GitHub Release created by
auto-tag.yaml. No Windows builds (architect's go-build
doesn't append .exe; would be confusing on Windows).
Left alone:
- CHANGELOG.md — kept as-is. Future releases publish notes only to the GitHub
Releases page; the existing file is now historical reference
for pre-migration entries.
Behavior differences vs. the old setup:
- Bump level: conventional-commit-driven (instead of always-patch). A `feat:`
commit now produces a minor bump; the previous flow would have produced a
patch. A breaking change produces a major bump; previously it would also
have produced a patch (silently incorrect for semver).
- Release notes: grouped by Added/Fixed/Changed/Security via git-cliff (instead
of a flat goreleaser-rendered list). Same as the section structure
release-please was originally configured to produce.
- Binary asset names: architect's naming (klausctl-linux-amd64) instead of
goreleaser's archives (klausctl_Linux_x86_64.tar.gz). Anyone consuming
release assets via a hardcoded URL/regex needs to update — flagged here
because install-script-style consumers are common for CLIs.
- No release PR. PR review on the feature PR is the gate; nothing pauses at
release time.
* refactor: rename auto-tag.yaml → auto-release.yaml
Now that the workflow does both the tag push and the GitHub Release
creation, "auto-release" better describes what it does. Matches the
rename in giantswarm/test-release-please#7. Also updated:
- workflow name field: "Auto-tag" → "Auto-release"
- concurrency group: "auto-tag-…" → "auto-release-…"
- CircleCI config comment reference
* fix: read git-cliff-action's content output, not version
Same bug as the original PoC: the action's `version` output is parsed by jq
from a `--context` JSON dump that doesn't populate sensibly for
`--bumped-version` mode, so it ends up empty and the workflow silently
skips tagging. Use the `content` output instead (which captures the
version string git-cliff writes when invoked with --bumped-version).
Mirrors giantswarm/test-release-please#8 — the bug surfaced after that
PoC PR's merge run produced no release. Caught before this klausctl PR
merged.
* feat: include PR links and author attribution in release notes
Mirrors giantswarm/test-release-please#9. Enables git-cliff's GitHub
integration so release notes show "<message> in [#N](url) by [@user](url)"
— the canonical shape used by starship, tokio, etc.
Required because giantswarm repos default to merge-commit-style PRs: the
merge subject is non-conventional and gets filtered, and the branch's
individual commits don't carry PR refs. Without this, release notes are
bare bullets with no link back to context.
Changes:
- cliff.toml: add [remote.github] with owner=giantswarm, repo=klausctl
(devctl will need to template these per-repo when generating cliff.toml
for other repos). Expand the [changelog] body template to include scope /
breaking-marker / PR link / author. Uses commit.remote.* instead of the
deprecated commit.github.*.
- auto-release.yaml: add `pull-requests: read` to job permissions for the
GitHub API lookups via GITHUB_TOKEN.
* chore: sync auto-release.yaml and cliff.toml to current shape
Copies the latest version of both files from giantswarm/test-release-please
(where the PoC has been validated end-to-end through v1.4.3). Rolls in all
the iterative fixes that landed there while this PR sat:
- Consolidated git-cliff invocations behind a single install
(one expensive call + one cheap render, ~5–8s saved per run)
- Atomic tag+release via `gh release create --target` (no
tag-without-release "stuck" state, no race with CircleCI's
upload-release-assets)
- Correct `--unreleased --bump --context` flag combination
(filters to bumped release only, doesn't drop the bump silently
like --latest --bump did)
- cliff template renders PR links + author attribution via
[remote.github] integration with commit.remote.*
- commit_preprocessors strip the squash-merge "(#N)" suffix so it
doesn't duplicate the explicit PR-link in the rendered bullet
- "Full Changelog" compare-with-previous footer (matches GitHub's
auto-generated notes format, mirrors release-please's old
CHANGELOG.md headers)
- cliff.toml whitespace-control template (no leading blank line,
no double-blank between section headers and bullets)
- Workflow named "Auto-release" (does both tag + release creation,
not just tag — that earlier naming was inherited from the original
PoC).
Only repo-specific change: cliff.toml's [remote.github].repo points at
klausctl instead of test-release-please.
* ci: drop multi-OS architectures override from go-build
Keeps the architect/go-build call at its default (linux/amd64 + linux/arm64).
The only CircleCI change this PR brings stays as the architect/upload-release-assets
addition, which attaches whatever go-build produces to the GitHub Release
that auto-release.yaml just created.
This is a behavioral regression vs. the previous goreleaser setup — Mac
users who install klausctl by downloading the darwin asset from a release
will not find one for vX.Y.Z+1. To be addressed in a follow-up (separate
PR with the multi-OS architectures + a note in the release for the
transition).
* ci: restore multi-OS architectures override on go-build
Reinstates linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 — matches
the platform set that the previous goreleaser setup shipped (minus
Windows, which architect's go-build doesn't currently handle cleanly:
it doesn't append .exe to the binary name).
Without this override, the architect default is linux-only, and Mac users
of klausctl would silently lose their darwin install path on the next
release.
* chore: sync auto-release.yaml polish from the parallel migration PRs
Same two adjustments muster/mcp-kubernetes/klaus-operator's migration
PRs all needed: restructure the trailing pull-requests permission
comment (avoid yamllint comments-indentation warning) + add inline
disable-line above the git-cliff download_url (143 chars, over the
120 limit some repos enforce).
klausctl itself may not have a yamllint config that catches these —
the sync is for consistency so the workflow content is byte-identical
across all four migration PRs (devctl will eventually template this;
the template should match what's deployed everywhere).
* fix: jq '// empty' guard against null version slipping through
From teemow's review of muster#792. If git-cliff ever returns an
empty array (no unreleased commits / no bumpable commits) the current
`jq -r '.[0].version'` would output the literal "null", slipping
past the [ -z ] / [ = last ] skip guards and attempting
`gh release create null`. `// empty` makes jq output nothing
instead, which [ -z ] catches.
Mirrored from giantswarm/test-release-please#17.
fiunchinho
added a commit
to giantswarm/mcp-kubernetes
that referenced
this pull request
Jun 3, 2026
* ci: migrate to push-based release flow
Replaces all the existing release-related workflows / configs with the
push-based auto-release flow validated end-to-end in
giantswarm/test-release-please.
Removed: the legacy create_release_pr.yaml / create_release.yaml / validate_changelog.yaml trio, the colleague-PoC auto-release.yaml, and (if present) .goreleaser configs.
Added:
- .github/workflows/auto-release.yaml (single workflow: git-cliff
decides bump, creates tag + GitHub Release atomically via
'gh release create')
- cliff.toml (Keep-a-Changelog sections, PR-link + author rendering
via [remote.github] integration, '(?m) (#N)$' preprocessor for
squash-merge suffixes, Full Changelog footer, --unreleased --bump
flag combo to filter to the bumped release only)
CHANGELOG.md left alone — historical reference; future releases publish
notes only to the GitHub Releases page.
CircleCI unchanged: this is a chart-wrapped service — users consume the container image + chart via the existing architect publish flow, not a binary download.
* fix: address mcp-kubernetes-specific lint failures from the migration
Applies the same set of fixes muster needed when its CI hit the
migration. mcp-kubernetes was about to fail the same way once its
Lint and Test ran:
1. Makefile.custom.mk referenced the deleted .goreleaser.yaml /
.goreleaser.ci.yaml in three release-* targets and the lint-yaml
target. Removed those targets entirely; trimmed the lint-yaml file
list. Also dropped the test-auto-release act-based simulation
(modeled after the old goreleaser auto-release flow, no longer
applicable).
2. ci.yaml installed goreleaser and ran `make release-dry-run-fast`
on PRs as a release-smoke test. Both steps removed.
3. auto-release.yaml's git-cliff download_url line was over the 120
char yamllint limit. Added an inline `# yamllint disable-line
rule:line-length` immediately above it (URLs don't have natural
wrap points). Also restructured the trailing pull-requests permission
comment that yamllint was flagging as misaligned (warning, not
error, but worth fixing while we're here).
Verified locally with the repo's .yamllint.yaml — auto-release.yaml
and ci.yaml both lint clean. (Pre-existing comment-spacing warnings
on ci.yaml are unrelated.)
* fix: jq '// empty' guard against null version slipping through
From teemow's review of muster#792. If git-cliff ever returns an
empty array (no unreleased commits / no bumpable commits) the current
`jq -r '.[0].version'` would output the literal "null", slipping
past the [ -z ] / [ = last ] skip guards and attempting
`gh release create null`. `// empty` makes jq output nothing
instead, which [ -z ] catches.
Mirrored from giantswarm/test-release-please#17.
* fix(ci): track go.mod toolchain instead of hard-coded 1.26.3
The ci.yaml workflow had `go-version: '1.26.3'` hard-coded with the
comment "Match the version used in auto-release" — that referred to the
goreleaser-based auto-release.yaml which this migration deleted. With
goreleaser gone, the rationale for pinning to a specific Go version
went with it, and the pinned 1.26.3 had drifted behind go.mod's
`toolchain go1.26.4` directive.
The drift was masking real failures: govulncheck (run with
GOTOOLCHAIN=local) was checking against the CI-installed Go 1.26.3
stdlib and finding three recent CVEs (GO-2026-5037 / 5038 / others
in mime/x509/textproto), all of which are FIXED in 1.26.4. main was
failing the same way for the same reason; this PR was inheriting a
pre-existing CI bug.
Switch to `go-version-file: go.mod` so the workflow tracks whatever
toolchain go.mod pins. Future toolchain bumps in go.mod automatically
propagate to CI; no two-place updates.
fiunchinho
added a commit
to giantswarm/klaus-operator
that referenced
this pull request
Jun 3, 2026
* ci: migrate to push-based release flow
Replaces all the existing release-related workflows / configs with the
push-based auto-release flow validated end-to-end in
giantswarm/test-release-please.
Removed: the legacy create_release_pr.yaml / create_release.yaml / validate_changelog.yaml trio, the colleague-PoC auto-release.yaml, and (if present) .goreleaser configs.
Added:
- .github/workflows/auto-release.yaml (single workflow: git-cliff
decides bump, creates tag + GitHub Release atomically via
'gh release create')
- cliff.toml (Keep-a-Changelog sections, PR-link + author rendering
via [remote.github] integration, '(?m) (#N)$' preprocessor for
squash-merge suffixes, Full Changelog footer, --unreleased --bump
flag combo to filter to the bumped release only)
CHANGELOG.md left alone — historical reference; future releases publish
notes only to the GitHub Releases page.
CircleCI unchanged: this is a chart-wrapped service — users consume the container image + chart via the existing architect publish flow, not a binary download.
* chore: keep auto-release.yaml in sync with the other migration PRs
Same workflow-file polish that muster and mcp-kubernetes needed for their
yamllint configs. klaus-operator has no .yamllint config so these don't
fix a current failure — they keep the auto-release.yaml content
byte-for-byte identical across all three migration PRs so future
maintenance (e.g. devctl-generated regeneration) doesn't drift between
repos.
- Restructure the trailing pull-requests permission comment so it sits
above the line instead of wrapping after it (avoids the
comments-indentation warning that some yamllint configs flag).
- Add inline `# yamllint disable-line rule:line-length` above the
git-cliff download_url (143 chars — over the 120 limit many repos use).
* fix: jq '// empty' guard against null version slipping through
From teemow's review of muster#792. If git-cliff ever returns an
empty array (no unreleased commits / no bumpable commits) the current
`jq -r '.[0].version'` would output the literal "null", slipping
past the [ -z ] / [ = last ] skip guards and attempting
`gh release create null`. `// empty` makes jq output nothing
instead, which [ -z ] catches.
Mirrored from giantswarm/test-release-please#17.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the migration PRs (klausctl/muster/mcp-kubernetes/klaus-operator) copied this repo's `auto-release.yaml` and ran it through their respective lint pipelines, two adjustments surfaced as needed:
Line-length over the 120-char limit that several giantswarm repos enforce (test-release-please's own `.yamllint` allows 200, so the issue was invisible here). The git-cliff download URL is 143 chars and URLs don't have natural wrap points — added inline `# yamllint disable-line rule:line-length` immediately above it.
`comments-indentation` warning on the wrapped trailing comment after `pull-requests: read`. Restructured the explanatory comment so it sits above the line rather than wrapping after it.
Net effect on this repo
Nothing functional changes for test-release-please itself — our yamllint allows 200 chars and we didn't have the comments-indentation rule enabled. This is purely source-of-truth maintenance: future copies (and the eventual devctl template) start from the polished version that works under stricter configs.
Same fix landed in the other migration PRs
Test plan