Makefile
Rama main · réplica de lectura del repositorio original.
BINARY_NAME=leafwiki
CMD_DIR=./cmd/leafwiki
VERSION ?= $(shell ./scripts/resolve-version.sh)
RELEASE_DIR := releases
DOCKER_BUILDER := Dockerfile.builder
UI_DIR := ui/leafwiki-ui
HTTP_DIST := internal/http/dist
# Single source for the golangci-lint version; the lint-go job in
# .github/workflows/backend.yml reads the same file.
GOLANGCI_LINT_VERSION ?= $(shell cat .golangci-lint-version)
# golang.org/x/tools release for `make deadcode` (not a go.mod dependency).
DEADCODE_VERSION ?= v0.52.0
EMBED_LDFLAGS := -X github.com/perber/wiki/internal/http.EmbedFrontend=true -X github.com/perber/wiki/internal/http.Environment=production
LDFLAGS := -X main.Version=$(VERSION) $(EMBED_LDFLAGS)
PLATFORMS := \
linux/amd64 \
linux/386 \
linux/arm64 \
windows/amd64 \
darwin/amd64 \
darwin/arm64
# Release targets other than linux, checked by `make cross` (and in CI) so a
# platform-specific compile error doesn't first show up at the release tag.
CROSS_PLATFORMS ?= windows/amd64 darwin/arm64
all: build
# Build the Vite SPA into internal/http/dist for go:embed.
ui:
@echo "Building frontend..."
cd $(UI_DIR) && npm ci --ignore-scripts && VITE_API_URL=/ APP_VERSION=$(VERSION) npm run build
rm -rf $(HTTP_DIST)
mkdir -p $(HTTP_DIST)
cp -R $(UI_DIR)/dist/. $(HTTP_DIST)/
touch $(HTTP_DIST)/.gitkeep
@test -f $(HTTP_DIST)/index.html || (echo "Frontend build missing $(HTTP_DIST)/index.html" && exit 1)
# Self-contained binary with embedded UI (matches release/Docker builds).
build: ui
go build -trimpath -tags nomsgpack -ldflags "$(LDFLAGS)" -o $(BINARY_NAME) $(CMD_DIR)
# API-only binary for local Vite-proxied development (no embedded SPA).
build-api:
go build -ldflags "-X main.Version=$(VERSION)" -o $(BINARY_NAME) $(CMD_DIR)
# npm dependencies for the frontend (ui-deps) and the e2e tests. Install
# scripts stay off, like in CI and `make ui`.
setup: ui-deps
cd e2e && npm ci --ignore-scripts
# Only for running the E2E suites locally (make run-e2e-local); Chromium is
# the browser the suites use. On Linux, `npx playwright install-deps chromium`
# in e2e/ adds missing system libraries (needs sudo).
setup-e2e: setup
cd e2e && npx playwright install chromium
# Toolchain versions against .nvmrc and go.mod; exits 1 on a missing tool or
# the wrong Node major.
doctor:
@./scripts/doctor.sh
# Backend and Vite dev server together; Ctrl-C stops both. ARGS go to the
# backend.
dev:
@./scripts/dev.sh $(ARGS)
run:
go run -ldflags "-X main.Version=$(VERSION)" $(CMD_DIR)
# Regenerate the experimental Swagger 2.0 spec in docs/api (pinned swag, not a go.mod dependency).
api-docs:
go run github.com/swaggo/swag/cmd/swag@v1.16.6 init --generalInfo api_docs.go --dir ./cmd/leafwiki,./internal --parseInternal --requiredByDefault --output ./docs/api --outputTypes json,yaml
clean:
rm -f $(BINARY_NAME)
rm -rf $(RELEASE_DIR)
test:
go test ./...
# Built with the toolchain from go.mod, so the result matches CI.
lint:
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run
# Functions no main or test can reach (#1766). deadcode exits 0 even when it
# finds something, so any output fails the target. -test counts test-only
# helpers as used. It analyses the host platform only: a function called
# solely from another GOOS's files would be reported here.
deadcode:
@out=$$(go run golang.org/x/tools/cmd/deadcode@$(DEADCODE_VERSION) -test ./...) || exit 1; \
if [ -n "$$out" ]; then echo "$$out"; echo "Unreachable functions found; remove them."; exit 1; fi
# Frontend checks, in two halves so CI can run them as parallel jobs
# (.github/workflows/frontend.yml); ui-check runs both.
ui-deps:
cd $(UI_DIR) && npm ci --ignore-scripts
ui-lint: ui-deps
cd $(UI_DIR) && npm run lint -- --max-warnings=0 && npm run format:check
# `npm run build` is the type check (tsc -b).
ui-test: ui-deps
cd $(UI_DIR) && npm test && npm run build
ui-check: ui-lint ui-test
# The local subset of the pull-request checks. Not included: the linux/386
# tests, govulncheck, Trivy (the dependency scans, and the image scan, which
# `make scan-image` runs locally with Docker and trivy installed), the
# install-script test, the e2e lint, the E2E suites and the Dev Container
# build (.github/workflows/devcontainer.yml).
# CI jobs that keep their own command: test-go (go test with coverage for the
# report artifact), lint-go (golangci-lint-action, for PR annotations and its
# cache) and the e2e lint (npm in e2e/, which has no Make target).
ci: verify lint deadcode test cross ui-check
bench:
go test -bench=. -benchmem -benchtime=3s ./internal/links/... ./internal/core/revision/...
# Build and vet (which also type-checks _test.go files) for each of
# CROSS_PLATFORMS, without cgo, like the release builds.
cross:
@for platform in $(CROSS_PLATFORMS); do \
goos=$${platform%/*}; goarch=$${platform#*/}; \
echo "Building and vetting for $$goos/$$goarch..."; \
CGO_ENABLED=0 GOOS=$$goos GOARCH=$$goarch go build ./... || exit 1; \
CGO_ENABLED=0 GOOS=$$goos GOARCH=$$goarch go vet ./... || exit 1; \
done
# Small repository checks that need neither Go nor Node; CI runs the same
# target (.github/workflows/verify.yml).
verify:
./scripts/check-private-references.sh
./scripts/check-toolchain-versions.sh
./scripts/check-toolchain-versions.test.sh
./scripts/changelog.test.sh
# Conventional Commit subjects for BASE..HEAD; CI runs the same script
# (.github/workflows/commit-messages.yml).
BASE ?= origin/main
verify-commits:
./scripts/check-commit-messages.sh "$(BASE)..HEAD"
# Build all platform targets
release: $(PLATFORMS)
@echo "✅ All builds complete."
# Build for each platform using Docker
$(PLATFORMS):
@mkdir -p $(RELEASE_DIR)
@GOOS=$(word 1,$(subst /, ,$@)) ; \
GOARCH=$(word 2,$(subst /, ,$@)) ; \
EXT=$$( [ "$$GOOS" = "windows" ] && echo ".exe" || echo "" ) ; \
OUTPUT=$(BINARY_NAME)-$(VERSION)-$$GOOS-$$GOARCH$$EXT ; \
echo "📦 Building $$OUTPUT..." ; \
docker build -f $(DOCKER_BUILDER) \
--build-arg GOOS=$$GOOS \
--build-arg GOARCH=$$GOARCH \
--build-arg APP_VERSION=$(VERSION) \
--build-arg OUTPUT=$(BINARY_NAME) \
-t leafwiki-builder-$$GOOS-$$GOARCH . ; \
ID=$$(docker create leafwiki-builder-$$GOOS-$$GOARCH) ; \
docker cp $$ID:/out/$(BINARY_NAME) $(RELEASE_DIR)/$$OUTPUT ; \
docker rm $$ID ; \
echo "✅ Binary done: $(RELEASE_DIR)/$$OUTPUT" ; \
(cd $(RELEASE_DIR) && sha256sum $$OUTPUT > $$OUTPUT.sha256) ; \
zip -j $(RELEASE_DIR)/$$OUTPUT.zip $(RELEASE_DIR)/$$OUTPUT ; \
tar -czf $(RELEASE_DIR)/$$OUTPUT.tar.gz -C $(RELEASE_DIR) $$OUTPUT ; \
echo "📦 Compressed: zip and tar.gz"
# Build inputs of the production image that don't depend on the platform.
# docker-build-publish and scan-image share them, so the release scan checks
# the image that gets pushed and the push reuses the scan's BuildKit cache.
IMAGE_BUILD_FLAGS = --file Dockerfile --target final --build-arg APP_VERSION=$(VERSION)
# Trivy settings shared by the image scans: fail only on HIGH/CRITICAL
# findings that have a fix; .trivyignore holds the accepted false positives.
TRIVY_IMAGE_FLAGS = --severity HIGH,CRITICAL --ignore-unfixed --ignorefile .trivyignore
require-trivy:
@command -v trivy >/dev/null 2>&1 || { echo "trivy is not installed: https://trivy.dev/latest/getting-started/installation/"; exit 1; }
# Build the final image for one platform, load it into Docker and scan it.
# CI runs it on PRs that touch the image inputs
# (.github/workflows/image-scan.yml) and in the release workflow before the
# push, once per platform.
SCAN_PLATFORM ?= linux/amd64
SCAN_TAG ?= leafwiki:scan
scan-image: require-trivy
docker buildx build $(IMAGE_BUILD_FLAGS) --platform $(SCAN_PLATFORM) --load --tag $(SCAN_TAG) .
trivy image --image-src docker --platform $(SCAN_PLATFORM) $(TRIVY_IMAGE_FLAGS) \
--exit-code 1 $(SCAN_TAG)
# Scan the published image straight from the registry (--image-src remote, so
# a stale local copy with another platform isn't scanned instead). The weekly
# CI run (.github/workflows/image-scan.yml) calls it twice: once with
# TRIVY_EXIT_CODE=0 and SARIF output for code scanning, once as the gate.
SCAN_IMAGE ?= ghcr.io/perber/leafwiki:latest
TRIVY_EXIT_CODE ?= 1
TRIVY_EXTRA_FLAGS ?=
scan-published-image: require-trivy
trivy image --image-src remote --platform $(SCAN_PLATFORM) $(TRIVY_IMAGE_FLAGS) \
--exit-code $(TRIVY_EXIT_CODE) $(TRIVY_EXTRA_FLAGS) $(SCAN_IMAGE)
# Final production Docker image
docker-build-publish:
ifndef REPO_OWNER
$(error REPO_OWNER is not set. Usage: make docker-build-publish VERSION=vX.Y.Z REPO_OWNER=your_github_username)
endif
docker buildx build $(IMAGE_BUILD_FLAGS) \
--platform linux/amd64,linux/arm64 \
--tag ghcr.io/$(REPO_OWNER)/leafwiki:$(VERSION) \
--tag ghcr.io/$(REPO_OWNER)/leafwiki:latest \
--annotation "index:org.opencontainers.image.title=LeafWiki" \
--annotation "index:org.opencontainers.image.description=LeafWiki – A fast wiki for people who think in folders, not feeds" \
--sbom=true \
--provenance=mode=max \
--push .
# Generate markdown changelog between two tags
changelog:
@if [ -z "$(PREVIOUS)" ] || [ -z "$(CURRENT)" ]; then \
echo "Usage: make changelog PREVIOUS=v0.1.0 CURRENT=v0.2.0"; \
exit 1; \
fi
@./scripts/changelog.sh $(PREVIOUS) $(CURRENT)
run-e2e:
@echo "🚀 Starting end-to-end tests..."
@./e2e/run.sh
run-proxy-e2e:
@echo "🔐 Starting proxy auth E2E tests..."
@./e2e-proxy/run.sh
run-e2e-local:
@echo "⚡ Starting end-to-end tests (local fast path)..."
@E2E_RUN_MODE=local ./e2e/run.sh
# Skip the Vite build when dist/ is already up to date; useful when iterating
# on tests without changing the frontend. Pass GREP=<pattern> to filter tests,
# e.g.: make run-e2e-local-fast GREP="shoutout"
run-e2e-local-fast:
@echo "⚡ Starting end-to-end tests (local, skip UI build)..."
@E2E_RUN_MODE=local E2E_SKIP_UI_BUILD=1 ./e2e/run.sh $(if $(GREP),--grep "$(GREP)",)
help:
@echo "Available commands:"
@echo " make setup – Install npm dependencies (frontend and e2e)"
@echo " make setup-e2e – make setup plus the Playwright browser for local E2E runs"
@echo " make doctor – Show Go, Node, npm and mise versions; check them against go.mod and .nvmrc"
@echo " make dev – Run backend and Vite dev server together (http://localhost:5173)"
@echo " Optional: ARGS=\"<backend flags>\""
@echo " make build – Build self-contained binary with embedded UI (needs Node.js)"
@echo " make build-api – Build API-only binary (use with Vite in Dev Setup)"
@echo " make ui – Build frontend into internal/http/dist for embedding"
@echo " make release – Cross-compile binaries for all platforms (via Docker)"
@echo " make clean – Clean all generated files"
@echo " make api-docs – Regenerate the experimental Swagger spec in docs/api"
@echo " make test – Run all Go tests"
@echo " make lint – Run golangci-lint (version from .golangci-lint-version)"
@echo " make ui-check – Frontend install, lint, format check, tests and build"
@echo " (ui-lint and ui-test run the two halves)"
@echo " make ci – verify, lint, deadcode, test, cross and ui-check, like CI"
@echo " make deadcode – Fail on Go functions no main or test reaches"
@echo " make verify – Run small repository checks (private references, toolchain versions)"
@echo " make verify-commits – Check commit subjects since BASE (default origin/main)"
@echo " make bench – Run Go benchmarks for links and revision"
@echo " make cross – Build and vet for windows/amd64 and darwin/arm64"
@echo " Optional: CROSS_PLATFORMS=\"<goos>/<goarch> ...\""
@echo " make run-e2e – Run end-to-end tests (using Docker)"
@echo " make run-proxy-e2e – Run reverse-proxy auth E2E tests (Docker + nginx)"
@echo " make run-e2e-local – Run end-to-end tests via local fast path"
@echo " make run-e2e-local-fast – Run E2E tests locally, skip UI build (use when dist/ is current)"
@echo " Optional: GREP=<pattern> to filter tests"
@echo " make run – Run development server (API only; use Vite for UI)"
@echo " make docker-build-publish – Build and push multi-arch Docker image"
@echo " make scan-image – Build the Docker image for one platform and scan it with Trivy"
@echo " Optional: SCAN_PLATFORM=linux/arm64 SCAN_TAG=<tag>"
@echo " make scan-published-image – Scan the published image (SCAN_IMAGE, default ghcr.io/perber/leafwiki:latest) with Trivy"
@echo " Optional: SCAN_PLATFORM, TRIVY_EXIT_CODE, TRIVY_EXTRA_FLAGS"
@echo " make changelog – Generate changelog"
.PHONY: all build build-api ui setup setup-e2e doctor dev run api-docs clean test lint deadcode ui-deps ui-lint ui-test ui-check ci bench cross verify verify-commits help docker-build-publish require-trivy scan-image scan-published-image changelog run-e2e run-e2e-local run-e2e-local-fast run-proxy-e2e