feat(skills): add cozy-bump skill for cozystack monorepo package bumps#6
feat(skills): add cozy-bump skill for cozystack monorepo package bumps#6
Conversation
Cozystack maintainers regularly need to bump upstream versions of components inside the cozystack monorepo. A bump is rarely just an appVersion change — it can include vendored subchart pulls, image digest updates, breaking-change adaptation in values.yaml/templates, schema regeneration, and an ApplicationDefinition refresh. The cozy-bump skill treats the bump as a real review task: detects the upstream source pattern (vendored Helm chart, in-repo image build, or postgres-style enum), fetches the changelog between current and target versions, surfaces breaking changes / deprecations / new required keys, applies adaptations, regenerates schema and ApplicationDefinition, runs helm template + lint, commits with a Conventional-Commit message, and optionally deploys the bumped version to a dev cluster via cozyhr suspend + make apply with a ttl.sh ephemeral image registry. Single approval gate at Phase 5 keeps the user in control of every adaptation before files land. Phase 9 deploy gates explicitly on context name and refuses production-shaped contexts without override. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Add cozy-bump entry to the marketplace registry and README plugin table so it can be installed via /plugin install cozy-bump@cozystack-claude-plugins. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Portability and correctness fixes flagged in pre-merge review. Phase 9: - Replace make --eval (GNU Make 3.82+) with portable read_make_var helper that uses make --makefile=- heredoc — works on macOS GNU Make 3.81 default and Linux. - Replace date --utc (GNU only) with TZ=UTC date +... (BSD+GNU). - Drop the false NAME/NAMESPACE convention claim. Real cozystack packages set both per-Makefile with no mechanical rule, and apps/ packages don't set them at all. Read from package Makefile, treat empty as 'Phase 9 unavailable for this package shape', not 'package diverges'. - Drop kubectl config use-context — every Phase 9 call already passes --context; switching global context creates a race with the user's other shells. - Watch rollouts via kubectl get deployment,statefulset rather than hardcoded deployment/<deploy>; works for storage-shaped packages. Phase 6: - Pattern A: prefer make update target (cleans charts/ before pulling). When falling back to manual helm pull, rm -rf charts/ first — a renamed upstream sub-chart otherwise leaves the previous version stranded alongside the new one. - Pattern B: do not silently commit a values.yaml that still carries the previous image digest. Make Phase 5's plan gate explicitly branch on Pattern B + --no-deploy, requiring the user to pick local-build / maintainer-handoff / re-enable-deploy. Phase 3 / Phase 4: - Derive upstream GitHub repo from sources[] / repository / home with explicit github.com guard. home: alone is unreliable — e.g. cloudnative-pg lists home: https://cloudnative-pg.io. - Refine changelog grep terms: drop lowercase 'must' (matches every changelog), keep RFC 2119 uppercase MUST/MUST NOT/MUST be. Style: - Expand short flags throughout (jq --raw-output, kubectl --output jsonpath=, drop yq -r — mikefarah yq returns scalars unwrapped). - Add guardrail entries reinforcing --context/--namespace on every cluster call, full flag names, and portable shell idioms. Marketplace: - Trim marketplace.json description to a one-line teaser; the full long-form description already lives in SKILL frontmatter where it drives skill matching. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Round-2 review caught factual errors verified against the actual monorepo. Fixes: Phase 2: - Define $REPO_ROOT once via git rev-parse, use it consistently in Phases 7/8 instead of <repo-root> placeholder. - Relax 'Chart.yaml.version must be 0.0.0' from stop to warn — real exceptions exist (apps/foundationdb 0.1.0, system/cozystack-scheduler 0.3.0, system/kubeovn 0.38.0, tests/cozy-lib-tests 0.1.0). Phase 3 Pattern A: - Drop the dependencies: indicator. Cozystack vendors via 'helm pull --untar' into charts/, not via Chart.yaml dependencies. The single package with a dependencies: block (apps/qdrant) points at the in-tree cozy-lib library, which is not an upstream-vendor case. - Read $CURRENT_VERSION from charts/<name>/Chart.yaml. Phase 3 Pattern B: - Indicator is '^image:' target at column 0, not 'docker buildx' string anywhere in the Makefile. Phase 4: - Note the helm repo add precondition explicitly so Step 2 works when the user supplied --target-version on the CLI and Phase 3's registration step was skipped. Phase 5: - Add ExternalArtifact reality-check warning: cozystack platform operator creates every managed HelmRelease with chartRef.kind: ExternalArtifact (verified in operator/package_reconciler.go:219), so Phase 9 can only verify Pattern B image-only bumps; Pattern A chart-structure bumps require a push-to-fork workflow on real clusters. Phase 6 Step 2: - 'make update' targets in 4+ packages hardcode --version inside the recipe (cilium 1.19, kafka-operator 0.45.1-rc1, etc.) — calling blindly would refetch the previous version. Edit the Makefile's hardcoded literal to $TARGET_VERSION first, or replicate the pull manually. Add a mandatory invariant self-check on the pulled Chart.yaml.version after the operation. Phase 6 Step 4: - 'make generate' exists in only ~30 of ~153 package Makefiles (mostly apps/*). Reframe as conditional via 'make --question generate', skip silently for system/* and core/*, do not warn about missing values.schema.json for those. - Capture $RD_DIR_CHANGED via 'git status --porcelain' for Phase 8. Phase 9 Step 4-5: - Reorder outcomes: ExternalArtifact is the rule, inline chart is the exception. Move ExternalArtifact + Pattern B to the primary documented path. Document the push-to-fork handoff for ExternalArtifact + Pattern A explicitly. Phase 9 Step 6: - Don't assume 'app.kubernetes.io/instance=$RELEASE' label is set. Helm 3 doesn't inject standard labels; many cozystack system/* packages set none. Derive the selector from the workload's actual spec.selector.matchLabels via go-template. Phase 8: - Use mktemp + trap for the multi-line commit body file. - Derive sibling -rd/ paths to git-add via 'git status --porcelain packages/system/' instead of the static 'packages/system/<name>-rd/' template. - Note that 'git -C' is git's canonical short form (no --directory long form exists), so future maintainers don't try to 'fix' it per the full-flag-names rule. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
…ound-3 review issues
The biggest correctness fix: 'cozyhr resume' on the ExternalArtifact +
Pattern B deploy path does NOT commit the bump to the cluster — it
makes Flux reconcile back to the source-of-truth artifact, which still
holds the OLD image (the local ttl.sh build was never published nor
committed). Resume reverts the bump on this cluster. The previous
wording told users the opposite. The sibling cozy-deploy skill gets
this right; cozy-bump now matches.
Other fixes:
- Bare-name resolution: state explicitly that packages/library/ and
packages/tests/ are out of scope (no upstream version to track).
Drop the tests/cozy-lib-tests Chart.yaml-version exception note —
the resolver wouldn't reach it anyway.
- Phase 6 Step 4 generate-target counts: precise figures (30 of 159
Makefiles: 22 apps, 7 extra, 1 library) instead of '~30 of ~153,
almost exclusively under apps/*' which understated extra/.
- Phase 8 staging: use a targeted glob 'packages/system/${PKG_NAME}-rd/'
instead of 'git status --porcelain | awk' (breaks on rename entries
and quoted filenames) plus 'xargs --no-run-if-empty' (GNU-only flag
that BSD xargs silently consumes).
- Phase 2 step 6: stop reading current-context here. The skill's own
guardrail says the global current-context can change at any time;
reading it ten phases before use is exactly that race. Read it
freshly in Phase 9 Step 1 right before the deploy gate.
- Phase 4 Step 1: warn when 'gh release list' returns count == --limit
(likely truncated). Bump default to 200, document pagination via
'gh api repos/.../releases?page=N' for Pattern C bumps that span
many minor releases.
- Phase 3: hoist 'helm repo add' so it runs unconditionally, not only
when target-version resolution needs it. Phase 4 Step 2 then has a
clean precondition.
- Phase 6 Step 5 path 2: add a visible 'WILL FAIL WITH 403 unless you
have push access' comment in the example block so the maintainer-only
caveat is impossible to miss when skimming.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR introduces the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces the cozy-bump skill, which automates the process of bumping package versions within the cozystack monorepo. The skill handles various upstream patterns, scrapes changelogs for breaking changes, applies necessary adaptations, and supports optional deployment to dev clusters for verification. The review feedback identifies a potential issue with command-line flag conventions where git does not support the long-form --directory flag, and points out a portability issue with the GNU-specific sed --in-place flag which would fail on macOS environments.
| - **Always** treat ExternalArtifact-shaped releases differently from inline chart releases — local `values.yaml` is ignored by Flux for the former. Stop and explain rather than pretending the deploy happened. | ||
| - For Pattern C (postgres-style enums), the bump is the `hack/update-versions.sh` output — do not hand-edit `files/versions.yaml` after running the script unless the user explicitly asks. | ||
| - **Always** pass `--context $KUBE_CONTEXT` and `--namespace $NAMESPACE` to every `kubectl` and `cozyhr` call in Phase 9 — never rely on the global current-context. | ||
| - **Always** use full flag names (`--raw-output`, not `-r`; `--output name`, not `-o name`; `--directory`, not `-C`) per the cozystack project standard. Short flags in prescribed commands train the user to mix conventions. |
There was a problem hiding this comment.
This instruction is ambiguous and contradicts Phase 8 (line 373). While make supports --directory, git does not have a global --directory flag and requires -C. The current wording "--directory, not -C" might lead the model to generate invalid git --directory commands. It should be clarified that this applies to make and that git is an exception.
| - **Always** use full flag names (`--raw-output`, not `-r`; `--output name`, not `-o name`; `--directory`, not `-C`) per the cozystack project standard. Short flags in prescribed commands train the user to mix conventions. | |
| - **Always** use full flag names (`--raw-output`, not `-r`; `--output name`, not `-o name`; `--directory` for `make`) per the cozystack project standard. Short flags in prescribed commands train the user to mix conventions. Note that `git` does not support a global `--directory` flag; use `-C` for `git` as correctly noted in Phase 8. |
There was a problem hiding this comment.
Already addressed in 9267f80. The Guardrails entry now explicitly lists git -C as an exception: it states that --directory is for make and similar tools that have a long form, while git -C <dir> has no --directory form by design, so -C is the canonical spelling for git and must not be "fixed" to a long flag. See skills/cozy-bump/skills/cozy-bump/SKILL.md:706 plus the matching rationale at SKILL.md:405 (Phase 8).
| Path: | ||
|
|
||
| 1. Read `$PKG_DIR/Makefile` — find the line matching `helm pull .* --version <X>`. | ||
| 2. If a `--version <X>` is hardcoded, edit that line to `--version $TARGET_VERSION` via `sed --in-place` (or a targeted Edit). Surface the diff to the user before continuing. |
There was a problem hiding this comment.
The --in-place flag is a GNU sed extension and is not supported by BSD sed (the default on macOS). This contradicts the portability requirements stated in Phase 2 (line 36) and Phase 10 (line 613). To ensure the skill works on both macOS and Linux, use a more portable approach for in-place editing, such as redirecting to a temporary file and then moving it back, or using perl -i -pe if available.
| 2. If a `--version <X>` is hardcoded, edit that line to `--version $TARGET_VERSION` via `sed --in-place` (or a targeted Edit). Surface the diff to the user before continuing. | |
| 2. If a `--version <X>` is hardcoded, edit that line to `--version $TARGET_VERSION` via a portable `sed` command (e.g., by using a temporary file) or a targeted Edit. Surface the diff to the user before continuing. |
There was a problem hiding this comment.
Already addressed in 9267f80. The sed --in-place example was dropped from Phase 6 Step 2. The text now warns explicitly that sed --in-place is GNU-only and breaks on macOS BSD sed (which requires -i '' with a mandatory backup-extension argument), prescribes the agent's Edit tool for in-place edits instead, and points at the cozystack monorepo's own SED_INPLACE shim in hack/common-envs.mk. See skills/cozy-bump/skills/cozy-bump/SKILL.md:258.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/cozy-bump/skills/cozy-bump/SKILL.md`:
- Around line 612-613: Update the Guardrails text that enforces "Always use full
flag names" to exempt Git's -C flag: replace the incorrect guidance that
recommends `--directory` for Git with a note that Git only supports the short
`-C` form, and instruct maintainers to prefer long flags generally but use `-C`
for Git commands; update the bullet point that currently mentions
`--directory`/`-C` so it references `-C` as the valid Git option and keeps the
portability guidance elsewhere (the bullet starting with "Always prefer portable
shell idioms" and the earlier bullet mentioning `--directory`).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2dcee2da-f13f-4242-933a-84954b00e570
📒 Files selected for processing (4)
.claude-plugin/marketplace.jsonREADME.mdskills/cozy-bump/.claude-plugin/plugin.jsonskills/cozy-bump/skills/cozy-bump/SKILL.md
Round-4 review caught a real correctness bug plus several smaller
issues.
Phase 8 (correctness):
The -rd/ ApplicationDefinition directory is named after the chart's
Chart.yaml.name, NOT the package directory basename. They diverge for
apps/vpc — Chart.yaml.name = virtualprivatecloud, so update-crd.sh
writes to packages/system/virtualprivatecloud-rd/. The previous glob
matched against ${PKG_NAME}-rd/ = vpc-rd/ and would silently miss the
regenerated ApplicationDefinition, shipping a commit where appVersion
and ApplicationDefinition disagree. Fix: yq read .name from
Chart.yaml and use that for the -rd/ path. Add a self-check invariant:
if generate: target ran, git diff --cached --stat must include the
sibling -rd/ path or the commit is rejected as a 'lying bump'.
Phase 6 Step 4 (clarity):
Drop the make --question probe — it returns 0/1/2 based on
prerequisite freshness, not target presence, and cozystack's
generate: recipes are not .PHONY. Just grep ^generate: in the
Makefile.
Phase 4 Step 1 (correctness):
gh release list count comparison uses >= but warns only when extra
pages actually exist (refetch one element beyond the cap to confirm).
Indented the inner block correctly.
Phase 4 (clarity):
Replace 'normalize via semver semantics, not string compare' with
three concrete tool options: helm's native --version constraint,
the npm 'semver' CLI, or 'sort --version-sort' (with macOS gsort
caveat).
Phase 9 Step 1 (clarity):
Document the KUBECONFIG-with-multiple-files caveat where 'current'
context can resolve to an unexpected file. The AskUserQuestion
pick-context option is the safety net.
Phase 6 Step 5 path 1 (xref):
'Phase 9 Step 5A' was a stale reference — Phase 9 Step 5 has named
subsections, not lettered ones. Replaced with 'the ExternalArtifact +
Pattern B sub-path of Phase 9 Step 5'.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
The biggest framing fix: cozystack DOES have a CI workflow that
rewrites per-package values.yaml at release time. `.github/workflows/
tags.yaml` runs `make build` on `push: tags: v*.*.*`, which calls
`make image` per Pattern B package; each package's image target writes
the new digest into values.yaml via 'yq -i', and then the workflow
commits 'Prepare release vX.Y.Z'. Previous SKILL claimed 'no such
workflow exists' and built a 'lying bump' interlock around the wrong
premise — a Pattern B contributor commit that bumps Chart.yaml.appVersion
without updating values.yaml is the NORMAL, intended state between
release tags.
Phase 6 Step 5 reframed:
- Contributor mode (default, no push credentials): commit Chart.yaml/
Dockerfile/templates only, leave values.yaml at the previous release's
digest. Release CI handles the rewrite. No interlock blocking this.
- Maintainer mode (push to ghcr.io/cozystack/cozystack): build now and
commit the new digest. Rare; only for out-of-band hotfixes.
Phase 5 plan gate: replace the Pattern B + --no-deploy interlock with
a mode disclosure. Both contributor and maintainer commit shapes are
valid.
Phase 9 Step 5 ExternalArtifact + Pattern B (correctness):
- 'kubectl set image' previously read 'yq .<key>.image' and assumed a
concatenated string. Cilium and others split into repository/tag/
digest sub-keys. Detect both shapes via JSON output type and assemble
the full ref accordingly. Stop loudly on unrecognised shapes.
Phase 9 Step 6 (correctness):
- Add daemonset to the rollout enumeration. Node-level packages
(cilium, multus, kubeovn) ship their primary workload as DaemonSet;
the previous 'deployment,statefulset' miss meant Phase 9 silently
no-op'd for the canonical Pattern B examples.
Phase 9 ExternalArtifact + Pattern A handoff:
- The cozystack PackageSourceReconciler accepts both GitRepository
and OCIRepository SourceRef.Kind. The previous advice only covered
the Git case — for OCI-backed clusters there is no spec.url to edit.
Detect via 'kubectl get packagesource' and branch the handoff text
accordingly.
Phase 8 staging:
- Narrow 'git add $RD_DIR' (the whole -rd/ tree) to just the single
file 'update-crd.sh' actually writes:
packages/system/${CHART_NAME}-rd/cozyrds/${CHART_NAME}.yaml.
The rest of the -rd/ package may have unrelated unstaged edits and
must not be swept into the bump commit.
Phase 6 Step 4:
- Add explicit exit-status check on 'make generate' with stderr
capture. Silent failures (missing icon → update-crd.sh exit 1)
are otherwise easy to miss until the staging-time invariant fires.
Phase 9 Step 5 image build:
- Replace hardcoded PLATFORM=linux/amd64 with cluster node arch
detection ('kubectl get nodes -o jsonpath=...architecture}'). On
arm64 dev clusters the previous build produced amd64 images that
crashlooped with 'exec format error' after kubectl set image.
Phase 4 Step 4:
- Extend the case-sensitive RFC 2119 grep beyond MUST/MUST NOT to
cover SHOULD/SHOULD NOT/MAY/MAY NOT/REQUIRED/SHALL. These also
flag behavioral changes worth surfacing.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Guardrails: - Resolve internal contradiction: Guardrails said 'always use long flags including --directory not -C' while Phase 8 said 'git -C has no long form, do not fix'. Reword Guardrails to make the git exception explicit (git -C has no --directory long form by design; --directory is for make et al). Phase 6 Step 2 (portability): - Drop the 'sed --in-place' suggestion — GNU-only, breaks on macOS BSD sed which requires '-i ""' with backup-extension. Prescribe the agent's Edit tool instead. Cite cozystack's own SED_INPLACE shim in hack/common-envs.mk so future maintainers know the pattern is real. Phase 4 Step 1 (correctness): - Drop 'helm install --version <range>' as a filtering tool — it resolves a single version and proceeds to install it; it cannot return a list of tags in the range. Likewise 'helm search repo --versions' lists versions but doesn't accept range filtering. Promote the standalone 'semver' CLI to primary, demote helm to a 'do NOT try' note. Phase 9 Step 5 (correctness, heterogeneous clusters): - Multi-arch awareness: sample EVERY node's architecture, not just .items[0]. Heterogeneous clusters (Ampere control plane + amd64 workers; kind-on-Mac + remote arm64) silently broke half the workload before. Build a multi-arch manifest when more than one arch is present, single-arch when uniform, fail loudly when zero. Phase 6 Step 4 (correctness, exit-status detection): - Add 'set -o pipefail' before the 'make generate ... | tee' chain. Without it, the 'if !' test caught tee's exit (always 0), letting a failing make generate slip through the gate. Document the trap inline so future edits don't strip pipefail thinking it's optional. Phase 9 Step 5 (clarity, name collision): - Rename TAG -> IMG_TAG in the split-image-shape branch. The outer TAG is the build tag for the new image; reusing it for the existing image's tag field clobbers the build tag. Renaming removes the trap even though the read-after-build ordering means it wasn't a live bug. Phase 5 (clarity): - Plan template uses full path 'packages/$PKG_TYPE/$PKG_NAME', not just the suffix — easier to copy-grep against a real checkout. Phase 4 Step 4 (precision): - Document proximity-filter heuristics for the high-noise grep terms (removed/renamed/migration) so they anchor to release-header context instead of firing on phrases like 'no items removed'. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Reviewer gave LGTM on round 7; these are the four documentation-polish items they flagged as non-blocking: Phase 9 Step 3: - Trim the read_make_var portability claim from 'GNU Make 3.81 / BSD make / modern GNU Make' to 'GNU Make 3.81+'. macOS ships GNU Make, not BSD make; the BSD claim was technically untested. - Handle the system/ingress-nginx shape where the Makefile sets NAME but not NAMESPACE (expects caller to supply it). Prompt for the missing one via AskUserQuestion instead of skipping Phase 9. Phase 6 Step 2: - Cover the path where the Makefile's helm pull line has no --version at all (e.g., ingress-nginx pulls 'latest'). Inject one explicitly rather than relying solely on the post-pull self-check. Phase 3 Pattern A: - Note that the directory under charts/ is the chart's metadata .name (not the package directory name) — postgres-operator vendors cloudnative-pg, external-secrets-operator vendors external-secrets. Read via 'yq .name' from the chart's own Chart.yaml. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Summary
cozy-bumpskill for bumping a single package inside the cozystack monorepo (packages/{apps,system,extra,core}/<name>/)values.yamland templates accordingly, regenerates schema and ApplicationDefinitionhelm template+helm lintbefore the commitcozyhr suspend+make applywith attl.shephemeral image registry. Detects HelmRelease shape (inline vs ExternalArtifact — the rule on real cozystack clusters per the platform operator) and falls back tokubectl set imagefor image-only ExternalArtifact bumps. Refuses production-shaped contexts without explicit overridemarketplace.jsonand adds aREADME.mdtable rowChanges
skills/cozy-bump/.claude-plugin/plugin.json— plugin metadataskills/cozy-bump/skills/cozy-bump/SKILL.md— 10-phase skill with Guardrails and References.claude-plugin/marketplace.json— added plugin entryREADME.md— added table rowSummary by CodeRabbit
New Features
cozy-bumpplugin now available in the marketplace for automating package version management, including changelog analysis, configuration updates, and optional deployment capabilities.Documentation