Files
cozystack/Makefile
Myasnikov Daniil 062207fd7b test(hack): run the unit bats suite under bats(1)
hack/cozytest.sh serves two populations that want opposite things from a
runner: 32 hermetic unit tests of hack/*.sh, and 3 live-cluster imperative
tests. This moves the unit half to real bats and leaves the live half where
it is; the hack/e2e-*.bats filter already in BATS_UNIT_FILES is what keeps
them apart.

The unit files need no edits. They pass under vanilla bats 1.13 unchanged
because their authors wrote to the intersection of both runners -- no run,
no $status, no skip, repo-root-relative paths. Measured on this tree: 328
tests, 0 failures, 26s under `bats -j 8` against cozytest's 63s serial.

What this buys, none of which cozytest offers: --filter-status failed to
rerun only the previous failures, JUnit so CI annotates the failing test
instead of requiring a log read, -j, and deletion of a bespoke awk parser
whose rewrite rules void helper exit codes, corrupt heredoc fixtures on a
column-0 brace, and collide test names after sanitization.

Two consequences worth naming, neither covered by the issue:

bats is a new dependency. cozytest is pure bash+awk, so no runner image or
contributor machine has ever needed anything else. The checks job installs
it from a pinned tag rather than the distro package, whose version varies
by base image, and the make target says so plainly when it is absent. GNU
parallel stays optional -- BATS_JOBS resolves to 1 without it, since
`bats -j` exits non-zero rather than degrading.

The pre-commit lane is the second consumer and does NOT get bats. That job
lints changed YAML and Markdown on a runner with no bats, and the new
hook's path filter covers .github/workflows/, so a workflow edit would drag
the whole 328-test shell suite into a lint lane and duplicate the checks
job that already runs `make unit-tests`. It is skipped there by id, keeping
the hook a local-developer gate.

The tested shell changes. cozytest is #!/bin/sh, which is dash on the CI
runner, and bats runs bash. Seven POSIX scripts that tests source rather
than execute -- seaweedfs-naming-audit.sh, promote-rewrite-tags.sh,
lib/image-refs.sh, the three e2e-capture scripts and cozystack-version.sh
-- therefore lose a runtime dash check they had by accident. Four
shell=bash files under e2e-chainsaw/_lib gain correct fidelity for the same
reason. The static replacement is the shellcheck gate in item 5 of #3453,
which does not exist yet.

set -u is not restored here. bats enforces -e but not -u, and there is no
runner-level way to inject it: --setup-suite-file does not reach test
files, and SHELLOPTS=nounset is exported, so it leaks into the scripts
under test and drops two tests. Restoring it needs a per-file load and is
the layer above this one.

Refs: #3453
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-07-31 12:08:21 +05:00

206 lines
9.3 KiB
Makefile

.PHONY: manifests assets unit-tests helm-unit-tests bats-unit-tests rd-presets-check migrations-target-check test-controllers preflight
include hack/common-envs.mk
build-deps:
@command -V find docker skopeo jq gh helm > /dev/null
@yq --version | grep -q "mikefarah" || (echo "mikefarah/yq is required" && exit 1)
@tar --version | grep -q GNU || (echo "GNU tar is required" && exit 1)
@sed --version | grep -q GNU || (echo "GNU sed is required" && exit 1)
@awk --version | grep -q GNU || (echo "GNU awk is required" && exit 1)
build: build-deps
make -C packages/apps/http-cache image
make -C packages/apps/mariadb image
make -C packages/apps/clickhouse image
make -C packages/apps/kubernetes image
make -C packages/system/monitoring image
make -C packages/system/cozystack-api image
make -C packages/system/cozystack-controller image
make -C packages/system/backup-controller image
make -C packages/system/backupstrategy-controller image
make -C packages/system/lineage-controller-webhook image
make -C packages/system/flux-shard-operator image
make -C packages/system/cilium image
make -C packages/system/linstor image
make -C packages/system/linstor-gui image
make -C packages/system/kubeovn-webhook image
make -C packages/system/kubeovn-plunger image
make -C packages/system/dashboard image
make -C packages/system/metallb image
make -C packages/system/kamaji image
make -C packages/system/capi-providers-cpprovider image
make -C packages/system/multus image
make -C packages/system/bucket image
make -C packages/system/objectstorage-controller image
make -C packages/system/securitygroup-controller image
make -C packages/system/grafana-operator image
make -C packages/core/testing image
make -C packages/core/talos image
make -C packages/core/platform image
make -C packages/core/installer image
make manifests
manifests:
mkdir -p _out/assets
cat internal/crdinstall/manifests/*.yaml > _out/assets/cozystack-crds.yaml
# kubectl-apply install path: render the bare Namespace resource alongside
# the operator. bareNamespace=true gates a Namespace cozy-system with PSA +
# identity labels (see packages/core/installer/templates/cozy-system-namespace.yaml).
# helm install/upgrade users keep the default (false) and use --create-namespace
# + the pre-install labeler hook.
# platformVersion is rendered into the COZYSTACK_VERSION env on the operator so
# the install artifacts carry the version as deploy-time data (not baked into
# the image). Promotion re-renders these with the stable version, no rebuild.
# Talos variant (default)
helm template installer packages/core/installer -n cozy-system \
--set bareNamespace=true \
--set cozystackOperator.platformVersion=$(if $(COZYSTACK_VERSION),v$(COZYSTACK_VERSION),) \
--show-only templates/cozy-system-namespace.yaml \
--show-only templates/cozystack-operator.yaml \
> _out/assets/cozystack-operator-talos.yaml
# Generic Kubernetes variant (k3s, kubeadm, RKE2)
helm template installer packages/core/installer -n cozy-system \
--set bareNamespace=true \
--set cozystackOperator.variant=generic \
--set cozystackOperator.platformVersion=$(if $(COZYSTACK_VERSION),v$(COZYSTACK_VERSION),) \
--set cozystack.apiServerHost=REPLACE_ME \
--show-only templates/cozy-system-namespace.yaml \
--show-only templates/cozystack-operator.yaml \
> _out/assets/cozystack-operator-generic.yaml
# Hosted variant (managed Kubernetes)
helm template installer packages/core/installer -n cozy-system \
--set bareNamespace=true \
--set cozystackOperator.variant=hosted \
--set cozystackOperator.platformVersion=$(if $(COZYSTACK_VERSION),v$(COZYSTACK_VERSION),) \
--show-only templates/cozy-system-namespace.yaml \
--show-only templates/cozystack-operator.yaml \
> _out/assets/cozystack-operator-hosted.yaml
cozypkg:
go build -ldflags "-X github.com/cozystack/cozystack/cmd/cozypkg/cmd.Version=v$(COZYSTACK_VERSION)" -o _out/bin/cozypkg ./cmd/cozypkg
# Operator diagnostic: reports non-ready cozystack / Flux / Kubernetes resources.
check-readiness:
go build -ldflags "-X main.Version=v$(COZYSTACK_VERSION)" -o _out/bin/check-readiness ./cmd/check-readiness
assets: assets-talos assets-cozypkg openapi-json
openapi-json:
mkdir -p _out/assets
VERSION=$(if $(COZYSTACK_VERSION),v$(COZYSTACK_VERSION),$(shell git describe --tags --always 2>/dev/null || echo dev)) go run ./tools/openapi-gen/ 2>/dev/null > _out/assets/openapi.json
assets-talos:
make -C packages/core/talos assets
assets-cozypkg: assets-cozypkg-linux-amd64 assets-cozypkg-linux-arm64 assets-cozypkg-darwin-amd64 assets-cozypkg-darwin-arm64 assets-cozypkg-windows-amd64 assets-cozypkg-windows-arm64
(cd _out/assets/ && sha256sum cozypkg-*.tar.gz) > _out/assets/cozypkg-checksums.txt
assets-cozypkg-%:
$(eval EXT := $(if $(filter windows,$(firstword $(subst -, ,$*))),.exe,))
mkdir -p _out/assets
GOOS=$(firstword $(subst -, ,$*)) GOARCH=$(lastword $(subst -, ,$*)) go build -ldflags "-X github.com/cozystack/cozystack/cmd/cozypkg/cmd.Version=v$(COZYSTACK_VERSION)" -o _out/bin/cozypkg-$*/cozypkg$(EXT) ./cmd/cozypkg
cp LICENSE _out/bin/cozypkg-$*/LICENSE
tar -C _out/bin/cozypkg-$* -czf _out/assets/cozypkg-$*.tar.gz LICENSE cozypkg$(EXT)
test:
make -C packages/core/testing apply
make -C packages/core/testing e2e
unit-tests: helm-unit-tests bats-unit-tests go-unit-tests rd-presets-check test-check-readiness migrations-target-check
helm-unit-tests:
hack/helm-unit-tests.sh
# Pin the resourcesPreset enum in every ApplicationDefinition openAPISchema
# to the canonical 47-value set (40 instance-type names + 7 legacy aliases).
# Catches the regression where one chart's Makefile forgets to invoke
# hack/update-crd.sh and that RD's schema drifts from values.schema.json.
rd-presets-check:
hack/check-rd-presets.sh
# Catch the off-by-one where migrations/<N> is added but
# migrations.targetVersion in packages/core/platform/values.yaml is not
# bumped to >= N+1. run-migrations.sh loops `seq $$CURRENT $$((TARGET-1))`,
# so the new migration is silently skipped on every cluster upgrade.
migrations-target-check:
hack/check-migrations-target.sh
# Scoped go test over the cozystack-api surface that this repo owns. Kept
# narrow intentionally - running `go test ./...` pulls in generated code
# round-trip suites whose behavior depends on tool versions outside this
# repo's control (kubebuilder, openapi-gen, etc.) and is better exercised
# from their generator workflows.
go-unit-tests:
go test ./pkg/registry/... ./pkg/config/... ./pkg/cmd/server/...
# Go tests for the controllers and supporting packages under ./internal.
# Excludes ./pkg/... and ./cmd/... — those are run separately by
# go-unit-tests above (pkg subset) and skipped (cmd) until their tests
# stabilise. Run as its own step in CI alongside helm/bats unit tests;
# locally invoke directly (`make test-controllers`) or chain
# (`make unit-tests test-controllers`).
test-controllers:
go test ./internal/... -count=1
# Black-box golden test for cmd/check-readiness. Builds the binary and runs it
# against a mock kubectl (fixtures under test/check-readiness/testdata),
# diffing stdout/stderr/exit against golden files. Regenerate goldens with:
# go test ./test/check-readiness/ -update
test-check-readiness:
go test ./test/check-readiness/ -count=1
# Discover every hack/*.bats file that is NOT an e2e test and run it under
# bats(1). Drop a new *.bats file in hack/ and it is picked up automatically
# on the next `make unit-tests` run.
#
# These are hermetic unit tests of hack/*.sh, and they run under real bats
# rather than hack/cozytest.sh (#3453). The live-cluster suite
# (hack/e2e-*.bats) stays on cozytest, whose streaming trace and snapshot
# behaviour earn their place over a 15-minute test; bats buffers a test's
# output until it completes. Filtering by the e2e- prefix is what keeps the
# two runners apart.
#
# Caveat: $(wildcard ...) returns space-separated names, so a filename
# containing a literal space would split into multiple tokens here. All
# current bats files use hyphen-separated names; if the project ever
# introduces whitespace-bearing filenames this recipe must be rewritten
# (e.g. to use `find ... -print0 | xargs -0`).
BATS_UNIT_FILES := $(filter-out hack/e2e-%.bats,$(wildcard hack/*.bats))
# `bats -j` needs GNU parallel and exits non-zero rather than degrading when
# it is missing, so resolve the job count to 1 unless parallel is present.
BATS_JOBS ?= $(shell command -v parallel >/dev/null 2>&1 && nproc 2>/dev/null || echo 1)
# JUnit XML so CI annotates the failing test instead of requiring a log read.
# _out is gitignored.
BATS_REPORT_DIR ?= _out/test-reports
bats-unit-tests:
@if [ -z "$(BATS_UNIT_FILES)" ]; then \
echo "ERROR: no hack/*.bats unit test files found"; \
exit 1; \
fi
@command -v bats >/dev/null 2>&1 || { \
echo "ERROR: bats not found. Install bats-core >= 1.5 — https://bats-core.readthedocs.io"; \
exit 1; \
}
@mkdir -p $(BATS_REPORT_DIR)
bats -j $(BATS_JOBS) --report-formatter junit -o $(BATS_REPORT_DIR) $(BATS_UNIT_FILES)
# Operator-facing host preflight check. Warns about a standalone
# containerd.service or docker.service running alongside the embedded
# k3s runtime. Safe to run at any time; always exits 0.
preflight:
@hack/check-host-runtime.sh
prepare-env:
make -C packages/core/testing apply
make -C packages/core/testing prepare-cluster
generate:
hack/update-codegen.sh
upload_assets: manifests
hack/upload-assets.sh