Developer Guide

Build and test Jenkins Operator with Nix, a devcontainer, or local tools

Development environment

Choose the Nix devshell, the repository devcontainer, or local tools with Make. All three use the same build and test targets below.

Nix devshell

Install Git, Nix with flakes enabled, a running Docker engine and client, and kubectl. Clone the repository and enter the development shell:

git clone git@github.com:jenkinsci/kubernetes-operator.git
cd kubernetes-operator
nix develop

The default shell provides Go, Kind, pre-commit, helm-docs, Bats and its libraries, and other build tools. Tool versions are maintained in config.base.env and consumed by variables.mk; do not copy separate version settings into local scripts. Release 0.9.0 uses Go 1.26 and Operator SDK 1.42.3.

Devcontainer

Open the checkout in VS Code with the Dev Containers extension and select Dev Containers: Reopen in Container. The configuration in .devcontainer/devcontainer.json provides Go, Docker-in-Docker, kubectl, Helm, Kind, Bats and its libraries, Hugo, and Nix. Run nix develop in the container terminal for the full development toolset, including pre-commit and helm-docs. Check docker info before running cluster tests.

Local tools with Make

Nix is not required by CI or the Dockerfiles. For a local setup, install the Go version from config.base.env, Git, GNU Make, Bash, Docker, kubectl, and Kind. The Make targets download versioned tools such as Helm, controller-gen, kustomize, golangci-lint and staticcheck into bin/ as needed. Make does not install the host prerequisites listed above. Install helm-docs and pre-commit as well if you use the documentation and commit hooks.

Build and run with Kind

Create one local cluster and build the operator:

make kind-setup
make build

The default cluster is jenkins, with context kind-jenkins. Confirm that this is the context you intend to use, then run the operator locally:

make run

make run installs CRDs, builds the operator, and watches the namespace selected by NAMESPACE (default unless overridden). In another terminal, apply a Jenkins resource from the deployment guide. The operator must remain running while it configures Jenkins.

For an existing cluster, select its context before running Make so CRD installation uses the same cluster as the operator:

kubectl config use-context my-context
make run KUBECTL_CONTEXT=my-context NAMESPACE=jenkins

Create the namespace first if it does not exist. For Docker Desktop’s Kubernetes cluster, use make config=config.docker-desktop.env run after selecting its context.

Focused tests and verification

Run a focused package test before the complete verification target:

RUNNING_TESTS=1 go test ./pkg/plugins
make verify

make verify runs formatting, lint, unit tests, staticcheck, and vet. The formatting target may modify files; review the diff afterward. For unit tests alone, use make test.

Before committing, run the repository hooks against the files you changed:

pre-commit install

For chart changes, use make helm-lint and regenerate the chart README with helm-docs --chart-search-root=chart/jenkins-operator. If using Make-installed Helm, run export PATH="$PWD/bin:$PATH" before the hooks so the Helm hook can find it.

Cluster integration tests

Use the same local Kind cluster and run suites sequentially. These tests create and remove Kubernetes resources; use a development cluster rather than an installation containing Jenkins data.

make kind-setup  # only if the local cluster does not already exist
kubectl config use-context kind-jenkins
make e2e
make helm-e2e
make bats-tests

To focus on a Ginkgo example, pass a matching description through E2E_TEST_ARGS:

make e2e E2E_TEST_ARGS='-ginkgo.focus=creates.*vanilla'

E2E_TEST_SELECTOR selects the Go test entry point with -run; Ginkgo example selection uses -ginkgo.focus. CI runs scenarios in separate jobs; do not run those scenarios concurrently against your shared local cluster. Keep any local plugin-mirror overrides out of committed fixtures.

The Helm/Bats Make targets currently build AMD64 operator images. Use an AMD64 test environment for those targets. The backup image has separate AMD64 and ARM64 checks.

Backup image tests

make -C backup/pvc docker-e2e builds the local-platform image and runs its backup/restore tests. The test image’s user must be able to write the bind-mounted test directories; adjust its UID/GID for your machine. These tests do not need a Kubernetes cluster.

To test an ARM64 image without pushing to a registry, use Docker with ARM64 execution support (native or QEMU/binfmt) and load a single-platform image:

make -C backup/pvc docker-buildx PLATFORMS=linux/arm64 \
  BUILDX_OUTPUT=type=docker GITCOMMIT=backup-dev UID="$(id -u)" GID=1000
DOCKER_DEFAULT_PLATFORM=linux/arm64 make -C backup/pvc docker-test GITCOMMIT=backup-dev

Use an available group ID in the image; 1000 is the normal backup image default. For an AMD64 check, substitute linux/amd64. Run the two suites sequentially because they share fixture directories. The docker-test target tests the loaded image without rebuilding it for the host architecture.

API and generated files

After changing API types, regenerate the deepcopy code and manifests:

make generate
make manifests
make verify

Review the generated CRDs, RBAC, and chart/deploy copies with the source changes. Do not edit generated files to introduce changes that their source cannot reproduce.

Access Jenkins locally

For a Jenkins resource named example in default, forward the HTTP service:

kubectl --namespace default port-forward service/jenkins-operator-http-example 8080:8080

Open http://localhost:8080. In another terminal, read the generated credentials:

kubectl --namespace default get secret jenkins-operator-credentials-example -o 'jsonpath={.data.user}' | base64 -d
kubectl --namespace default get secret jenkins-operator-credentials-example -o 'jsonpath={.data.password}' | base64 -d

Website development

From the repository root, enter the website directory before opening its shell:

cd website
nix develop ..#website
hugo server -D

This shell installs the website’s npm dependencies. Review incidental package/lockfile changes before committing. For a production build from the repository root, use nix build .#website. New files must be added to Git for a Git-backed flake build to include them.

For a devcontainer or local-tool setup without the website devshell, install Node.js/npm and a C/C++ build toolchain (needed by extended Hugo), then run from the repository root:

make generate-docs
make run-docs

make generate-docs installs npm dependencies and builds the configured extended Hugo locally under bin/hugo; make run-docs starts the preview with drafts enabled. The website still uses Hugo 0.99; compatibility with newer Hugo remains separate work.

Clean up the local cluster

Once all local cluster tests are finished:

make kind-clean

Last modified October 31, 2026