build: move releases to CI and trim the Makefile
check / check (push) Successful in 6m23s

Merging a pull request into main is now the whole release. A Gitea
Actions workflow derives the CalVer tag, builds the image and pushes
it with :latest, so nothing is built locally any more.

That made image/push/release redundant, and with them the .release-tag
state file and the main-branch guard — the workflow only runs on main,
which is protected, so the guard had nothing left to catch. The digest
verification went too: it guarded a `make -j` race between image and
push that cannot happen in a single CI job.

seed, icons and vendor ran a few times a year and are written out in
the README instead. Makefile: 151 lines to 71.

Docs referenced the removed targets in sixteen places, including a
CONTRIBUTING note claiming the branch check "has to be local".
This commit is contained in:
Esa Kataja
2026-09-06 10:54:22 +03:00
parent c0b48ee71a
commit 6590c18412
8 changed files with 158 additions and 151 deletions
+2 -81
View File
@@ -3,18 +3,8 @@
COMPOSE ?= podman compose
BIN := foodster
PKG := ./cmd/foodster
STATIC := cmd/foodster/static
# What `make image` last built. push reads it rather than re-deriving the tag:
# sorting tags by date is ambiguous when two point at the same commit, and
# re-deriving is what let a parallel make push the wrong one.
TAGFILE := .release-tag
# Vendored Datastar client. Bump, run `make vendor`, commit the result.
DATASTAR_VERSION ?= v1.0.3
SEED ?= seeds/testi.json
# Registry coordinates, shared password and TZ live here. Gitignored.
# Shared password and TZ live here. Gitignored.
ifneq (,$(wildcard .env))
include .env
export
@@ -24,7 +14,7 @@ endif
GOFILES = $(shell find . -name '*.go' -not -name '*_templ.go' 2>/dev/null)
.DEFAULT_GOAL := help
.PHONY: help generate build run seed test smoke check lint fix icons vendor image push release up down logs clean
.PHONY: help generate build run test smoke check lint fix up down logs clean
help: ## Show this help
@grep -hE '^[a-zA-Z_-]+:.*## ' $(MAKEFILE_LIST) \
@@ -40,9 +30,6 @@ build: generate ## Build ./foodster
run: generate ## Run locally on :8080 (database in ./data)
PASSWORD=$${PASSWORD:-dev} ENV=dev go run $(PKG)
seed: ## Import a dish bundle (SEED=seeds/testi.json)
go run $(PKG) -import $(SEED)
test: generate ## Run unit tests
go test ./...
@@ -57,21 +44,6 @@ check: ## Everything that must pass before a commit
@$(MAKE) --no-print-directory smoke
@echo "check: all passed"
icons: ## Rasterise home-screen PNGs from assets/icon.svg and optimise them
rsvg-convert -w 180 -h 180 assets/icon.svg -o $(STATIC)/apple-touch-icon.png
rsvg-convert -w 192 -h 192 assets/icon.svg -o $(STATIC)/icon-192.png
rsvg-convert -w 512 -h 512 assets/icon.svg -o $(STATIC)/icon-512.png
# oxipng -o max alone loses to optipng on the 512; --zopfli wins at every
# size. Slow, but these are three tiny files built by hand.
oxipng -o max --zopfli --quiet \
$(STATIC)/apple-touch-icon.png $(STATIC)/icon-192.png $(STATIC)/icon-512.png
@ls -l $(STATIC)/*.png
vendor: ## Re-download the Datastar client (DATASTAR_VERSION=v1.0.3)
curl -sSfL -o $(STATIC)/datastar.js \
"https://cdn.jsdelivr.net/gh/starfederation/datastar@$(DATASTAR_VERSION)/bundles/datastar.js"
@head -1 $(STATIC)/datastar.js
lint: generate ## go vet, gofmt check, golangci-lint when installed
go vet ./...
@bad=$$(gofmt -l $(GOFILES) 2>/dev/null); \
@@ -84,57 +56,6 @@ fix: ## Format Go and templ sources, tidy go.mod
go tool templ fmt .
go mod tidy
image: ## Build and tag an image as vYYYYMMDD-N. Creates a git tag.
@test -n "$(REPO)" || { echo "set REPO in .env"; exit 1; }
@# A release tag must point into main, or the tag records a commit that
@# was never released.
@branch=$$(git symbolic-ref --short HEAD); \
if [ "$$branch" != "main" ]; then \
echo "releases are cut from main, not $$branch:"; \
echo " git switch main && git merge --ff-only dev"; \
exit 1; \
fi
@day=$$(date +%Y%m%d); \
tag="v$$day-$$(( $$(git tag -l "v$$day-*" | wc -l) + 1 ))"; \
echo "==> $$tag"; \
git tag "$$tag"; \
podman build --platform linux/amd64 --build-arg VERSION="$$tag" \
-t "$(REPO):$$tag" -t "$(REPO):latest" . ; \
echo "$$tag" > $(TAGFILE)
# Pushing reported success while uploading the previous release once, because
# nothing compared what was built against what arrived. So afterwards, ask the
# registry what it actually serves for each tag and fail if it is not the
# image we just built.
push: ## Push the newest tag and :latest, then verify the registry
@test -n "$(REPO)" || { echo "set REPO in .env"; exit 1; }
@test -f $(TAGFILE) || { echo "nothing built - run make image"; exit 1; }; \
tag=$$(cat $(TAGFILE)); \
built=$$(podman image inspect "$(REPO):$$tag" --format '{{.Id}}' 2>/dev/null) || \
{ echo "no local image tagged $$tag - run make image"; exit 1; }; \
podman push "$(REPO):$$tag"; \
podman push "$(REPO):latest"; \
echo "==> verifying $$tag"; \
for ref in "$$tag" latest; do \
podman pull -q "$(REPO):$$ref" >/dev/null 2>&1 || \
{ echo " FAIL $$ref is not in the registry"; exit 1; }; \
served=$$(podman image inspect "$(REPO):$$ref" --format '{{.Id}}'); \
if [ "$$served" != "$$built" ]; then \
echo " FAIL $$ref serves $$served"; \
echo " expected $$built"; \
exit 1; \
fi; \
echo " ok $$ref"; \
done
# Sub-makes, not prerequisites. Under `make -j` — and -j16 is the default on
# at least one machine here — these run concurrently, so push resolves the
# newest tag and uploads :latest before image has finished building and
# tagging. That silently ships the previous release a second time.
release: ## Build, tag and push in one go
@$(MAKE) --no-print-directory image
@$(MAKE) --no-print-directory push
up: ## Start the stack
@mkdir -p data # or the engine creates it root-owned and the app cannot write
$(COMPOSE) up -d