Set up this repo as a base image registry. Each image is self-contained in
its own directory under images/ (Dockerfile + README.md + optional test.sh);
CI discovers them by glob, so adding an image needs no workflow changes.
template/ is the skeleton to copy.
The Makefile is the single entry point for both local work and CI, so a green
`make all` locally means a green pipeline.
Workflows:
* lint.yaml — layout check, hadolint, shellcheck
* build.yaml — diffs against the base commit to build only the images that
changed, smoke-tests each one before anything is published, then pushes.
Releases are per-image tags (<image>/vX.Y.Z); main publishes :edge.
First image, node-agent: node:22-alpine plus a GNU userland (Alpine ships
BusyBox, whose applets take narrower flags than scripts and models expect),
helm, kubectl, jq, yq, bind-tools, curl, git, ripgrep, fd and friends.
Nothing is version-pinned — rebuilding is how upstream updates land, and the
published tag is what pins things for consumers.
Its smoke test asserts the deployment contract as well as tool presence: the
image must work non-root, with a read-only root filesystem and all
capabilities dropped, which is how ToolHive runs it.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
69 lines
2.4 KiB
Makefile
69 lines
2.4 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 ?=
|
|
|
|
HADOLINT ?= hadolint/hadolint:latest-alpine
|
|
SHELLCHECK ?= koalaman/shellcheck:stable
|
|
SCRIPTS := $(wildcard hack/*.sh images/*/test.sh template/test.sh)
|
|
|
|
.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
|
|
@docker run --rm -v "$(CURDIR)":/repo:ro -w /repo $(HADOLINT) \
|
|
hadolint $(addprefix images/,$(addsuffix /Dockerfile,$(IMAGES))) template/Dockerfile
|
|
@echo "hadolint ok"
|
|
|
|
shellcheck: ## Lint every shell script
|
|
@docker run --rm -v "$(CURDIR)":/repo:ro -w /repo $(SHELLCHECK) $(SCRIPTS)
|
|
@echo "shellcheck ok"
|
|
|
|
lint: hadolint shellcheck ## Run all linters
|
|
|
|
build: ## Build IMAGE, or every image when IMAGE is unset
|
|
@for i in $(TARGETS); do \
|
|
echo "==> building $$i"; \
|
|
docker build -t $(REGISTRY)/$(NAMESPACE)/$$i:dev images/$$i || exit 1; \
|
|
done
|
|
|
|
test: ## Smoke-test 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 test ## Everything CI does, locally
|