Showstopper. Adding, editing or deleting a dish redirected to /ruoat, which stopped existing when the tab was renamed to Ruuat — every one of those actions ended on a 404. Live in v20260905-4. The tests missed it because they asserted only a 303; a redirect to a dead URL is still a 303. They now assert the target. The page no longer jumps. Deleting a dish partway down the catalog, or opening a day in Kirjaa, sent the browser to the top. Both now patch in place via Datastar — bin, pencil, day rows, dish pills, save, delete, cancel and Näytä lisää. Links stay links and forms stay forms, so it works without JavaScript. Non-production tabs are labelled. ENV=dev gives dev · Foodster. Contributing guide added, and commits now take Conventional Commit types. ⚠️ Breaking: rewrite the server's .env in this deploy. Environment variables lost the FOODSTER_ prefix; the app refuses to start on an unset PASSWORD. REPO=… TAG=latest PASSWORD=… HOST=foodster.kessinen.com ENV=prod PUID=1000 PGID=1000 TZ=Europe/Helsinki PUID/PGID rather than UID/GID — UID is read-only in bash and would be silently overwritten. Co-authored-by: Esa Kataja <[email protected]> Reviewed-on: #3
151 lines
5.7 KiB
Makefile
151 lines
5.7 KiB
Makefile
# Foodster. Run `make` for the target list.
|
|
|
|
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.
|
|
ifneq (,$(wildcard .env))
|
|
include .env
|
|
export
|
|
endif
|
|
|
|
# Generated templ output is excluded — it is not ours to format.
|
|
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
|
|
|
|
help: ## Show this help
|
|
@grep -hE '^[a-zA-Z_-]+:.*## ' $(MAKEFILE_LIST) \
|
|
| awk -F':.*## ' '{printf " \033[1m%-9s\033[0m %s\n", $$1, $$2}'
|
|
|
|
generate: ## Generate Go from .templ files
|
|
go tool templ generate
|
|
|
|
build: generate ## Build ./foodster
|
|
CGO_ENABLED=0 go build -trimpath \
|
|
-ldflags="-s -w -X main.version=dev" -o $(BIN) $(PKG)
|
|
|
|
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 ./...
|
|
|
|
smoke: generate ## End-to-end check: auth, static assets, bundle import
|
|
./scripts/smoke.sh
|
|
|
|
# Sub-makes rather than prerequisites: these must run in order even under
|
|
# `make -j`, and a parallel run vets generated code that is being rewritten.
|
|
check: ## Everything that must pass before a commit
|
|
@$(MAKE) --no-print-directory lint
|
|
@$(MAKE) --no-print-directory test
|
|
@$(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); \
|
|
if [ -n "$$bad" ]; then echo "gofmt needed:"; echo "$$bad"; exit 1; fi
|
|
@if command -v golangci-lint >/dev/null 2>&1; then golangci-lint run; \
|
|
else echo "golangci-lint not installed - skipped"; fi
|
|
|
|
fix: ## Format Go and templ sources, tidy go.mod
|
|
@if [ -n "$(GOFILES)" ]; then gofmt -w $(GOFILES); fi
|
|
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
|
|
|
|
down: ## Stop the stack
|
|
$(COMPOSE) down
|
|
|
|
logs: ## Follow app logs
|
|
$(COMPOSE) logs -f app
|
|
|
|
clean: ## Remove the binary and generated templates
|
|
rm -f $(BIN)
|
|
find . -name '*_templ.go' -delete
|