Skip to content

Commit b4d139f

Browse files
committed
docs: add CLAUDE.md with repository guidance
Add project memory documenting build/test/lint commands, architecture, and conventions to orient Claude Code and other AI coding agents in this repo. Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
1 parent 8b574f0 commit b4d139f

1 file changed

Lines changed: 83 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# edp-sonar-operator
2+
3+
`github.com/epam/edp-sonar-operator` — a Go kubebuilder operator that configures an **existing** SonarQube instance declaratively via Kubernetes CRDs. It does not install SonarQube; it reconciles its state. Quality gates defined here are the blocking gates enforced in every KRCI Tekton CI pipeline.
4+
5+
CRD group: `edp.epam.com/v1alpha1``Sonar`, `SonarProject`, `SonarQualityGate`, `SonarQualityProfile`, `SonarUser`, `SonarGroup`, `SonarPermissionTemplate`.
6+
7+
## Build & Test
8+
9+
```bash
10+
make build # fmt + vet + compile → dist/manager-<arch>
11+
make test # unit + envtest integration tests (downloads envtest binaries on first run)
12+
make lint # golangci-lint (config: .golangci.yaml)
13+
make lint-fix # golangci-lint with auto-fix
14+
```
15+
16+
Run a single test package:
17+
18+
```bash
19+
go test ./internal/controller/qualitygate/... -v
20+
```
21+
22+
Integration tests against a live SonarQube (optional):
23+
24+
```bash
25+
TEST_SONAR_URL=http://localhost:9000 TEST_SONAR_USER=admin TEST_SONAR_PASSWORD=admin make test
26+
```
27+
28+
## Code Generation
29+
30+
After editing kubebuilder markers in `api/v1alpha1/` or controller RBAC comments:
31+
32+
```bash
33+
make generate # regenerates DeepCopy methods (zz_generated.deepcopy.go)
34+
make manifests # regenerates CRDs → deploy-templates/crds/ and config/crd/bases/, also runs api-docs
35+
make mocks # regenerates mockery mocks in pkg/client/sonar/mocks/
36+
```
37+
38+
CRD YAML files in `deploy-templates/crds/` and `config/crd/bases/` are generated — do not edit manually. Same for `api/v1alpha1/zz_generated.deepcopy.go` and `api/common/zz_generated.deepcopy.go`.
39+
40+
## Architecture
41+
42+
```
43+
cmd/main.go
44+
└── creates controller-runtime Manager, registers all 7 reconcilers
45+
46+
api/v1alpha1/ — CRD type definitions (spec, status, kubebuilder markers)
47+
api/common/ — shared SonarRef and HasSonarRef interface
48+
49+
internal/controller/<resource>/
50+
├── sonar*_controller.go — Reconcile() entry: fetches CR, resolves Sonar client,
51+
│ delegates to chain; handles finalizer + deletion
52+
└── chain/
53+
├── chain.go — handler interface + sequential chain runner
54+
├── factory.go — MakeChain() wires handlers in order
55+
├── create_*.go — idempotent create/update step
56+
├── sync_*.go — sync sub-resources (conditions, rules, groups, perms)
57+
└── remove_*.go — deletion step (invoked on DeletionTimestamp)
58+
59+
pkg/client/sonar/
60+
├── sonar.go — Client struct (resty-based), base HTTP methods
61+
├── client_interface.go — ClientInterface composed of sub-interfaces (hand-written, NOT generated)
62+
├── quality_gate.go — QualityGateClient methods
63+
├── quality_profile.go — QualityProfileClient methods
64+
├── group.go / user.go / project.go / permission_template.go / rule.go / system.go
65+
├── provider.go — ApiClientProvider: resolves Client from Sonar CR + K8s Secret
66+
└── mocks/ — mockery-generated mocks (do not edit)
67+
68+
deploy-templates/ — Helm chart (values.yaml, crds/, templates/); README auto-generated by helm-docs
69+
config/ — Kustomize manifests (crd, rbac, manager, webhook, certmanager, prometheus)
70+
bundle/ — OLM bundle manifests for OperatorHub
71+
```
72+
73+
## Key Conventions
74+
75+
**SonarRef dependency model.** Every child CR (`SonarQualityGate`, `SonarUser`, etc.) has a `spec.sonarRef.name` pointing to a `Sonar` CR. Reconcilers call `ApiClientProvider.GetSonarApiClientFromSonarRef`, which checks `sonar.Status.Connected == true` before building the HTTP client. If the parent `Sonar` is not yet connected, the child requeues after 30 s.
76+
77+
**Chain of responsibility.** Each controller delegates work to a `chain.MakeChain(sonarApiClient)` call. To add a new reconciliation step, implement `ServeRequest(ctx, *sonarApiCRType) error` and append it in `chain/factory.go`. All handlers are tested individually with mock clients.
78+
79+
**SonarQube REST client is hand-written, not generated.** `pkg/client/sonar/sonar.go` and sibling files wrap resty with idiomatic Go. `ClientInterface` in `client_interface.go` is the composition interface used by all chain handlers. Mocks in `mocks/` are generated from `ClientInterface` via mockery (`.mockery.yaml`).
80+
81+
**Credentials.** The `Sonar` CR's `spec.secret` names a K8s Secret with `user` and `password` keys. The client is constructed with basic auth against `spec.url`.
82+
83+
**Name field is immutable post-creation.** `SonarQualityGate.spec.name` (and analogous fields on other CRDs) drives the SonarQube resource name. Changing it after creation causes the old resource to be deleted and a new one created.

0 commit comments

Comments
 (0)