Skip to content

Developer Guide

Layout

api/v1alpha1/          CRD types, status helpers; api/planid plan ID derivation
cmd/manager            controller binary        cmd/runner   runner binary
internal/controller    reconciliation (setup, plan, apply, drift, outputs, finalizer)
internal/runner        gRPC server executing terraform/tofu (runner.proto)
internal/mtls          CA + per-namespace runner certificates
internal/source        git / OCI fetchers, Argo CD credential lookup
internal/plan          plan <-> Secret/ConfigMap encoding (gzip, chunking)
internal/tarball       source archiving / safe extraction
internal/argocd        tests for config/argocd/lua
config/                kustomize: crd, rbac, manager, runner (per-namespace), argocd (component), samples
charts/                Helm chart (CRD synced from config/crd)
ui/extension           Argo CD UI extension (TypeScript, built in a Node container)
hack/argocd-cm         renders config/argocd/lua into argocd-cm-patch.yaml
test/e2e               kind end-to-end tests

Everyday commands

make generate manifests     # deepcopy, CRD, RBAC, gRPC code, argocd-cm patch
make test                   # unit + envtest (needs terraform or tofu in PATH)
make lint                   # golangci-lint
make build                  # bin/manager, bin/runner
make docker-build docker-build-runner
make test-e2e               # kind: builds images, deploys, applies with tofu and terraform
make ui-test ui-build build-extension   # UI, in a node:22 container
make helm-lint verify-argocd-overlay
make build-docs serve-docs   # documentation site, in a python:3.12 container

The envtest suite starts the controller with INSECURE_LOCAL_RUNNER=1 and an in-process runner on localhost, using the local tofu/terraform binary and a local backend stored outside the working directory. The e2e suite serves the local checkout from a git daemon Pod inside kind unless E2E_SOURCE_URL (with E2E_SOURCE_REF, E2E_SOURCE_PATH) points elsewhere.

Running locally against a cluster

make install                                 # CRD
INSECURE_LOCAL_RUNNER=1 go run ./cmd/runner --grpc-port 30000 &   # no TLS, local binary
INSECURE_LOCAL_RUNNER=1 DISABLE_TF_K8S_BACKEND=1 go run ./cmd/manager --runner-grpc-port 30000

INSECURE_LOCAL_RUNNER=1 makes the controller dial localhost instead of creating runner Pods (it still issues the mTLS secret with a localhost SAN when the runner is started with --tls-secret-name).

Changing the gRPC protocol

Edit internal/runner/runner.proto, run make proto (buf + protoc-gen-go, installed into bin/), implement the server method in internal/runner and the client call in internal/controller.

Changing the Argo CD customizations

Edit config/argocd/lua/** and run make argocd-cm (also part of make manifests) to regenerate config/argocd/argocd-cm-patch.yaml. Tests in internal/argocd exercise the scripts with gopher-lua. The UI mirrors the health logic in ui/extension/src/model.ts; keep them in sync.

Releasing

Bump export VERSION=vX.Y.Z in docs/getting-started.md so the guide stays copy-pasteable (make verify-release-version TAG=vX.Y.Z checks it; the Release workflow fails early if it does not match the tag), then tag vX.Y.Z. CI pushes the quay.io/redhatworkshops/argocd-terraform-controller-{manager,runner} images, publishes the Helm chart to oci://quay.io/redhatworkshops/argocd-terraform-controller-helmchart (tag X.Y.Z), builds the UI extension tarball, the install manifest, the Argo CD patches and the chart tarball, and attaches them to the GitHub release.

The chart is named argocd-terraform-controller-helmchart so Helm's OCI push lands it in its own Quay repository; nameOverride in values.yaml keeps the rendered resources named argocd-terraform-controller. The Quay robot (QUAY_USERNAME / QUAY_PASSWORD) needs write access to that repository, as it does for the image repositories.

Documentation site

The docs are MkDocs with the Material theme, configured like the Argo CD docs: mkdocs.yml at the repository root, sources under docs/, Python requirements in docs/requirements.txt. Nothing needs to be installed on the host:

make serve-docs             # live reload on http://localhost:8000
make build-docs             # strict build into site/ (what CI runs)

strict: true turns broken links, missing nav entries and unknown relative links into build failures. Links from docs to files in the repository (code, manifests) must be absolute GitHub URLs; links between pages are relative .md paths. GitHub-style callouts (> [!NOTE]) render on both GitHub and the site through the gh-admonitions plugin.

The Docs workflow (.github/workflows/docs.yml) runs only when docs/**, mkdocs.yml or .readthedocs.yaml change: pull requests get a strict build; pushes to main also deploy to the gh-pages branch, served at https://redhat-developer.github.io/argocd-terraform-controller/. The other workflows ignore documentation changes.

The configuration is Read the Docs-ready (.readthedocs.yaml, like argoproj/argo-cd). To move the site there: import the repository on readthedocs.org, which picks up .readthedocs.yaml and sets READTHEDOCS_CANONICAL_URL (used by site_url in mkdocs.yml), then remove the deploy job from docs.yml and delete the gh-pages branch.