From ba253b7bf722a5e5cddd5bc0c5f4c50762a1ed0b Mon Sep 17 00:00:00 2001 From: Niklas Ye Date: Wed, 30 Sep 2026 19:22:19 +0200 Subject: [PATCH] Add CI, repo CLAUDE.md, and finish Stage 0 - .gitea/workflows/ci.yaml: fmt/lint/test, same no-actions/checkout-and-manual-clone shape as terdut-server's ci.yaml, and the same reasoning for why (Node/ES2022 incompatibility on the runner image). No chart/security jobs yet -- nothing for either to check until Stage 6 / real controller code exists. - CLAUDE.md: Checks + Release sections, matching the sibling repos' convention from the workspace-level CLAUDE.md ("each repo has its own CLAUDE.md... read it before working in that repo"). Release is explicitly marked not-wired-yet rather than copying terdut-server's, since there's no chart to release against until Stage 6. - ROADMAP.md: moved the .release.conf bullet out of Stage 0 (it names a HELM_CHART this repo doesn't have yet) -- it was already duplicated into Stage 6, which is where it actually belongs. Stage 0 done: `make fmt lint test` verified green locally. Real open question the CI workflow's comments flag rather than assume past: whether storage.googleapis.com (envtest's binary source) is reachable from this Gitea runner's container network the way proxy.golang.org is -- terdut-server's own ci.yaml notes get.helm.sh/github.com are not. Only running the workflow for real will confirm; the comment names the fallback (move the job out of `container:`, like terdut-server's chart job) if it isn't. --- .gitea/workflows/ci.yaml | 68 ++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 25 +++++++++++++++ ROADMAP.md | 31 +++++++++++------- 3 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 CLAUDE.md diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..d79361a --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,68 @@ +name: CI + +# Same shape as terdut-server's ci.yaml: the release workflow gates a tag, which is +# late, so this runs the same checks on the way in instead. +# +# push is scoped to main rather than all branches so a branch pushed as part of a pull +# request is not checked twice. +# +# No actions/checkout, deliberately -- same reason as terdut-server: the runner image's +# `nodejs` package predates ES2022 static initialiser blocks, so actions/checkout@v4 +# dies with `SyntaxError: Unexpected token '{'` before running. Cloning with git +# directly avoids JS actions entirely. This repo is public, so the clone needs no +# credential. +# +# `${{ }}` values are passed through `env:` and referenced as quoted shell variables -- +# a ref name is attacker-influenced by anyone who can push a branch or open a PR. +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +env: + REPO_URL: https://git.ryuvia.com/niklas/terdut-operator.git + +jobs: + # `make fmt lint test` is exactly what a developer runs locally, so a green job here + # and a green working copy mean the same thing by construction. `test` also drives + # controller-gen/setup-envtest (via the Makefile's own `manifests generate ... test` + # chain), which needs storage.googleapis.com to fetch the envtest kube-apiserver/etcd + # binaries -- unconfirmed whether that host is reachable from this runner's dind + # bridge the way proxy.golang.org and git.ryuvia.com are (terdut-server's ci.yaml + # flags get.helm.sh and github.com as *not* reachable from here); if this job goes + # red on the fetch specifically rather than on a real test failure, move it out of + # `container:` the way the chart job in terdut-server's ci.yaml runs on the host + # instead, for the same "can't reach a fetch target from the dind bridge" reason. + test: + runs-on: ubuntu-latest + container: + image: golang:1.26.6-bookworm + volumes: + - go-mod-cache:/go/pkg/mod + - go-build-cache:/root/.cache/go-build + - gobin-cache:/go/bin + + steps: + - name: Checkout + env: + REF_NAME: ${{ github.ref_name }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + if [ -n "$HEAD_SHA" ]; then + # A pull_request ref_name is "/merge", which is not a fetchable branch. + git clone "$REPO_URL" . + git checkout -q "$HEAD_SHA" + else + git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" . + fi + + - name: Format, lint and test + run: make fmt lint test + + # No `chart` job yet -- there's no Helm chart until Stage 6 (ROADMAP.md). No + # `security` job yet either (govulncheck/gitleaks, as terdut-server has); add one + # alongside `test` once there's controller code worth scanning. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5517ba1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,25 @@ +# terdut-operator + +Kubebuilder/controller-runtime operator for terdut-server. See `DESIGN.md` for the +settled design (CRD catalog, reconciliation semantics, bootstrap/auth, RBAC) and +`ROADMAP.md` for the staged build plan this repo is following. `README.md` stays the +short pitch. + +## Checks + +`make fmt lint test` is the CI gate (`.gitea/workflows/ci.yaml` calls these targets +rather than restating them, same convention as terdut-server). `test` chains through +the Kubebuilder-scaffolded `manifests`/`generate` (`controller-gen`) and `setup-envtest` +targets automatically — everything needed lands in `bin/` (gitignored) on first run, no +separate tool install required beyond Go itself and network access to +`proxy.golang.org`/`storage.googleapis.com`. + +`make test-e2e` stands up a real `kind` cluster (`kind`/`docker` must be installed) and +is not part of the CI gate yet — it has no service-image to test against until later +ROADMAP stages produce one. + +## Release + +Not wired yet. `.release.conf` and the release-vars Makefile target land in ROADMAP.md's +Stage 6, once there's an actual Helm chart to release — see that file before assuming +the `release` skill's terdut-server/terdut-tui conventions already apply here. diff --git a/ROADMAP.md b/ROADMAP.md index 1005dd7..f4efd23 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -24,18 +24,25 @@ land in Stage 5, not before. ## Stage 0 — Scaffolding & CI -- `go.mod` (`git.ryuvia.com/niklas/terdut-operator`) + Kubebuilder scaffold - (`cmd/main.go`, `config/`, `Makefile`, `PROJECT`), matching terdut-server's - Go toolchain and house style (§3). -- `.release.conf` + a release-vars Makefile target, same shape as - terdut-server's — this repo ships a Helm chart (§1, §10), so it follows - the wrapper-chart release path, not terdut-tui's binary-only one. -- Gitea Actions CI calling `fmt lint test helm-lint`, mirroring - terdut-server's `ci.yaml`/`release.yaml` convention (its `CLAUDE.md`: "a - green gate here and a green pipeline are the same code, not two - descriptions of it"). -- Install `setup-envtest`, wire it into `make test` so the `envtest` suite - (§11) runs without needing the full `kubebuilder` CLI at test time. +- `go.mod` (`git.ryuvia.com/niklas/terdut-operator`) + Kubebuilder v4 + scaffold (`cmd/main.go`, `config/`, `Makefile`, `PROJECT`), matching + terdut-server's Go toolchain and house style (§3). Kubebuilder's own + scaffolded `Makefile` already wires `manifests`/`generate` + (`controller-gen`) and `setup-envtest` into `test`, and `golangci-lint` + into `lint`, all fetched on demand into `bin/` — no separate install + step needed beyond what `make test`/`make lint` already do. +- `.release.conf` deliberately **not** added yet: it names a `HELM_CHART` + this repo doesn't have until Stage 6. Adding it now would either be a + stub that lies about what's releasable or dead config nobody can run — + it lands in Stage 6, alongside the chart it describes. +- Gitea Actions CI calling `fmt lint test`, mirroring terdut-server's + `ci.yaml` convention (its `CLAUDE.md`: "a green gate here and a green + pipeline are the same code, not two descriptions of it") minus the + `chart`/`security` jobs, which need a chart (Stage 6) and real controller + code (Stage 1+) respectively to have anything to check. +- Drop kubebuilder's default `.github/workflows/*` scaffold — this org + runs on Gitea, not GitHub; `.gitea/workflows/ci.yaml` is the only CI this + repo has. - Housekeeping: drop the stray `.DESIGN.md.swp` (leftover vim swapfile, shouldn't be committed); correct `DESIGN.md` §6/§13's "v1-blocking, not v1-shippable" language — the service-account feature it was blocking on