fluxcd/flux-controller-minor-releases
> Run the upstream Flux controller minor release procedure for helm-controller, image-automation-controller, image-reflector-controller, kustomize-controller, notification-controller, source-controller, and source-watcher. Use when branch, drafting the minor changelog, tagging, merging the release branch back to main, and adding the backport label.
npx skills add https://github.com/fluxcd/agent-skills --skill flux-controller-minor-releases
Use this skill for upstream Flux controller minor releases (vX.Y.0) only —
the release that opens a new release/vX.Y.x series. Do not use it for flux2,
pkg, or other non-controller repos.
Supported controllers:
helm-controllerimage-automation-controllerimage-reflector-controllerkustomize-controllernotification-controllersource-controllersource-watcherbelow has a reason. Do not invent substitutions, batch unrelated commands into
one shell invocation, or insert extra verification commands between documented
steps unless asked. Adapt only the version numbers.
tag-triggered release workflow, and approval waits must be watched in the
background (run_in_background) so the user can keep steering and you get
notified on completion. A foreground watch blocks the session.
https://github.com/fluxcd/source-controller/pull/2082), never the
<owner>/<repo>#<number> shorthand — full URLs are clickable from the user's
terminal.
gh pr checks <num> -R fluxcd/<repo> --watch in the background as soon as the
PR is created, and the same for tag-triggered release workflows
(gh run watch <id> -R fluxcd/<repo>).
gh pr checks --watch onlycovers CI, not maintainer approval. Poll the review state in the background:
while :; do
state=$(gh pr view <num> -R fluxcd/<repo> --json mergeStateStatus,reviewDecision --jq '.reviewDecision+" "+.mergeStateStatus')
case "$state" in "APPROVED CLEAN") echo "$state"; break;; esac
sleep 30
done
-s (sign-off). Never include Co-Authored-By lines,your own name, or any AI attribution in commit messages, PR titles, or PR
descriptions. This applies to the skill-update PR too.
session, ask a maintainer to approve it (or confirm it is already approved)
before merging.
approved — act immediately so the next step (tag push, merge to main, label PR)
unblocks. Applies only to PRs opened with the user's account this session.
commits. The release PR must stay at exactly two commits
(Add changelog entry for vX.Y.0 and Release vX.Y.0). Use
git reset --soft HEAD~2 + re-commit, or an interactive rebase, then
git push --force-with-lease.
Fixed, thanks! on the thread and resolveit.** Reply via
gh api repos/<owner>/<repo>/pulls/<n>/comments/<cid>/replies -f body='Fixed, thanks!'
and resolve via the GraphQL resolveReviewThread mutation.
git tag -s -m ...). Never create releasetags through the GitHub API — that produces lightweight tags which break
git tag -v verification.
the title. The release→main PR uses the GitHub-default humanized branch name
Release/vX.Y.x. Every PR body is a single line pointing at the flux2 minor
release tracking issue: Part of: https://github.com/fluxcd/flux2/issues/NNNN.
the final backport label PR (step 11). Tagging and merging to main are not the
last step. Walk the numbered steps and confirm each one ran before reporting
completion.
website/content/en/flux/releases/procedure.md,section Controllers: minor releases
(https://fluxcd.io/flux/releases/procedure/#controllers-minor-releases).
(Part of: https://github.com/fluxcd/flux2/issues/NNNN).
date to get the release date for the changelog entry.git fetch --all --tags --prune before reasoning about branches, tags, ormerged PRs. Do not trust stale local origin/* refs.
git and gh commands as confirmation points if the user wants that.For the controller being released (target version vX.Y.0):
main and push it.git switch -c release/vX.Y.x maingit push origin release/vX.Y.xgit switch -c release-vX.Y.0 release/vX.Y.xCHANGELOG.md entry (see "How To Build The Changelog Entry").Then commit it.
git add CHANGELOG.mdgit commit -s -m "Add changelog entry for vX.Y.0"go.mod to vX.Y.0.Inspect the actual go.mod; do not assume the self-API path form
(source-watcher uses github.com/fluxcd/source-watcher/api/v2).
config/manager/kustomization.yaml newTag to vX.Y.0.git add go.mod config/manager/kustomization.yamlgit commit -s -m "Release vX.Y.0"git push origin release-vX.Y.0release/vX.Y.x Head: release-vX.Y.0Release vX.Y.0, body Part of: <tracking issue URL>.git switch release/vX.Y.xgit pull origin release/vX.Y.xvX.Y.0 on the merged commit before tagging.api/ tag first — the release tag depends on it.
git tag -s -m "api/vX.Y.0" api/vX.Y.0git push origin api/vX.Y.0git tag -s -m "vX.Y.0" vX.Y.0git push origin vX.Y.0vX.Y.0 tag. Watch it in thebackground until it concludes successfully (images published + signed, SBOM,
SLSA provenance, GitHub release created).
10. Merge the release series branch into main via PR. This merges the whole
branch (changelog + version bump), not a cherry-pick.
main Head: release/vX.Y.xRelease/vX.Y.x. Body Part of: <tracking issue URL>.
11. Last: open the backport label PR against main. Do this only after
step 10 has merged.
git switch maingit pull origin maingit switch -c label-X.Y main.github/labels.yaml, after the previous backport: entry: - name: backport:release/vX.Y.x
description: To be backported to release/vX.Y.x
color: '#ffd700'
git add .github/labels.yamlgit commit -s -m "Add backport:release/vX.Y.x label"git push origin label-X.Ymain, title Add backport:release/vX.Y.x label, bodyPart of: <tracking issue URL>) and merge when green.
main. If you open it beforestep 10 merges, that merge moves main forward and the label PR must then
be rebased onto the new main and force-pushed
(git rebase main + git push --force-with-lease). Opening it last avoids
the rebase entirely.
A minor changelog entry summarizes what is **new in vX.Y.0 relative to the whole
vX.(Y-1) line** — not every commit since the previous minor. The hard part is
selecting exactly the right PRs.
main since the previous minor(v(X).(Y-1).0).
git log --merges --grep="Merge pull request" v(X).(Y-1).0..release/vX.Y.x
and extract the #NNNN.
gh so squash/rebase merges are not missed:gh pr list --base main --state merged --limit 200 --json number,mergedAt,title
filtered to merges after the previous minor's release timestamp.
gh pr view <n> -R fluxcd/<repo> --json number,baseRefName,state,mergedAt,title.Keep only PRs that are MERGED and have baseRefName == main. Use the PR
title from GitHub, never the local merge-commit subject (these drift; e.g. a
commit may say one thing while the PR title says another).
(anything > v(X).(Y-1).0 and < vX.Y.0). Read the ## (X).(Y-1).Z patch
sections already in CHANGELOG.md and drop any candidate whose change shipped
there. Note the patch changelogs cite the cherry-pick PR numbers
(against release/v(X).(Y-1).x), which differ from the original main PR
numbers — match by change, not by number.
PRs, the previous release's Release/v(X).(Y-1).x merge-back, and label PRs.
content already shipped in a patch) into a single Various dependency updates
bullet listing each PR link. Keep genuinely user-facing items as their own
bullets. See "Dependency update PRs" below before settling for a generic line.
Write the new section at the top of CHANGELOG.md, matching the existing minor
entries in that repo:
## X.Y.0Release date: YYYY-MM-DD (from date)⚠️ upgrade warnings (API removals, required flux migrate, etc.).When warning about a deprecated/beta API removal, link the upgrade instruction
to the canonical flux2 upgrade-procedure discussion
(https://github.com/fluxcd/flux2/discussions/5572), not to a one-off
flux migrate PR — the discussion is the maintained guide covering both the
Flux CLI and Flux Operator migration paths. Older changelog entries may still
point at a migrate PR; do not copy that, use the discussion link.
### GitRepository, ### OCIRepository,### HelmChart, ### Bucket, …) describing notable features in prose.
### General updates subsection for k8s/Go/dependency posture.Fixes: and Improvements: bullet lists, each bullet a short title plus oneor more #NNNN links.
Surface borderline items (repo-internal docs, a dep bump whose content already
shipped in a patch) to the user rather than guessing whether to headline them.
Do not reduce a dependency bump to a generic line without checking its substance.
Includes: fluxcd/pkg#NNNN), and look at the go.mod diff.
impact parenthetical. Use matching wording across controllers that pull the
same bump.
does — a bumped module often ships capabilities the controller never exercises.
git fetch --all --tags --prune before comparingv(X).(Y-1).0..release/vX.Y.x or reasoning about merged PRs.
main; the prep branch (step 2)is cut from release/vX.Y.x.
tagging. Tag from the series-branch merge commit, not from the prep branch.
api/vX.Y.0 before vX.Y.0.go.mod for the self-API path; do not assume its form.apply, inspect the file and confirm before proceeding.
After a controller minor ships, its API module often needs bumping in the
controllers that depend on it (e.g. image-reflector-controller/api in
image-automation-controller, or source-controller/api in helm-controller,
kustomize-controller, image-automation-controller, and source-watcher). This is a
separate follow-up PR per dependent repo, not part of the 11 release steps above.
main (which may already carry an earlierbump from the same release round), then
go get github.com/fluxcd/<controller>/[email protected] followed by go mod tidy.
go.mod + go.sum only. Mirror an existing sibling PRfrom the same round for the exact title/body/commit shape.
manifests** in config/default/kustomization.yaml (remote
…/releases/download/vX.Y.Z/<controller>.crds.yaml and .deployment.yaml
URLs). If it does, bump those URLs to the new version too. Some repos pin them
(source-controller is pinned by source-watcher, helm-controller, and
kustomize-controller) and some do not (image-automation-controller does not pin
image-reflector-controller). Do not assume — grep the repo.
not import a removed package version. Run go build ./... and go vet ./....
accumulating more changes during a release session, amend and force-push rather
than adding new commits.
the release is fully done. Do not keep a CI watch open on it throughout — check
CI right before merging.
or AI attribution into the skill file.
git branch -r --list 'origin/release/v*.x' | sort -Vgit tag -l 'v*' | sort -V | tailgit log --merges --grep="Merge pull request" v(X).(Y-1).0..release/vX.Y.x
gh pr list --base main --state merged --limit 200 --json number,mergedAt,title
gh pr view <n> -R fluxcd/<repo> --json number,title,url,baseRefName,state,mergedAt
Take fluxcd/flux-controller-minor-releases from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.