oficina / sheets Public

build: add a stamped release target, and refuse dirty trees

The root-page release shipped with a plain `go build`, so rastrillo's
BuildVersion kept its "dev" default and the live instance answered
GET /api/version with "dev". That is the field used to tell what is
actually deployed, so an unstamped binary makes the fleet unreadable
while still reporting a successful deploy — and `carlos deploy` printed
"live" against it.

The stamp was never encoded anywhere: earlier releases carried a sha
because the ldflags were typed by hand, which is why one build without
them was enough to lose it. `make release` is now the only supported way
to build a shipping binary.

It also refuses a dirty tree, because a sha that names a commit other
than what is in the binary is worse than no stamp at all. Both behaviours
were watched: the refusal fires on a dirty tree and writes no output
file.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APtNStXDZ5H2fAc1ZuGqtS
Paul Campbell pushed by paul@keymail.dev f013d2ef0cce5f0e32a2bd928f9f8def957129ee parent aa3d7f2
2 files changed, +20 −1
  • .gitignore +1 −0
  • Makefile +19 −1
diff --git a/.gitignore b/.gitignore
index 62171f9..35c6f85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@
.claude/workflows
.claude/launch.json
.claude/settings.local.json
+/sheets-arm64
diff --git a/Makefile b/Makefile
index b695aad..0e99e22 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: build test test-vet test-fmt test-build test-migrations test-go test-race
+.PHONY: build release test test-vet test-fmt test-build test-migrations test-go test-race
# One binary, CGO_ENABLED=0, cgo-free SQLite (AGENTS.md / Deploys). Set
# per-target below rather than exported globally, because test-race is
@@ -6,6 +6,24 @@
build:
CGO_ENABLED=0 go build ./...
+# The ONLY way a binary should be built for shipping. rastrillo's
+# BuildVersion defaults to "dev", and an unstamped binary answers
+# GET /api/version with "dev" — which is the field used to tell what is
+# actually deployed, so an unstamped release makes the fleet unreadable
+# while still looking like a successful deploy. Shipping one by hand
+# with a plain `go build` is exactly the mistake this target removes.
+#
+# A dirty tree is refused: the sha would name a commit that is not what
+# is in the binary, which is worse than no stamp at all.
+RELEASE_OUT ?= ./sheets-arm64
+release:
+ @git diff --quiet && git diff --cached --quiet || \
+ { echo "refusing to build a release from a dirty tree"; exit 1; }
+ CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath \
+ -ldflags "-s -w -X github.com/carlosframework/rastrillo.BuildVersion=$$(git rev-parse --short HEAD)" \
+ -o $(RELEASE_OUT) ./cmd/sheets
+ @echo "built $(RELEASE_OUT) stamped $$(git rev-parse --short HEAD)"
+
# The gate, split into named targets so CI can report them individually
# (.amadan/ci.d calls these one at a time, each its own step). `make
# test` runs exactly the same six things in the same order, so the