first commit

This commit is contained in:
bryanpedini committed 2026-10-10 10:37:53 +02:00
commit 1354db6c39
90 files changed
+13123

No files matched your search

+150
View File
@@ -0,0 +1,150 @@
#!make
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2026 Bryan Joshua Pedini
# makefile for skeptical-updater: install, lint and test targets.
# Plain GNU make + bash + Docker (+ curl once, for `make vendor`); no other tooling.
# `make` or `make help` lists the targets. Tests run entirely in Docker containers.
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.ONESHELL:
.NOTPARALLEL:
.DEFAULT_GOAL := help
MAKEFLAGS += --no-print-directory
APPLET := skeptical-updater
PREFIX ?= /usr/local
DESTDIR ?=
# ---- vendored test tooling, pinned --------------------------------------------
# To bump: set the new tag and the sha256sum of its GitHub tag tarball
# (https://github.com/bats-core/<repo>/archive/refs/tags/v<version>.tar.gz),
# then `rm -rf tests/vendor && make vendor`.
BATS_VERSION := 1.14.0
BATS_SHA256 := bb537b70b15b732f6d8827dd6578e3d8ce166636ce1f18ea9a074184fcce9177
BATS_SUPPORT_VERSION := 0.3.0
BATS_SUPPORT_SHA256 := 7815237aafeb42ddcc1b8c698fc5808026d33317d8701d5ec2396e9634e2918f
BATS_ASSERT_VERSION := 2.2.4
BATS_ASSERT_SHA256 := e305df20c4c36cba4570e10f1cd824efb1ae71d88b5ef474550781ebee04192f
BATS_GITHUB := https://github.com/bats-core
VENDOR := tests/vendor
BATS := $(VENDOR)/bats-core/bin/bats
# ---- tests ----------------------------------------------------------------------
SHELLCHECK_IMAGE ?= koalaman/shellcheck:stable
UNIT_IMAGE ?= debian:12
E2E_IMAGES ?= tests/docker/images.txt
E2E_ONLY ?=
E2E_FAIL_FAST ?= 0
# discovery/ is frozen reference material (not shellcheck-clean, never edited): not linted.
LINT_FILES := $(wildcard $(APPLET) tests/docker/*.sh tests/e2e/*.sh tests/e2e/fixtures/*.sh \
tests/e2e/*.bash tests/e2e/*.bats tests/unit/*.bash tests/unit/*.bats \
tests/unit/fakes/*.bash tests/unit/fakes/*/* tests/unit/data/rpm/db.bash)
# $(call fetch,<repo>,<version>,<sha256>,<file that must exist>)
# Download github.com/bats-core/<repo> tag v<version> with curl into a temp dir,
# verify its sha256 and that <file> was extracted, then move it to tests/vendor/<repo>.
define fetch
tmp=$$(mktemp -d "$${TMPDIR:-/tmp}/skeptical-updater-vendor.XXXXXX")
trap 'rm -rf -- "$$tmp"' EXIT
url="$(BATS_GITHUB)/$(1)/archive/refs/tags/v$(2).tar.gz"
echo "vendor: $(1) v$(2) <- $$url"
curl -fsSL --retry 3 --proto '=https' -o "$$tmp/src.tar.gz" "$$url"
if ! echo "$(3) $$tmp/src.tar.gz" | sha256sum -c --status -; then echo "vendor: $(1) v$(2): sha256 mismatch (expected $(3))" >&2; exit 1; fi
mkdir -- "$$tmp/src"
tar -xzf "$$tmp/src.tar.gz" -C "$$tmp/src"
if [[ ! -f "$$tmp/src/$(1)-$(2)/$(4)" ]]; then echo "vendor: $(1) v$(2): $(4) not found in the tarball" >&2; exit 1; fi
mkdir -p -- "$(VENDOR)"
rm -rf -- "$(VENDOR)/$(1)"
mv -- "$$tmp/src/$(1)-$(2)" "$(VENDOR)/$(1)"
echo "$(1) v$(2) sha256:$(3) $$url" >"$(VENDOR)/$(1)/.vendored"
echo "vendor: $(1) v$(2) -> $(VENDOR)/$(1)"
endef
.PHONY: help install uninstall lint vendor docker-snapshot docker-cleanup docker-cleanup-dry-run \
test test-no-cleanup test-unit test-e2e clean
help: ## show this help (default target)
@echo "usage: make <target> [VAR=value ...]"
echo
echo "targets:"
grep -hE '^[A-Za-z0-9_.-]+:.*## ' $(MAKEFILE_LIST) | awk -F ':.*## ' '{ printf " %-24s %s\n", $$1, $$2 }'
echo
echo "variables:"
echo " PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) install location"
echo " E2E_ONLY=<label>[,<label>...] run only these labels of $(E2E_IMAGES)"
echo " E2E_FAIL_FAST=1 stop test-e2e at the first failing distro"
install: ## install skeptical-updater as DESTDIR/PREFIX/bin/skeptical-updater, mode 0755
install -d -m 0755 "$(DESTDIR)$(PREFIX)/bin"
install -m 0755 $(APPLET) "$(DESTDIR)$(PREFIX)/bin/$(APPLET)"
uninstall: ## remove DESTDIR/PREFIX/bin/skeptical-updater (the statefile in /var/lib is kept)
rm -f -- "$(DESTDIR)$(PREFIX)/bin/$(APPLET)"
lint: ## shellcheck (in Docker) the applet, the test scripts, fixtures and fakes
ifeq ($(strip $(LINT_FILES)),)
@echo "lint: no shell files to check"
else
docker run --rm -v "$(CURDIR)":/mnt:ro $(SHELLCHECK_IMAGE) $(LINT_FILES)
endif
vendor: $(BATS) $(VENDOR)/bats-support/load.bash $(VENDOR)/bats-assert/load.bash ## download pinned bats-core, bats-support, bats-assert to tests/vendor (once)
$(BATS):
@$(call fetch,bats-core,$(BATS_VERSION),$(BATS_SHA256),bin/bats)
$(VENDOR)/bats-support/load.bash:
@$(call fetch,bats-support,$(BATS_SUPPORT_VERSION),$(BATS_SUPPORT_SHA256),load.bash)
$(VENDOR)/bats-assert/load.bash:
@$(call fetch,bats-assert,$(BATS_ASSERT_VERSION),$(BATS_ASSERT_SHA256),load.bash)
docker-snapshot: ## record the Docker image set (never overwrites; re-baseline: tests/docker/snapshot.sh --force)
tests/docker/snapshot.sh
docker-cleanup: ## restore the Docker image set to the snapshot (re-tag stolen tags, remove new images)
tests/docker/cleanup.sh
docker-cleanup-dry-run: ## print what docker-cleanup would do, without changing anything
tests/docker/cleanup.sh --dry-run
test: docker-snapshot ## test-unit + test-e2e, then ALWAYS docker-cleanup; exits with the tests' status
@status=0
trap 'status=130' INT TERM
$(MAKE) test-unit test-e2e || status=$$?
trap - INT TERM
echo "== test: restoring the Docker image set (tests exited with status $$status) =="
$(MAKE) docker-cleanup || { rc=$$?; if (( status == 0 )); then status=$$rc; fi; }
exit $$status
test-no-cleanup: docker-snapshot test-unit test-e2e ## same as test but keep pulled images (iterate; run docker-cleanup when done)
test-unit: vendor ## run tests/unit/*.bats with the vendored bats in a debian:12 container
docker run --rm -i -v "$(CURDIR)":/work:ro -w /work \
-e SKEPTICAL_UPDATER_STATE_DIR=/tmp/su-state \
$(UNIT_IMAGE) bash $(BATS) --tap tests/unit
test-e2e: vendor ## run the E2E suite in each distro of tests/docker/images.txt (E2E_ONLY, E2E_FAIL_FAST)
@only="$(strip $(E2E_ONLY))"
only=",$${only//[[:space:]]/,},"
ran=0
failed=()
while read -r -u 3 label image _ || [[ -n "$${label:-}" ]]; do
case "$$label" in ''|'#'*) continue ;; esac
if [[ "$$only" != ",," && "$$only" != *",$$label,"* ]]; then continue; fi
if [[ -z "$${image:-}" ]]; then echo "test-e2e: $(E2E_IMAGES): no image for label '$$label'" >&2; exit 1; fi
ran=$$((ran + 1))
if ! tests/docker/run-e2e.sh "$$label" "$$image" </dev/null; then
failed+=("$$label")
if [[ "$(E2E_FAIL_FAST)" == 1 ]]; then echo "test-e2e: E2E_FAIL_FAST=1: stopping after $$label" >&2; break; fi
fi
done 3<"$(E2E_IMAGES)"
if (( ran == 0 )); then echo "test-e2e: no label in $(E2E_IMAGES) matches E2E_ONLY='$(E2E_ONLY)'" >&2; exit 1; fi
if (( $${#failed[@]} )); then echo "test-e2e: $${#failed[@]} of $$ran distro(s) FAILED: $${failed[*]} (logs: tests/docker/logs/)" >&2; exit 1; fi
echo "test-e2e: all $$ran distro(s) passed"
clean: ## remove tests/docker/logs and .bats-tmp (never tests/vendor, never the Docker snapshot)
rm -rf -- tests/docker/logs .bats-tmp