refactor(controllers): unified Gitea client SUPERSET API + consolidation (CC2, #1095) (#1136)
CC1 (#1135) promoted the easy-to-merge shared internals (semver, render,
placement, labels) but explicitly DEFERRED the Gitea HTTP client because
the four Group C controllers (slices C1-C4) shipped four divergent
client surfaces:
* organization (C1): Org+Repo CRUD with `Org`/`Repo` struct returns;
`EnsureRepo(ctx, org, name, desc, private) (Repo, error)`
* blueprint (C3): File CRUD via `*FileResponse`;
`EnsureRepo(ctx, org, repo) error`
* environment (C2): File CRUD via `*FileContent` + `UpsertFile` (with
committer attribution); BaseURL must include `/api/v1`
* application (C4): File CRUD via `*FileResponse`;
`EnsureRepo(ctx, org, repo) error` + `EnsureBranch`
The two `EnsureRepo` shapes collide on signature. CC2's task: design the
SUPERSET, migrate every controller without behavior change.
What CC2 ships:
* `core/controllers/internal/gitea/{client,DESIGN}.go` + `client_test.go`
— single unified Client. The SUPERSET method list:
Org+Repo CRUD (won from): C1 — only implementer
GetOrg(ctx, slug) (Org, error)
CreateOrg(ctx, slug, fullName, desc, vis) (Org, error)
EnsureOrg(ctx, slug, fullName, desc, vis) (Org, error)
GetRepo(ctx, owner, name) (Repo, error)
CreateRepo(ctx, org, name, desc, private, autoInit, defBranch) (Repo, error)
EnsureRepo(ctx, org, name, desc, private) (Repo, error) ← C1 surface; C3+C4 callers discard the Repo
EnsureBranch(ctx, org, repo, branch) error (won from): C4
GetFile(ctx, org, repo, branch, path) (File, error) (won from): C2 — has repo-vs-file 404 distinction
PutFile(...) (File, committed bool, err error) (won from): C4 signature + C1 byte-equal short-circuit + C2 PutFileOpts for committer
DeleteFile(ctx, org, repo, branch, path, msg) (bool, error) (won from): C3/C4 (identical)
Errors: ErrOrgNotFound, ErrRepoNotFound, ErrFileNotFound + HTTPError
+ IsNotFound() + IsConflict() — covers every prior helper.
BaseURL semantics canonicalized: takes Gitea root WITHOUT `/api/v1`;
client appends internally. environment-controller's GITEA_API_URL
default updated to drop the `/api/v1` suffix.
26 tests covering every reconciler-relevant code path including:
* EnsureOrg / EnsureRepo / EnsureBranch find-or-create + 422/409 races
* PutFile create / update / byte-equal short-circuit / with author
* GetFile / DeleteFile typed sentinels (ErrFileNotFound vs ErrRepoNotFound)
* IsNotFound / IsConflict coverage of typed sentinels + HTTPError
* Per-controller migration:
* organization (C1): EnsureOrg/EnsureRepo same; PutFile arg-order
swap (path↔branch — C1 was the outlier) and `(_, _, err :=)`
triple. 1 reconciler call site updated.
* blueprint (C3): EnsureRepo wrapped with the canonical description
literal + private=false (catalog Org). 1 reconciler call site.
* environment (C2): GiteaClient interface updated; UpsertFile →
PutFile with PutFileOpts for committer attribution; *Org → Org.
cmd/main.go drops trailing `/api/v1` from default GITEA_API_URL.
1 reconciler call site + 1 fake.
* application (C4): Gitea interface updated to match new shape;
EnsureRepo wrapped with description + private=true literal.
1 reconciler call site + 1 fake.
* Each per-controller `internal/gitea/` directory deleted (4 dirs,
~2400 LoC removed).
Test-coverage delta:
Pre-CC2 client tests: 4 + 4 + 10 + 5 = 23 tests across 4 packages
Post-CC2 shared tests: 26 tests in one package (+3 net)
Per-controller tests: unchanged in count, all still GREEN
Verified locally:
go vet ./... — clean
go test -count=1 -race ./... — every package GREEN
go build per controller cmd/ — all 5 binaries link
Architecture rules preserved:
* No behavior change for any existing call site (the SUPERSET is
strictly a union; reconciler logic byte-identical).
* Single shared go.mod; no new module path.
* Idempotency anchor (PutFile byte-equal short-circuit) preserved.
* No new Gitea API methods beyond union of existing usage.
* No deploy-manifest changes (env-controller's URL drop is
cmd-side default; no chart template touches GITEA_API_URL yet).
Co-authored-by: hatiyildiz <hatiyildiz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>