diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6c69290 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,32 @@ +## Release + +Say **"Release"** (or "Release X.Y.Z") and the `release` skill runs it: commit, push, tag, +wait for the pipeline, then open the wrapper-chart PR against `Ryuvia/charts`. It stops +there — merging and the Flux reconcile stay manual, deliberately. + +Preconditions and the plan, without side effects: + +```sh +~/.claude/skills/release/scripts/release-preflight # state + suggested version +~/.claude/skills/release/scripts/release-preflight vX.Y.Z # validate that release +``` + +Config is `.release.conf` here plus `make release-vars`. The process itself lives in +`~/.claude/skills/release/`; why it is shaped this way is in README.md §Releasing. + +Two things about this repo specifically: + +- **The pipeline has no image scan.** `.gitea/workflows/release.yaml` runs `test`, + `binaries`, `image` and `chart`. A green release run is not evidence the image is + CVE-clean, and a release note must not imply it is. +- **The wrapper chart has two `tag:` lines** — the app image and the python backup sidecar — + so `chart-bump` needs `--image "$IMAGE"` to know which one moves. + +## Checks + +`make fmt lint test helm-lint` mirrors `.gitea/workflows/ci.yaml`, so a green gate here means +a green pipeline there. The one deliberate difference is `-race`, which CI does not run; see +the comment on the `test` target. + +There are deliberately no `build`/`push`/`helm-push` targets — the workflow owns publishing, +and it builds multi-arch. Publishing happens by pushing a tag. diff --git a/README.md b/README.md index cd200c0..013a08a 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ with the app — chart `x.y.z` is always app `vx.y.z`: ```bash helm upgrade --install terdut-server oci://git.ryuvia.com/niklas/terdut-server \ - --version 0.9.0 \ + --version 0.9.2 \ --namespace terdut-server --create-namespace \ --set networking.hostname=terdut.example.com ``` @@ -661,3 +661,52 @@ go test ./... # run all tests go build ./... # compile all packages go run ./cmd/terdut # run locally ``` + +`make fmt lint test helm-lint` is the gate. It mirrors `.gitea/workflows/ci.yaml` step for +step, so a green run here means a green pipeline — with one deliberate exception: `make test` +adds `-race`, which CI does not. The sweeper, the notifier goroutine and the dead man's switch +sweep all touch the same single database connection, and a race between them would surface as +a flaky incident in production rather than as a red build. + +## Releasing + +``` +push to main → ci.yaml gofmt, go vet, go test +push tag vX.Y.Z → release.yaml same gate, then publish: + git.ryuvia.com/niklas/terdut-server:vX.Y.Z + oci://git.ryuvia.com/niklas/terdut-server X.Y.Z +PR to Ryuvia/charts → bump the wrapper chart to X.Y.Z; on merge + Flux reconciles and the release rolls out +``` + +Both artifacts go to the **personal** Gitea namespace rather than `ryuvia`, because Gitea +scopes package visibility to the owner with no per-package override — so `ryuvia/*` is private +because the org is. Publishing to `niklas` keeps them anonymously pullable, which is why no +pull secret is needed in the cluster. Same reasoning, and the same choice, as riksdata and +rd-web. + +Saying **"Release"** runs all three rows: the `release` skill commits, pushes, tags, waits for +the pipeline, and opens the `Ryuvia/charts` PR, stopping before the merge. See +`~/.claude/skills/release/`, or `.release.conf` here for this repo's part of it. + +The chart is published **only** from the tag, by the `chart` job. There used to be a second +publisher on every `charts/**` push to main, and the two raced for the same chart version with +different answers — chart 0.9.0 went out reading `appVersion: "latest"` that way. One +publisher, triggered by the tag (`766f439`). The cost is that a chart-only change has no +version of its own and rides the next app tag. + +There is deliberately **no** `make build` / `make push`. The workflow builds +`linux/amd64,linux/arm64` through buildx; a local single-platform push would land on top of +the multi-arch tag and stay invisible, because the tag would still resolve — just not on +arm64. Publishing happens by pushing a tag. + +Two things the release process needs to know about this repo: + +- **The pipeline has no image scan**, unlike riksdata and rd-web. A green release run is not + evidence the image is CVE-clean. +- **The wrapper chart's `values.yaml` has two `tag:` lines** — the app image and the python + backup sidecar — so `chart-bump` is given `--image` to say which one moves. + +The wrapper chart must have **its own `version:` bumped in the same commit**. Flux reconciles +with `reconcileStrategy: ChartVersion`, so a chart whose version did not change produces no +new artifact and the change is never deployed — with no error anywhere.