comma := ,
export GOPRIVATE := $(if $(GOPRIVATE),$(GOPRIVATE)$(comma))amadan.net/oficina/estilo.git

.PHONY: build release test test-vet test-fmt test-build test-migrations test-go test-race test-browser

# One binary, CGO_ENABLED=0, cgo-free SQLite (AGENTS.md / Deploys). Set
# per-target below rather than exported globally, because test-race is
# a deliberate, documented exception — see its comment.
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.
#
# The stamp was a short sha because there were no tags to describe. Now
# that a release IS a tag, git describe --tags --always answers with the
# tag when the build sits on one and falls back to the same short sha
# when it does not, so nothing is lost and a published binary reports
# the name it was published under.
#
# The artifact lands in releases/ under the name the publish step
# expects: `amadan release create` uploads a file under its basename,
# and that basename is what appears on the release page permanently.
APP := sheets
RELEASE_GOOS   ?= linux
RELEASE_GOARCH ?= arm64
RELEASE_BIN := releases/$(APP)-$(RELEASE_GOOS)-$(RELEASE_GOARCH)
VERSION ?= $(shell git describe --tags --always 2>/dev/null)

release:
	@git diff --quiet && git diff --cached --quiet || \
		{ echo "refusing to build a release from a dirty tree"; exit 1; }
	@test -n "$(VERSION)" || \
		{ echo "make release: no version to stamp; commit, or name it: make release VERSION=v0.1.0"; exit 1; }
	@mkdir -p releases
	CGO_ENABLED=0 GOOS=$(RELEASE_GOOS) GOARCH=$(RELEASE_GOARCH) go build -trimpath \
		-ldflags "-s -w -X amadan.net/rastrillo/rastrillo.BuildVersion=$(VERSION)" \
		-o $(RELEASE_BIN) ./cmd/$(APP)
	@echo "built $(RELEASE_BIN) reporting version $(VERSION)"
	@echo "publish it with:"
	@echo "  amadan release create -repo oficina/$(APP) -notes-file NOTES.md $(VERSION) $(RELEASE_BIN)"

# 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
# local gate and CI stay ONE definition rather than two lists that
# drift apart. Debugging CI is running `make test`.
#
# Order is cheapest-and-fastest first: vet and gofmt are near-instant,
# build catches compile errors before minutes are spent on tests,
# test-migrations needs the app to compile but no database and no test
# suite, plain `go test` (tens of seconds, dominated by the store
# package) comes next, and -race — by far the slowest step — runs last.
test: test-vet test-fmt test-build test-migrations test-go test-race

# Also vets the browser-tagged tests: they are outside `make test`, and a
# test behind a tag that nothing compiles rots silently.
test-vet:
	CGO_ENABLED=0 go vet ./...
	CGO_ENABLED=0 go vet -tags browser ./internal/sheets/

# Fails on unformatted files rather than rewriting them. CI must never
# silently "fix" a diff out from under a branch — a red test-fmt tells
# the author to run `gofmt -w` themselves.
test-fmt:
	@if [ -n "$$(gofmt -l .)" ]; then \
		echo "gofmt needs to be run on:"; \
		gofmt -l .; \
		exit 1; \
	fi

test-build:
	CGO_ENABLED=0 go build ./...

# CI gate for AGENTS.md's additive-only migrations rule: models
# (internal/sheets/migrations.go's Models) and migrations
# (internal/sheets/migrations/*.sql, via Schema) must already agree.
# Touches no database — it diffs structs against committed SQL, the
# same computation `rastrillo migration generate` does before deciding
# there is nothing to write — so it belongs this early, right after the
# app is known to compile and well before test-go pays for real SQLite
# files. A model changed without `rastrillo migration generate` run
# after it fails here, not in production at the next boot.
#
# `go tool`, not a bare `rastrillo` on PATH: go.mod pins the CLI as a tool
# at the same version as the module, so the check always runs the
# migrate the app is built against — never whatever a machine happened
# to have installed (a v0.25.0 CLI answering for a v0.23.0 app, until
# the move to amadan.net/rastrillo/rastrillo).
test-migrations:
	go tool rastrillo migration check

# Includes internal/guardstest: the mechanical guards for the line cap,
# forbidden imports, excelize confinement, calc isolation and sealtest
# containment all run here as ordinary tests, plus internal/sheets/seal
# and internal/sheets/xlsx's plaintext-leak checks (AGENTS.md / "The one
# rule"). -count=1 so a cached "ok" from a previous run can never stand
# in for actually having run.
test-go:
	CGO_ENABLED=0 go test -count=1 ./...

# The concurrency-bearing packages: store's one-connection writer pool
# and its handle gate (AGENTS.md: "Scope tx, never the outer handle,
# inside transactions, or the one-connection writer pool deadlocks"),
# and live's fan-out hub, where one publisher and every open browser
# tab meet. Scoped to those two rather than ./... because -race's
# slowdown is worth paying where the concurrency actually lives, not
# repeated across packages that don't touch goroutines.
#
# Deliberately NOT CGO_ENABLED=0: the race detector requires cgo (`go:
# -race requires cgo`), so this one target runs with the ambient
# CGO_ENABLED (cgo on, given a C toolchain is present). Nothing this
# target builds is shipped — it only exercises store's own test suite —
# so it does not violate the cgo-free binary rule, which is about what
# gets deployed.
test-race:
	go test -race -count=1 ./internal/sheets/store/... ./internal/sheets/live/...

# The browser checks (internal/sheets/*_browser_test.go), in a real
# Chromium: on PATH, via RASTRILLO_CHROME, or in a Playwright cache.
# Deliberately NOT part of `test`: the gate CI runs on every push must
# not need a browser. Run it before shipping a change to the CSS or to
# rastrillo's pin — TestNoZoomOnTap is the iOS zoom-on-tap check, and
# TestDocumentStylesSurviveTheProductionCSP is the one browser check served
# through rastrillo's production stack, so it sees the real CSP.
test-browser:
	CGO_ENABLED=0 go test -tags browser -count=1 -run 'OnTap|DocumentStyles' ./internal/sheets/
