mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-22 10:14:15 +00:00
The lint target never passed the integration or stripe_integration tags, so every file under test/ was compiled out and unchecked. Add a pass for each and move the integration package comment onto the package's one non-test file, which is where staticcheck looks for it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WTdBxLFU5TpwmqVdVsN1wq
282 lines
12 KiB
Makefile
282 lines
12 KiB
Makefile
# ATCR Makefile
|
|
# Build targets for the ATProto Container Registry
|
|
|
|
.PHONY: all build build-appview build-hold build-credential-helper build-oauth-helper \
|
|
build-trixie \
|
|
generate test test-billing test-race test-verbose integration-test stripe-integration-test \
|
|
lint lex-lint clean help install-credential-helper \
|
|
develop develop-detached develop-down dev \
|
|
docker docker-appview docker-hold docker-scanner
|
|
|
|
.DEFAULT_GOAL := help
|
|
|
|
help: ## Show this help message
|
|
@echo "ATCR Build Targets:"
|
|
@echo ""
|
|
@awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-28s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
|
|
|
all: generate build ## Generate assets and build all binaries (default)
|
|
|
|
# Generated asset files
|
|
GENERATED_ASSETS = \
|
|
pkg/appview/public/js/htmx.min.js \
|
|
pkg/appview/public/js/lucide.min.js \
|
|
pkg/appview/licenses/spdx-licenses.json
|
|
|
|
generate: ## Run go generate ./... (always — regenerates cbor_gen, icon sprites, vendor assets)
|
|
@echo "→ Running go generate ./..."
|
|
go generate ./...
|
|
|
|
# File rule: lazily download missing vendor assets for fast incremental local builds.
|
|
# Production builds depend on the phony `generate` target instead so generated code
|
|
# (cbor_gen.go, icon sprites, etc.) is always up to date.
|
|
$(GENERATED_ASSETS):
|
|
@echo "→ Generating vendor assets and code..."
|
|
go generate ./...
|
|
|
|
##@ Build Targets
|
|
|
|
build: build-appview build-hold build-credential-helper ## Build all binaries
|
|
|
|
# Legal page "Last updated" dates come from the git commit date of the page
|
|
# templates. Empty values (e.g., Docker builds without .git) fall back to the
|
|
# hardcoded default in legal.go.
|
|
LEGAL_PKG := atcr.io/pkg/appview/handlers
|
|
PRIVACY_DATE := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/privacy.html 2>/dev/null)
|
|
TERMS_DATE := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/terms.html 2>/dev/null)
|
|
APPVIEW_LDFLAGS := -X '$(LEGAL_PKG).privacyLastUpdated=$(PRIVACY_DATE)' -X '$(LEGAL_PKG).termsLastUpdated=$(TERMS_DATE)'
|
|
|
|
build-appview: $(GENERATED_ASSETS) ## Build appview binary only
|
|
@echo "→ Building appview..."
|
|
@mkdir -p bin
|
|
go build -ldflags="$(APPVIEW_LDFLAGS)" -o bin/atcr-appview ./cmd/appview
|
|
|
|
build-hold: $(GENERATED_ASSETS) ## Build hold binary only
|
|
@echo "→ Building hold..."
|
|
@mkdir -p bin
|
|
go build -o bin/atcr-hold ./cmd/hold
|
|
|
|
build-credential-helper: ## Build credential helper only (atcr brand)
|
|
@echo "→ Building credential helper..."
|
|
@mkdir -p bin
|
|
cd cmd/credential-helper/atcr && go build -ldflags="-X main.version=$(shell git describe --tags --always 2>/dev/null || echo dev) -X main.commit=$(shell git rev-parse HEAD 2>/dev/null || echo none)" -o ../../../bin/docker-credential-atcr .
|
|
|
|
build-oauth-helper: ## Build OAuth helper only
|
|
@echo "→ Building OAuth helper..."
|
|
@mkdir -p bin
|
|
go build -o bin/oauth-helper ./cmd/oauth-helper
|
|
|
|
# Trixie cross-build (Debian 13, glibc 2.41) — produces binaries that run on
|
|
# any glibc ≥ 2.41 target, even when the host glibc is newer (e.g. Fedora's
|
|
# 2.43, which otherwise stamps sqrtf@GLIBC_2.43 onto cgo-linked output).
|
|
TRIXIE_BUILDER_IMAGE ?= golang:1-trixie
|
|
|
|
# Billing is OFF by default, and that default is load-bearing.
|
|
#
|
|
# pkg/billing sits behind the `billing` build tag, so the tag decides whether a
|
|
# deployment has Stripe compiled in at all. This target used to hardcode it,
|
|
# which meant the only supported way to build a non-billing appview was to
|
|
# bypass the Makefile and drive the container by hand — and every deploy that
|
|
# forgot to would silently switch billing on for a deployment whose operator
|
|
# had chosen to run without it.
|
|
#
|
|
# Opt in explicitly instead:
|
|
#
|
|
# make build-trixie # no billing (default)
|
|
# make build-trixie BILLING=1 # billing compiled in
|
|
#
|
|
# Only the appview is affected; hold, scanner, labeler and the credential
|
|
# helper never reference pkg/billing. Verify what you built with:
|
|
#
|
|
# strings -a bin/atcr-appview | grep -c stripe-go # 0 when billing is off
|
|
BILLING ?=
|
|
ifeq ($(BILLING),)
|
|
APPVIEW_TAGS :=
|
|
else
|
|
APPVIEW_TAGS := -tags billing
|
|
endif
|
|
|
|
build-trixie: generate ## Build all production binaries for linux/amd64 in a Debian 13 (glibc 2.41) container. Billing is off unless BILLING=1.
|
|
@echo "→ Building in $(TRIXIE_BUILDER_IMAGE) for glibc 2.41 compatibility..."
|
|
@mkdir -p bin
|
|
docker run --rm \
|
|
--user $$(id -u):$$(id -g) \
|
|
-v "$(CURDIR)":/src \
|
|
-w /src \
|
|
-e HOME=/tmp \
|
|
-e GOCACHE=/tmp/.gocache \
|
|
-e GOMODCACHE=/tmp/.gomodcache \
|
|
-e CGO_ENABLED=1 \
|
|
-e GOOS=linux \
|
|
-e GOARCH=amd64 \
|
|
$(TRIXIE_BUILDER_IMAGE) \
|
|
bash -c '\
|
|
set -e && \
|
|
go build -trimpath $(APPVIEW_TAGS) -ldflags="-s -w $(APPVIEW_LDFLAGS)" -o bin/atcr-appview ./cmd/appview && \
|
|
go build -trimpath -ldflags="-s -w" -o bin/atcr-hold ./cmd/hold && \
|
|
(cd cmd/credential-helper/atcr && go build -trimpath -ldflags="-s -w" -o ../../../bin/docker-credential-atcr .) && \
|
|
go build -trimpath -ldflags="-s -w" -o bin/atcr-labeler ./cmd/labeler && \
|
|
cd scanner && go build -trimpath -ldflags="-s -w" -o ../bin/atcr-scanner ./cmd/scanner'
|
|
@echo "✓ Built to bin/ (glibc ≥ 2.41 compatible), appview billing: $(if $(BILLING),ENABLED,disabled)"
|
|
|
|
##@ Test Targets
|
|
|
|
# Every module in the workspace except the root. `go test ./...` only ever
|
|
# covers the module it is run from, so a workspace module needs its own
|
|
# invocation or its tests never run at all. That is how the scanner's suite sat
|
|
# dark: 17 test files, none of them reached by `make test`.
|
|
#
|
|
# Derived from go.work rather than listed by hand, so adding a module to the
|
|
# workspace is enough to get it tested. Falls back to the known set if the
|
|
# go tool cannot answer, so a broken workspace fails loudly in the test run
|
|
# rather than silently testing less.
|
|
GO_SUBMODULE_DIRS := $(shell go list -m -f '{{.Dir}}' 2>/dev/null | tail -n +2)
|
|
ifeq ($(strip $(GO_SUBMODULE_DIRS)),)
|
|
GO_SUBMODULE_DIRS := scanner cmd/credential-helper/atcr cmd/credential-helper/seamark deploy/upcloud
|
|
endif
|
|
|
|
# $(call test-submodules,<go test flags>)
|
|
define test-submodules
|
|
@for dir in $(GO_SUBMODULE_DIRS); do \
|
|
echo "→ Testing module $$(basename $$dir)..."; \
|
|
(cd $$dir && go test $(1) ./...) || exit 1; \
|
|
done
|
|
endef
|
|
|
|
# Tests run as a `testmode` build. The tag compiles pkg/atproto/indigo_local.go
|
|
# in place of indigo_prod.go, which is what lets a did:web on a loopback port
|
|
# (every test server, the integration harness, docker-compose) resolve over
|
|
# plain HTTP. Production binaries never carry the tag; there is no runtime
|
|
# switch. Tests that need it fail fast with a message naming the tag.
|
|
TEST_TAGS := testmode
|
|
|
|
test: test-billing ## Run all tests (every workspace module)
|
|
@echo "→ Running tests..."
|
|
go test -tags $(TEST_TAGS) -cover ./...
|
|
$(call test-submodules,-tags $(TEST_TAGS) -cover)
|
|
|
|
# pkg/billing is behind the `billing` build tag, so `go test ./...` never
|
|
# compiles it, let alone runs it. Its tests covered the money path and had
|
|
# never executed in this target or in CI.
|
|
test-billing: ## Run the billing-tagged tests (skipped by plain `go test ./...`)
|
|
@echo "→ Running billing-tagged tests..."
|
|
go test -tags billing,$(TEST_TAGS) -cover ./pkg/billing/...
|
|
|
|
test-race: ## Run tests with race detector (every workspace module)
|
|
@echo "→ Running tests with race detector..."
|
|
go test -race -tags $(TEST_TAGS) ./...
|
|
@echo "→ Running billing-tagged tests with race detector..."
|
|
go test -race -tags billing,$(TEST_TAGS) ./pkg/billing/...
|
|
$(call test-submodules,-race -tags $(TEST_TAGS))
|
|
|
|
test-verbose: ## Run tests with verbose output (every workspace module)
|
|
@echo "→ Running tests with verbose output..."
|
|
go test -v -tags $(TEST_TAGS) ./...
|
|
$(call test-submodules,-v -tags $(TEST_TAGS))
|
|
|
|
integration-test: ## Run in-process smoke test (no docker, fake PDS + gofakes3 + hold + appview)
|
|
@echo "→ Running integration smoke test..."
|
|
go test -tags=integration,$(TEST_TAGS) -count=1 -race -timeout=120s ./test/integration/...
|
|
|
|
stripe-integration-test: ## Run Stripe sandbox-backed billing tests (needs STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_TEST_PRICE_MONTHLY, STRIPE_TEST_PRICE_YEARLY)
|
|
@echo "→ Running Stripe sandbox integration tests..."
|
|
@echo " Required env: STRIPE_SECRET_KEY (sk_test_...), STRIPE_WEBHOOK_SECRET (whsec_...),"
|
|
@echo " STRIPE_TEST_PRICE_MONTHLY, STRIPE_TEST_PRICE_YEARLY"
|
|
@echo " Optional env: STRIPE_TEST_TIER_NAME (default 'Supporter'),"
|
|
@echo " STRIPE_TEST_EXISTING_CUSTOMER_DID (skips portal search-lag wait)"
|
|
go test -tags="billing stripe_integration $(TEST_TAGS)" -count=1 -timeout=180s ./test/stripe-integration/...
|
|
|
|
##@ Quality Targets
|
|
|
|
.PHONY: check-golangci-lint
|
|
check-golangci-lint:
|
|
@LINT_PKG=github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest; \
|
|
CUR_GO=$$(go version | grep -oE 'go[0-9]+\.[0-9]+' | head -1 | sed 's/^go//'); \
|
|
if ! command -v golangci-lint > /dev/null 2>&1; then \
|
|
echo "→ Installing golangci-lint..."; \
|
|
go install $$LINT_PKG; \
|
|
else \
|
|
LINT_GO=$$(golangci-lint --version 2>&1 | grep -oE 'built with go[0-9]+\.[0-9]+' | head -1 | sed 's/^built with go//'); \
|
|
if [ -n "$$LINT_GO" ] && [ "$$LINT_GO" != "$$CUR_GO" ] && \
|
|
[ "$$(printf '%s\n%s\n' $$LINT_GO $$CUR_GO | sort -V | head -1)" = "$$LINT_GO" ]; then \
|
|
echo "→ golangci-lint built with go$$LINT_GO but project targets go$$CUR_GO — reinstalling..."; \
|
|
go install $$LINT_PKG; \
|
|
fi; \
|
|
fi
|
|
|
|
lint: check-golangci-lint ## Run golangci-lint
|
|
@echo "→ Running golangci-lint..."
|
|
golangci-lint run ./...
|
|
@echo "→ Running golangci-lint (billing tag)..."
|
|
golangci-lint run --build-tags=billing ./pkg/billing/...
|
|
@echo "→ Running golangci-lint (testmode tag)..."
|
|
golangci-lint run --build-tags=testmode ./...
|
|
@echo "→ Running golangci-lint (integration tags)..."
|
|
golangci-lint run --build-tags=integration,testmode ./test/integration/...
|
|
golangci-lint run --build-tags=billing,stripe_integration,testmode ./test/stripe-integration/...
|
|
|
|
lex-lint: ## Lint ATProto lexicon schemas
|
|
goat lex lint ./lexicons/
|
|
|
|
##@ Install Targets
|
|
|
|
install-credential-helper: build-credential-helper ## Install credential helper to /usr/local/sbin
|
|
@echo "→ Installing credential helper to /usr/local/sbin..."
|
|
install -m 755 bin/docker-credential-atcr /usr/local/sbin/docker-credential-atcr
|
|
@echo "✓ Installed docker-credential-atcr to /usr/local/sbin/"
|
|
|
|
##@ Development Targets
|
|
|
|
# Air's build command appends $GO_TAGS to its -tags list; a local run needs
|
|
# `testmode` for the same reason the tests do (see TEST_TAGS above).
|
|
dev: export GO_TAGS ?= testmode
|
|
dev: $(GENERATED_ASSETS) ## Run AppView locally with Air hot reload (testmode build)
|
|
@which air > /dev/null || (echo "→ Installing Air..." && go install github.com/air-verse/air@latest)
|
|
air -c .air.toml
|
|
|
|
##@ Docker Targets
|
|
|
|
docker: docker-appview docker-hold docker-scanner ## Build all Docker images
|
|
|
|
docker-appview: ## Build appview Docker image
|
|
@echo "→ Building appview Docker image..."
|
|
docker build -f Dockerfile.appview \
|
|
--build-arg PRIVACY_DATE=$(PRIVACY_DATE) \
|
|
--build-arg TERMS_DATE=$(TERMS_DATE) \
|
|
-t atcr.io/atcr.io/appview:latest .
|
|
|
|
docker-hold: ## Build hold Docker image
|
|
@echo "→ Building hold Docker image..."
|
|
docker build -f Dockerfile.hold -t atcr.io/atcr.io/hold:latest .
|
|
|
|
docker-scanner: ## Build scanner Docker image
|
|
@echo "→ Building scanner Docker image..."
|
|
docker build -f Dockerfile.scanner -t atcr.io/atcr.io/scanner:latest .
|
|
|
|
develop: ## Build and start docker-compose with Air hot reload
|
|
@echo "→ Building Docker images..."
|
|
docker-compose build
|
|
@echo "→ Starting docker-compose with hot reload..."
|
|
docker-compose up
|
|
|
|
develop-detached: ## Build and start docker-compose with hot reload (detached)
|
|
@echo "→ Building Docker images..."
|
|
docker-compose build
|
|
@echo "→ Starting docker-compose with hot reload (detached)..."
|
|
docker-compose up -d
|
|
@echo "✓ Services started in background with hot reload"
|
|
@echo " AppView: http://localhost:5000"
|
|
@echo " Hold: http://localhost:8080"
|
|
|
|
develop-down: ## Stop docker-compose services
|
|
@echo "→ Stopping docker-compose..."
|
|
docker-compose down
|
|
|
|
##@ Utility Targets
|
|
|
|
clean: ## Remove built binaries and generated assets
|
|
@echo "→ Cleaning build artifacts..."
|
|
rm -rf bin/
|
|
rm -f pkg/appview/licenses/spdx-licenses.json
|
|
@echo "✓ Clean complete"
|