diff --git a/Makefile b/Makefile index 322ae61..c236c7f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ -# One command before committing: make +# `make` is everything that has to pass before a commit. The rest are the workflows that were +# otherwise copy-pasted out of README.md and docs/deployment.md. # -# gofmt is first because a formatting failure is the cheapest to fix, and it is the only check that -# needs a wrapper — gofmt reports offending files on stdout and still exits 0. -.POSIX: -.PHONY: check fmt vet test build run +# gofmt needs a wrapper because it reports offending files on stdout and still exits 0. +.PHONY: check fmt vet test fix build run image db backup clean + +# Overridable, so a target never bakes in one person's environment. +BIN ?= levyraati26-go +ADDR ?= 127.0.0.1:8080 +STORAGE ?= ./storage check: fmt vet test @@ -16,11 +20,44 @@ vet: test: go test ./... +# Suggestions only. go fix rewrites files in place without -diff, and it is not always right — +# read the hunks before applying any of them. +fix: + @go fix -diff ./... || true + # -o is required, not stylistic: the package lives in ./src, and without it `go build` would try to # write a binary named "src" over the directory. build: - go build -o levyraati26-go ./src + go build -o $(BIN) ./src -# Templates and migrations are embedded, so seeing a change means rebuilding. +# Templates, static files and migrations are embedded, so seeing a change means rebuilding. +# The admin credentials seed the first account on an empty database and are ignored after that. run: build - ./levyraati26-go + ADMIN_EMAIL=$${ADMIN_EMAIL:-dev@example.com} \ + ADMIN_PASSWORD=$${ADMIN_PASSWORD:-dev} \ + SECURE_COOKIES=false STORAGE_DIR=$(STORAGE) ADDR=$(ADDR) ./$(BIN) + +# A release image. VERSION comes from the tag, because that is the only way it reaches the binary +# and /healthz must not claim a version that was never tagged. IMAGE names the registry and stays +# out of this file: pass it in, or put it in the .env this reads nothing from. +# +# make image IMAGE=registry.example.com/owner/levyraati26-go +image: + @test -n "$(IMAGE)" || { echo "set IMAGE, e.g. make image IMAGE=registry.example.com/owner/levyraati26-go"; exit 1; } + @v=$$(git describe --tags --exact-match 2>/dev/null) || { echo "HEAD is not tagged; tag the release first"; exit 1; }; \ + podman build --build-arg VERSION=$$v -t $(IMAGE):$$v -t $(IMAGE):latest . && \ + echo "built $(IMAGE):$$v — push with: podman push $(IMAGE):$$v" + +# Operations against the running container, straight out of docs/deployment.md. +db: + docker compose exec app sqlite3 /storage/levyraati.db + +# Copying the file while the app runs is not a backup: WAL keeps recent writes in a sidecar. +backup: + docker compose exec app sqlite3 /storage/levyraati.db ".backup '/storage/tmp/backup.db'" + gzip -c $(STORAGE)/tmp/backup.db > backup-$$(date +%F).db.gz + rm $(STORAGE)/tmp/backup.db + @echo "wrote backup-$$(date +%F).db.gz" + +clean: + rm -f $(BIN) diff --git a/README.md b/README.md index bdac664..f44ab95 100644 --- a/README.md +++ b/README.md @@ -162,11 +162,23 @@ docker compose exec app sqlite3 /storage/levyraati.db ## Layout -Go source is flat at the repository root, one package. Beyond that: `templates/` and `static/` are -embedded assets, `migrations/` holds numbered `.sql` files applied in order at startup, and -`testdata/` holds the golden JSON files that guard the API contract, plus `ytdlp-noose.json` — a real -`yt-dlp -J` dump of an ordinary upload, used to test metadata prefill against a video that has no -`track`, `artist` or `album` at all. +`src/` is the whole program: one flat `package main`, with the assets it embeds beside it, because +`//go:embed` cannot reach outside its own directory. `templates/` and `static/` are those assets, +`migrations/` holds numbered `.sql` files applied in order at startup, and `testdata/` holds the +golden JSON files that guard the API contract, plus `ytdlp-noose.json` — a real `yt-dlp -J` dump of +an ordinary upload, used to test metadata prefill against a video that has no `track`, `artist` or +`album` at all. + +The root keeps what is not source: `docs/`, the container and compose files, the `Makefile`, and +`storage/` once the app has run. + +| Command | Does | +|---|---| +| `make` | gofmt, `go vet`, `go test` — everything that must pass before a commit | +| `make run` | Build and start on `127.0.0.1:8080` with development defaults | +| `make fix` | Show `go fix` modernizer suggestions as a diff, without applying them | +| `make image IMAGE=…` | Build a release image tagged from `git describe`; refuses an untagged HEAD | +| `make db` / `make backup` | SQLite shell, and a WAL-safe snapshot, against the running container | ## Notes