A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
atcr.io
docker
container
atproto
go
1# ATCR Makefile
2# Build targets for the ATProto Container Registry
3
4.PHONY: all build build-appview build-hold build-credential-helper build-oauth-helper \
5 generate test test-race test-verbose lint lex-lint clean help install-credential-helper \
6 develop develop-detached develop-down dev \
7 docker docker-appview docker-hold docker-scanner
8
9.DEFAULT_GOAL := help
10
11help: ## Show this help message
12 @echo "ATCR Build Targets:"
13 @echo ""
14 @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)
15
16all: generate build ## Generate assets and build all binaries (default)
17
18# Generated asset files
19GENERATED_ASSETS = \
20 pkg/appview/public/js/htmx.min.js \
21 pkg/appview/public/js/lucide.min.js \
22 pkg/appview/licenses/spdx-licenses.json
23
24generate: $(GENERATED_ASSETS) ## Run go generate to download vendor assets
25
26$(GENERATED_ASSETS):
27 @echo "→ Generating vendor assets and code..."
28 go generate ./...
29
30##@ Build Targets
31
32build: build-appview build-hold build-credential-helper ## Build all binaries
33
34# Legal page "Last updated" dates come from the git commit date of the page
35# templates. Empty values (e.g., Docker builds without .git) fall back to the
36# hardcoded default in legal.go.
37LEGAL_PKG := atcr.io/pkg/appview/handlers
38PRIVACY_DATE := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/privacy.html 2>/dev/null)
39TERMS_DATE := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/terms.html 2>/dev/null)
40APPVIEW_LDFLAGS := -X '$(LEGAL_PKG).privacyLastUpdated=$(PRIVACY_DATE)' -X '$(LEGAL_PKG).termsLastUpdated=$(TERMS_DATE)'
41
42build-appview: $(GENERATED_ASSETS) ## Build appview binary only
43 @echo "→ Building appview..."
44 @mkdir -p bin
45 go build -ldflags="$(APPVIEW_LDFLAGS)" -o bin/atcr-appview ./cmd/appview
46
47build-hold: $(GENERATED_ASSETS) ## Build hold binary only
48 @echo "→ Building hold..."
49 @mkdir -p bin
50 go build -o bin/atcr-hold ./cmd/hold
51
52build-credential-helper: ## Build credential helper only
53 @echo "→ Building credential helper..."
54 @mkdir -p bin
55 go build -o bin/docker-credential-atcr ./cmd/credential-helper
56
57build-oauth-helper: ## Build OAuth helper only
58 @echo "→ Building OAuth helper..."
59 @mkdir -p bin
60 go build -o bin/oauth-helper ./cmd/oauth-helper
61
62##@ Test Targets
63
64test: ## Run all tests
65 @echo "→ Running tests..."
66 go test -cover ./...
67
68test-race: ## Run tests with race detector
69 @echo "→ Running tests with race detector..."
70 go test -race ./...
71
72test-verbose: ## Run tests with verbose output
73 @echo "→ Running tests with verbose output..."
74 go test -v ./...
75
76##@ Quality Targets
77
78.PHONY: check-golangci-lint
79check-golangci-lint:
80 @LINT_PKG=github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest; \
81 CUR_GO=$$(go version | grep -oE 'go[0-9]+\.[0-9]+' | head -1 | sed 's/^go//'); \
82 if ! command -v golangci-lint > /dev/null 2>&1; then \
83 echo "→ Installing golangci-lint..."; \
84 go install $$LINT_PKG; \
85 else \
86 LINT_GO=$$(golangci-lint --version 2>&1 | grep -oE 'built with go[0-9]+\.[0-9]+' | head -1 | sed 's/^built with go//'); \
87 if [ -n "$$LINT_GO" ] && [ "$$LINT_GO" != "$$CUR_GO" ] && \
88 [ "$$(printf '%s\n%s\n' $$LINT_GO $$CUR_GO | sort -V | head -1)" = "$$LINT_GO" ]; then \
89 echo "→ golangci-lint built with go$$LINT_GO but project targets go$$CUR_GO — reinstalling..."; \
90 go install $$LINT_PKG; \
91 fi; \
92 fi
93
94lint: check-golangci-lint ## Run golangci-lint
95 @echo "→ Running golangci-lint..."
96 golangci-lint run ./...
97
98lex-lint: ## Lint ATProto lexicon schemas
99 goat lex lint ./lexicons/
100
101##@ Install Targets
102
103install-credential-helper: build-credential-helper ## Install credential helper to /usr/local/sbin
104 @echo "→ Installing credential helper to /usr/local/sbin..."
105 install -m 755 bin/docker-credential-atcr /usr/local/sbin/docker-credential-atcr
106 @echo "✓ Installed docker-credential-atcr to /usr/local/sbin/"
107
108##@ Development Targets
109
110dev: $(GENERATED_ASSETS) ## Run AppView locally with Air hot reload
111 @which air > /dev/null || (echo "→ Installing Air..." && go install github.com/air-verse/air@latest)
112 air -c .air.toml
113
114##@ Docker Targets
115
116docker: docker-appview docker-hold docker-scanner ## Build all Docker images
117
118docker-appview: ## Build appview Docker image
119 @echo "→ Building appview Docker image..."
120 docker build -f Dockerfile.appview \
121 --build-arg PRIVACY_DATE=$(PRIVACY_DATE) \
122 --build-arg TERMS_DATE=$(TERMS_DATE) \
123 -t atcr.io/atcr.io/appview:latest .
124
125docker-hold: ## Build hold Docker image
126 @echo "→ Building hold Docker image..."
127 docker build -f Dockerfile.hold -t atcr.io/atcr.io/hold:latest .
128
129docker-scanner: ## Build scanner Docker image
130 @echo "→ Building scanner Docker image..."
131 docker build -f Dockerfile.scanner -t atcr.io/atcr.io/scanner:latest .
132
133develop: ## Build and start docker-compose with Air hot reload
134 @echo "→ Building Docker images..."
135 docker-compose build
136 @echo "→ Starting docker-compose with hot reload..."
137 docker-compose up
138
139develop-detached: ## Build and start docker-compose with hot reload (detached)
140 @echo "→ Building Docker images..."
141 docker-compose build
142 @echo "→ Starting docker-compose with hot reload (detached)..."
143 docker-compose up -d
144 @echo "✓ Services started in background with hot reload"
145 @echo " AppView: http://localhost:5000"
146 @echo " Hold: http://localhost:8080"
147
148develop-down: ## Stop docker-compose services
149 @echo "→ Stopping docker-compose..."
150 docker-compose down
151
152##@ Utility Targets
153
154clean: ## Remove built binaries and generated assets
155 @echo "→ Cleaning build artifacts..."
156 rm -rf bin/
157 rm -f pkg/appview/licenses/spdx-licenses.json
158 @echo "✓ Clean complete"