Skip to content

Make Targets

The provider repository, cluster-api-provider-terraform, drives its build, checks, test environment and releases with make. Every tool is a pinned version that make installs into hack/tools/bin on first use, so you need only Go, make, and for some targets podman, python3, git or jq. make with no target, and make help, print the targets with their one-line descriptions, grouped as they are here.

For how the targets fit into a contribution, see Contributing.

The everyday loop

For most changes, run this before you push:

make lint test verify
Target What it gives you
make lint Style and correctness findings from golangci-lint in every module, including the e2e-tagged test code, and from kube-api-linter on api/.
make test The unit tests of every Go module, with the race detector.
make verify Every other consistency check: generated files, manifests, schemas, templates, alert rules and the test-tier guard.

After you change api/v1alpha1 or a controller’s kubebuilder markers, run make generate manifests first. make fmt formats Go code before you lint it.

To try a change against a real cluster, run make testenv-up once, then make testenv-reload after each change. See Test environment.

make verify fails on unstaged changes

Its verify-gen step regenerates code and manifests, then runs git diff --exit-code over the whole tree. Stage your work (git add) before you run it, or it reports your own edits as a failure.

Variables

Set a variable on the command line, as in make docker-build IMG=<image>. Unless the table says otherwise, a variable only affects the targets named in its row.

Variable Default Effect
IMG ghcr.io/captf-io/cluster-api-provider-terraform:dev The manager and runner image that docker-build, docker-buildx and docker-push build or push.
CONTAINER_TOOL podman The tool that builds and pushes images. docker works for docker-build and docker-push. docker-buildx needs podman.
PLATFORMS linux/amd64,linux/arm64 The platforms of the manifest list that docker-buildx builds.
GO_VERSION 1.26 The Go version used by image builds.
VERSION from hack/version.sh The version stamped into binaries, and the tag that release targets use. It is always a valid semantic version: v0.0.0-dev.g<commit> before the first release tag. Release targets require vX.Y.Z or vX.Y.Z-rc.N.
RELEASE_REPO ghcr.io/captf-io/cluster-api-provider-terraform The repository of the release image.
RELEASE_IMG $(RELEASE_REPO):$(VERSION) The image manifests-release writes into the components file. make release passes the pushed image by digest.
RELEASE_DIR out Where manifests-release writes its files. Release assets go to out/release.
SKOPEO skopeo The skopeo binary that release-image-digest runs.
RUNNER_IMAGE $(IMG) The runner image make run gives the manager.
WEBHOOK_CERT_DIR bin/dev-webhook-certs Where make run keeps its self-signed webhook certificate.
ARGS Extra flags that make run passes to the manager.
GOTESTSUM_FORMAT pkgname The gotestsum output format of test-cover. CI sets github-actions.
TESTENV_NAME captf-test-dev The cluster name for the testenv-* targets. It must start with captf-test-.
TESTENV_ENGINE auto-detected podman or docker, for the testenv-* and e2e-* targets. Auto-detection prefers podman.
TESTENV_WORKERS 0 The number of kind worker nodes for testenv-up, from 0 to 5.
CAPTF_TESTENV_REUSE off Set to 1 to make testenv-up reuse a matching cluster.
TESTENV_ALL off Set to 1 to make testenv-down delete every captf-test-* cluster.
CAPTF_E2E_CLUSTER captf-test-e2e The cluster the e2e-* targets use.
CAPTF_E2E_REUSE off Set to 1 to make e2e-foundation reuse an existing cluster.
CAPTF_E2E_TEARDOWN off Set to 1 to make e2e-foundation delete the cluster after a passing run.
CAPTF_E2E_STABILITY 2m The length of the foundation suite’s stability window.
CAPTF_E2E_WORKERS 0 The number of kind worker nodes for e2e-foundation.
CAPTF_E2E_GREENLIGHT_MAX_AGE 24h How old the green light may be before e2e-noop rejects it.
CAPTF_E2E_NOOP_BAD_DIGEST off Set to 1 to run e2e-noop’s negative check: one machine gets a nonexistent image digest, and the suite must fail on the image pull.

An empty value takes the default in the table.

General

Target Description
help Print every target with its description, grouped. This is the default target.

Development

Target Description
generate Regenerate the deepcopy code for api/ with controller-gen. Run it after you change an API type.
manifests Regenerate the CRD, RBAC and webhook manifests into config/. Run it after you change API types or kubebuilder markers.
fmt Format Go code with gofmt -s and goimports.
vet Run go vet in every Go module, then on the test module’s e2e-tagged code.
lint Run golangci-lint in every module and on the test module’s e2e-tagged code, then lint-api.
lint-api Run kube-api-linter on the api/ module.
lint-fix Run lint with the auto-fixers of both linters on.

Test

Target Description
test Run the unit tests of every Go module with -race -count=1. It never compiles the e2e-tagged code.
test-cover Run the unit tests with -race and coverage through gotestsum, and write a profile and a JUnit report per module into bin/. CI runs this instead of test.
cover-check Check each package’s coverage in the bin/cover-*.out profiles against its floor in hack/coverage-floors.txt. Run it after test-cover.

See Testing for what the tests cover, the coverage floors, and how to run one package or one test.

Test environment

The testenv-* targets manage a kind cluster on podman (or docker) with cert-manager, Cluster API and CAPTF built from your working tree. Use it to try a change against a real API server, without a cloud. Each target runs one operation of the e2e-tagged package test/env/lifecycle, with the pinned clusterctl and kustomize. Everything for a cluster <name> lands in bin/testenv/<name>/: its kubeconfig, an env.sh that exports KUBECONFIG, a state.json and the diagnostics bundles.

Target Description
testenv-up Build the manager image, create the kind cluster, install the providers and wait until they are ready. About 6 minutes cold.
testenv-reload Rebuild the manager image from the tree, load it into the nodes and roll the manager Deployment over to it. Run it after each change to the manager or runner.
testenv-status Show whether the cluster exists, its nodes, the pods that are not ready and a summary of state.json.
testenv-logs Collect pod logs, events, CAPI and CAPTF objects and node logs into bin/testenv/<name>/artifacts/<timestamp>/. Secrets are not collected.
testenv-down Delete the cluster. The artifacts/ directory is kept.
make testenv-up
source bin/testenv/captf-test-dev/env.sh
kubectl get pods -A
make testenv-reload
make testenv-down

Only cluster names that start with captf-test- are accepted, and the targets never read ~/.kube/config. testenv-up refuses an existing cluster unless CAPTF_TESTENV_REUSE=1 is set. For example, to run a cluster with one worker node next to the default one:

make testenv-up TESTENV_NAME=captf-test-pool TESTENV_WORKERS=1

End-to-end

The e2e-* targets run the opt-in e2e suites under test/e2e/. They need podman or docker. make test never compiles them, and CI does not run them. See Testing.

Target Description
e2e-foundation Build the manager from your tree and the captf-test-e2e cluster, check it stage by stage, and write a green light for it. Run it first. It keeps the cluster after a passing run unless CAPTF_E2E_TEARDOWN=1.
e2e-noop Run the no-op data-flow suite on the green-lit cluster: Cluster API objects drive the published no-op modules, and the suite checks that data flows from the spec to the module and back and that deletion cleans up. It fails unless e2e-foundation passed recently.
e2e-down Delete the e2e cluster, captf-test-e2e or CAPTF_E2E_CLUSTER. The artifacts are kept.

Build

Target Description
build Build every cmd/* binary into bin/.
manager Build the static manager into bin/manager, and check that it is statically linked.
runner Build the static Job runner into bin/runner, and check that it is statically linked.
run Build the manager and run it out of cluster against your current kubeconfig. It turns leader election off and makes a self-signed webhook certificate if needed.
docker-build Build the manager and runner image $(IMG) for the host platform.
docker-buildx Build a multi-architecture manifest list $(IMG) for $(PLATFORMS), with podman.
docker-push Push $(IMG). A manifest list from docker-buildx is pushed with all its images.

make run points the manager at $(RUNNER_IMAGE), which is $(IMG) by default. Build the image first when a Job needs a runner you changed:

make docker-build IMG=<image>
make run RUNNER_IMAGE=<image> ARGS="<flags>"
  • <image> is an image reference the cluster can pull, for example localhost/captf:dev on a cluster that shares your image store.
  • <flags> are extra manager flags. Leave out ARGS if you have none.

Verify

make verify runs every check below. Each one also runs alone, which is faster when only one has failed. Several need python3, git or podman.

Target Description
verify Run all the checks in this table.
verify-godoc Check that every declaration, parameter, return value and package has a doc comment.
verify-gen Run generate and manifests, then fail if git diff shows a change. It needs git.
verify-modules Check go.work and go.mod pins, and that no module uses replace.
verify-schemas Validate the contract JSON Schemas, their examples and the golden inputs and outputs. It needs python3 with jsonschema.
verify-components Check the clusterctl components built from config/default.
verify-metadata Validate metadata.yaml, and check that releaseSeries only grows compared with the previous tag.
verify-version Check that hack/version.sh prints a valid semantic version for every checkout state.
verify-templates Render templates/ with the pinned clusterctl.
verify-local-repository Generate the provider and both flavors from a clusterctl local repository of the release assets, offline and without a cluster.
verify-test-tiers Check that e2e code carries the e2e build tag and lives only in test/e2e/ and test/env/lifecycle/.
check-licenses Check that no MPL-2.0 dependency of tfcapi-lint applies Exhibit B.
promtool-check Check the alert rules with promtool, and build the Prometheus component on config/default.
promtool-test Unit-test the alert rules.

verify does not run cover-check, which needs the profiles test-cover writes. CI runs the two as separate steps.

Release

These targets build and publish a release. They need a clean tree with HEAD tagged $(VERSION). A tag never moves, so a bad release candidate gets a new one. Releasing has the full procedure. Publishing is for maintainers.

Target Description
release-preflight Check that the tree is clean, HEAD carries the tag $(VERSION), and metadata.yaml only grows.
release Run the preflight, build and push the manager image, and build every asset into out/release with the image pinned by digest. Set VERSION=vX.Y.Z.
release-image-digest Print the registry digest of $(RELEASE_REPO):$(VERSION). It needs skopeo.
manifests-release Build out/infrastructure-components.yaml for $(RELEASE_IMG), and copy metadata.yaml and templates/*.yaml next to it.
release-assets Build every release asset for $(VERSION) into out/release. It needs the git tag.
release-notes Write out/release/notes.md from the commits since the previous tag.
release-github Create the GitHub release for $(VERSION) from out/release. This publishes: run it as the maintainer only.
release-lint-snapshot Build the tfcapi-lint release assets and checksums into dist/ as a GoReleaser snapshot, to try a release without a tag.
release-lint-binaries An alias of release-lint-snapshot.
release-lint Build the tfcapi-lint release assets from the current git tag.

Tools

Target Description
tools Install every pinned tool into hack/tools/bin. Run it once, and again after a version bump.

Cleanup

Target Description
clean Remove the build output in bin/ and dist/. This also removes bin/testenv/, so run testenv-down first if you want the cluster gone.