Files
images/Makefile
T
rmcguireandClaude Opus 5 b888f09eb1 Readable job names, latest tracks main, and an AGENTS.md
Job names in the Gitea UI rendered as the raw matrix expression
("${{ fromJSON(needs.select.outputs.images) }}"). Gitea resolves a job's matrix
when it PARSES the workflow, before `needs` outputs exist, so matrix.image was
interpolated against an unresolved matrix. There is no way to win with a dynamic
matrix: jobparser.nameWithMatrix interpolates a name containing "${{ }}", and
appends "(<values>)" to one that doesn't — either way the raw expression shows.
See go-gitea/gitea#28207.

So drop the matrix. build.yaml now runs one job, "Build changed images", that
loops over the selected images and emits ::group:: markers, giving a collapsible
section per image. Also: every step has an explicit static name, because Gitea
does not interpolate expressions in names either ("Log in to ${{ env.REGISTRY }}"
rendered literally).

Tag scheme, per review: `latest` now tracks main rather than the newest release,
and `edge` is gone — it's an Alpine/Traefik convention, not a broad standard, and
`main-<sha>` already covers "a specific commit". `latest` has exactly one owner
so a release tag and a main build can't race to define it. Release tags remain
immutable `:vX.Y.Z`/`:vX.Y`/`:vX` for pinning. This also means the ToolHive
manifest's `:latest` resolves as soon as this lands on main, with no release tag
needed first.

hack/docker-tags.sh folded into hack/build-images.sh, which is now the whole
pipeline — tag, build, smoke-test, push — shared by `make build` and CI. It uses
plain `docker build` instead of buildx, dropping setup-buildx-action: it loads
into the local store so the test runs pre-publish, and emits a plain manifest
with no attestations for Gitea's registry.

Verified in a simulated runner (repo in a docker volume, socket mounted, real
runner image): select + build + group markers, all four tag modes, and the
multi-image loop with a scratch second image.

AGENTS.md records the conventions and, importantly, the three Gitea gotchas that
all look fine locally: no bind-mounting the workspace into a sibling container,
no dynamic matrix, no expressions in names.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-09 12:05:23 -04:00

59 lines
2.0 KiB
Makefile

# Entry point for local work and for CI. The Gitea workflows call these same
# targets, so a green `make all` locally means a green pipeline.
REGISTRY ?= gitea.libretechconsulting.com
NAMESPACE ?= rmcguire
# Every directory under images/ that has a Dockerfile is an image.
IMAGES := $(patsubst images/%/Dockerfile,%,$(wildcard images/*/Dockerfile))
# Build/test a single image with `make build IMAGE=node-agent`; unset means all.
IMAGE ?=
TARGETS := $(if $(IMAGE),$(IMAGE),$(IMAGES))
# CI overrides REF with the real published ref so the smoke test runs against it.
REF ?=
.DEFAULT_GOAL := help
.PHONY: help list check lint hadolint shellcheck build test all
help: ## Show available targets
@awk 'BEGIN{FS=":.*##"} /^[a-z][a-z-]*:.*##/ {printf " \033[36m%-11s\033[0m %s\n",$$1,$$2}' $(MAKEFILE_LIST)
list: ## List every image in this repository
@printf '%s\n' $(IMAGES)
check: ## Verify each image directory follows the expected layout
@rc=0; \
if [ -z "$(IMAGES)" ]; then echo "no images found under images/"; rc=1; fi; \
for i in $(IMAGES); do \
[ -f images/$$i/README.md ] || { echo "images/$$i: missing README.md"; rc=1; }; \
if [ -e images/$$i/test.sh ] && [ ! -x images/$$i/test.sh ]; then \
echo "images/$$i/test.sh: not executable"; rc=1; \
fi; \
done; \
[ $$rc -eq 0 ] && echo "layout ok: $(IMAGES)"; \
exit $$rc
hadolint: ## Lint every Dockerfile
@hack/lint.sh dockerfiles
shellcheck: ## Lint every shell script
@hack/lint.sh scripts
lint: hadolint shellcheck ## Run all linters
build: ## Build and smoke-test IMAGE, or every image when IMAGE is unset
@hack/build-images.sh $(TARGETS)
test: ## Smoke-test an already-built IMAGE, or every image when IMAGE is unset
@for i in $(TARGETS); do \
if [ -x images/$$i/test.sh ]; then \
images/$$i/test.sh "$(if $(REF),$(REF),$(REGISTRY)/$(NAMESPACE)/$$i:dev)" || exit 1; \
else \
echo "==> $$i has no test.sh, skipping"; \
fi; \
done
all: check lint build ## Everything CI does, locally (build smoke-tests too)