Skip to content

chore: backport auto-release.yaml polish from migration PRs - #17

Merged
fiunchinho merged 2 commits into
mainfrom
polish-auto-release-template
Jun 3, 2026
Merged

chore: backport auto-release.yaml polish from migration PRs#17
fiunchinho merged 2 commits into
mainfrom
polish-auto-release-template

Conversation

@fiunchinho

Copy link
Copy Markdown
Member

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:

  1. 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.

  2. `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

  • Local yamllint with default and 120-max configs: clean
  • After squash-merge: workflow run produces a release as usual (this PR is `chore:` so the bump-decider won't trigger a new release on its own — verified by the same skip-when-no-bumpable-commits logic we've been relying on).

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.
@fiunchinho fiunchinho self-assigned this Jun 3, 2026
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.
@fiunchinho
fiunchinho merged commit 2886c08 into main Jun 3, 2026
1 check passed
@fiunchinho
fiunchinho deleted the polish-auto-release-template branch June 3, 2026 15:47
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