A composite GitHub Action that installs kind, creates a kind cluster, and runs a Go end-to-end test command — in a single step.
It replaces the five-step inline block every kubebuilder repo tends to copy (setup-go → install kind → verify kind → kind create cluster → go mod tidy && make test-e2e).
- One action, whole kind-based e2e flow:
setup-go→ download kind →kind create cluster→ wait for node readiness → optionalgo mod tidy→ e2e command - Defaults match the standard kubebuilder layout (
go.mod,make test-e2e, latest kind, cluster namekind) — zero config for most repos - Tunable: pinned
kind_version, explicitkind_node_image,kind_configfor multi-node / port-mapping clusters, customcluster_name,cluster_ready_timeout, custome2e_command, pinnedgo_version, subdirectoryworking_directory,cache_dependency_pathpassthrough for mono-repos - Multi-arch: detects
linux/amd64,linux/arm64,darwin/amd64,darwin/arm64automatically when downloading the kind binary - Automatic failure diagnostics: on action failure, runs
kind export logsand uploads the directory as a workflow artifact (kind-logs-<cluster_name>-<run_id>-<run_attempt>, 7-day retention) — can be disabled viaupload_logs_on_failure: false - Writes a per-run summary table to
$GITHUB_STEP_SUMMARY - Exposes
cluster_nameande2e_exit_codeoutputs for downstream steps
- Runner OS:
ubuntu-latestis the tested target (kind needs a working Docker daemon; GitHub's hosted Ubuntu runners ship one). Self-hosted runners need Docker/containerd available. - Caller must run
actions/checkoutbefore this action so thatworking_directorycontains the Go module. make/ Go toolchain available in the repo when using the defaulte2e_command: make test-e2e. Overridee2e_commandif you invoke the e2e suite differently.
Drop this into .github/workflows/test-e2e.yml of any kubebuilder-style repo:
name: E2E Tests
on:
push:
branches: [main]
paths-ignore:
- '.github/workflows/**'
- '**/*.md'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
test-e2e:
name: Run on Ubuntu
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1With all defaults it runs: setup-go from go.mod → install latest kind → kind create cluster --name kind → kubectl wait --for=condition=Ready nodes --all --timeout=60s → go mod tidy → make test-e2e. On failure, kind logs are exported and uploaded as a workflow artifact.
- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
kind_version: v0.23.0- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
kind_version: v0.23.0
kind_node_image: kindest/node:v1.30.0- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
cluster_name: acme-e2e
e2e_command: 'go test ./test/e2e/ -v -ginkgo.v'- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
working_directory: operator
go_version_file: go.mod- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
go_version: '1.22'- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
kind_config: ./test/e2e/kind-multi-node.yamlExample kind-multi-node.yaml:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker# raise the timeout
- uses: somaz94/kind-e2e-test-action@v1
with:
cluster_ready_timeout: 3m
# or skip the wait (the action moves straight to go mod tidy + e2e)
- uses: somaz94/kind-e2e-test-action@v1
with:
cluster_ready_timeout: ''- uses: actions/checkout@v6
- uses: somaz94/kind-e2e-test-action@v1
with:
working_directory: services/api
cache_dependency_path: services/api/go.sum- uses: somaz94/kind-e2e-test-action@v1
with:
upload_logs_on_failure: 'false'- id: e2e
uses: somaz94/kind-e2e-test-action@v1
- name: Report
if: always()
run: |
echo "cluster_name=${{ steps.e2e.outputs.cluster_name }}"
echo "e2e_exit_code=${{ steps.e2e.outputs.e2e_exit_code }}"| Input | Description | Required | Default |
|---|---|---|---|
go_version_file |
Path to go.mod (or another file) used by actions/setup-go as go-version-file. Ignored when go_version is set. |
No | go.mod |
go_version |
Explicit Go version (e.g., 1.22). Takes precedence over go_version_file when non-empty. |
No | '' |
working_directory |
Directory to run all commands in (Go module root). | No | . |
cache |
Enable Go module/build cache in actions/setup-go. |
No | true |
cache_dependency_path |
Passthrough to actions/setup-go cache-dependency-path. Leave empty to rely on setup-go's default (go.sum next to go.mod). Handy for mono-repos. |
No | '' |
run_mod_tidy |
When true, run go mod tidy before the e2e command. |
No | true |
kind_version |
kind release to install. latest or a version tag like v0.23.0. |
No | latest |
kind_node_image |
Node image passed to kind create cluster --image. Empty means use kind's default for the installed release. Ignored for nodes that set an image inside kind_config. |
No | '' |
kind_config |
Path to a kind cluster config YAML passed as kind create cluster --config. Empty means single-node default cluster. |
No | '' |
cluster_name |
Name passed to kind create cluster --name. |
No | kind |
cluster_ready_timeout |
Timeout for kubectl wait --for=condition=Ready nodes --all --timeout=<value> after cluster creation. Empty skips the wait. |
No | 60s |
e2e_command |
E2E command executed from working_directory. |
No | make test-e2e |
upload_logs_on_failure |
When true, on action failure run kind export logs and upload the directory as a workflow artifact (kind-logs-<cluster_name>-<run_id>-<run_attempt>, 7-day retention). |
No | true |
| Output | Description |
|---|---|
cluster_name |
Name of the kind cluster that was created (echo of the cluster_name input). |
e2e_exit_code |
Exit code of the e2e command. Always 0 when the action succeeds (the action fails otherwise). |
The action itself needs no special permissions beyond what actions/checkout and actions/setup-go require. A typical caller:
permissions:
contents: read- Validate inputs —
go_versionorgo_version_filemust be set;working_directorymust exist;cluster_nameande2e_commandmust be non-empty;kind_config(when set) must point to an existing file. actions/setup-go— either fromgo_version_file(default) orgo_version(when explicitly set). Go module/build cache controlled bycache;cache_dependency_pathis passed through verbatim toactions/setup-go.- Install kind — detects OS/arch (
linux/amd64,linux/arm64,darwin/amd64,darwin/arm64) and downloadshttps://kind.sigs.k8s.io/dl/<version>/kind-<os>-<arch>(latestis a literal URL segment kind publishes). Placed at/usr/local/bin/kind. - Verify kind —
kind versionfor a visible version stamp in the log. - Create kind cluster —
kind create cluster --name <cluster_name>(plus--image <kind_node_image>and/or--config <kind_config>when set). Follows up withkubectl cluster-info --context kind-<cluster_name>as a smoke check. Exposescluster_nameoutput. - Wait for node readiness (unless
cluster_ready_timeoutis empty) —kubectl wait --for=condition=Ready nodes --all --timeout=<cluster_ready_timeout>. Fail-fast on slow images or misconfigured multi-node clusters. go mod tidy— optional, matches the pattern every repo's inline workflow already uses.- E2E command —
bash -c "$e2e_command"run fromworking_directory. Exit code emitted as thee2e_exit_codeoutput. - Summary — a markdown table (working directory / kind version / node image / config / cluster name / ready timeout / e2e command / result) is appended to
$GITHUB_STEP_SUMMARY. - Failure diagnostics (when
upload_logs_on_failure: true, skipped on success) —kind export logsdumps container / kubelet / containerd logs for every node, thenactions/upload-artifact@v4uploads the directory askind-logs-<cluster_name>-<run_id>-<run_attempt>(7-day retention). Gracefully skipped if the cluster never finished creating.
This project is licensed under the MIT License — see the LICENSE file for details.