# ATCR Makefile # Build targets for the ATProto Container Registry .PHONY: all build build-appview build-hold build-credential-helper build-oauth-helper \ generate test test-race test-verbose 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: $(GENERATED_ASSETS) ## Run go generate to download vendor assets $(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 @echo "→ Building credential helper..." @mkdir -p bin go build -o bin/docker-credential-atcr ./cmd/credential-helper build-oauth-helper: ## Build OAuth helper only @echo "→ Building OAuth helper..." @mkdir -p bin go build -o bin/oauth-helper ./cmd/oauth-helper ##@ Test Targets test: ## Run all tests @echo "→ Running tests..." go test -cover ./... test-race: ## Run tests with race detector @echo "→ Running tests with race detector..." go test -race ./... test-verbose: ## Run tests with verbose output @echo "→ Running tests with verbose output..." go test -v ./... ##@ 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 ./... 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 dev: $(GENERATED_ASSETS) ## Run AppView locally with Air hot reload @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"