288 lines
12 KiB
Makefile
288 lines
12 KiB
Makefile
|
|
# =============================================================================
|
||
|
|
# go-doc — documentation & audience feedback platform
|
||
|
|
#
|
||
|
|
# make help list every target
|
||
|
|
# make dev run infrastructure + backend + frontend together
|
||
|
|
# make test run unit, integration and BDD suites
|
||
|
|
# make build embed the React bundle into the portable Go binary
|
||
|
|
# make docker build the all-in-one image
|
||
|
|
# make docker-push build and push the image to the private registry
|
||
|
|
# make docker-run run the image on :8080
|
||
|
|
# make helm-deploy-development deploy to development
|
||
|
|
# make helm-deploy-production deploy to production
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
SHELL := /bin/bash
|
||
|
|
.SHELLFLAGS := -eu -o pipefail -c
|
||
|
|
|
||
|
|
GO ?= go
|
||
|
|
NPM ?= npm
|
||
|
|
COMPOSE ?= docker compose
|
||
|
|
HELM ?= helm
|
||
|
|
|
||
|
|
ROOT := $(shell pwd)
|
||
|
|
WORKSPACE ?= $(dir $(ROOT))
|
||
|
|
BACKEND_DIR := $(ROOT)/backend
|
||
|
|
FRONTEND_DIR := $(ROOT)/frontend
|
||
|
|
DATA_DIR := $(ROOT)/data
|
||
|
|
WEBUI_DIST := $(BACKEND_DIR)/webui/dist
|
||
|
|
|
||
|
|
BINARY := $(ROOT)/bin/godoc
|
||
|
|
BACKEND_ADDR ?= 0.0.0.0:8080
|
||
|
|
HOST_ADDR ?= 127.0.0.1:8080
|
||
|
|
VITE_PORT ?= 5173
|
||
|
|
|
||
|
|
# Docker/Registry
|
||
|
|
IMAGE ?= go-doc
|
||
|
|
TAG ?= latest
|
||
|
|
REGISTRY_IMAGE ?= nexus.urpi.be/docker-hosted/go-doc
|
||
|
|
|
||
|
|
# Helm
|
||
|
|
HELM_CHART := $(ROOT)/helm/go-doc
|
||
|
|
HELM_RELEASE ?= go-doc
|
||
|
|
HELM_NAMESPACE ?= go-doc
|
||
|
|
KUBECONFIG ?= $(HOME)/.kube/config
|
||
|
|
GO_LOOSE_CA_SECRET ?= local-ca
|
||
|
|
|
||
|
|
# Go Loose credentials passed via environment or .env
|
||
|
|
GO_LOOSE_SET = $(if $(GO_LOOSE_CLIENT_ID),--set-string goLoose.clientID=$(GO_LOOSE_CLIENT_ID)) \
|
||
|
|
$(if $(GO_LOOSE_CLIENT_SECRET),--set-string goLoose.clientSecret=$(GO_LOOSE_CLIENT_SECRET)) \
|
||
|
|
$(if $(GO_LOOSE_CA_SECRET),--set-string goLoose.ca.existingSecret=$(GO_LOOSE_CA_SECRET))
|
||
|
|
|
||
|
|
# Parent directory that holds the go-* projects to document. Override with
|
||
|
|
# WORKSPACE=/path/to/projects when the projects live elsewhere.
|
||
|
|
DOCS_WORKSPACE ?= $(patsubst %/,%,$(WORKSPACE))
|
||
|
|
DOCGEN_INTERVAL ?= 5s
|
||
|
|
|
||
|
|
DOCS_COUNT ?= 120
|
||
|
|
COMMENTS_PER_DOC ?= 25
|
||
|
|
SEED_WORKERS ?= 8
|
||
|
|
|
||
|
|
GO_SOURCES := $(shell find $(BACKEND_DIR) -name '*.go' -type f 2>/dev/null)
|
||
|
|
FRONTEND_SOURCES := $(shell find $(FRONTEND_DIR)/src -type f 2>/dev/null)
|
||
|
|
|
||
|
|
.DEFAULT_GOAL := help
|
||
|
|
.PHONY: help infra-up infra-down infra-logs backend-run frontend-run dev test \
|
||
|
|
test-unit test-integration test-bdd test-race build build-frontend \
|
||
|
|
build-backend fmt vet tidy seed seed-perf clean distclean run docker-build \
|
||
|
|
docker docker-push docker-run helm-lint helm-deploy-development \
|
||
|
|
helm-deploy-production helm-down-development helm-down-production \
|
||
|
|
docs-sync docs-watch docs-dry-run docs-list
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Help
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
help: ## Show this help
|
||
|
|
@printf '\n\033[1mgo-doc\033[0m — available targets\n\n'
|
||
|
|
@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
|
||
|
|
| sort \
|
||
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||
|
|
@printf '\n'
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Infrastructure
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
infra-up: ## Start local development containers detached
|
||
|
|
@if $(COMPOSE) version >/dev/null 2>&1; then \
|
||
|
|
$(COMPOSE) up -d --remove-orphans; \
|
||
|
|
else \
|
||
|
|
echo "error: '$(COMPOSE)' is unavailable. Install Docker Compose v2." >&2; \
|
||
|
|
exit 1; \
|
||
|
|
fi
|
||
|
|
|
||
|
|
infra-down: ## Tear down infrastructure and remove volumes
|
||
|
|
@if $(COMPOSE) version >/dev/null 2>&1; then \
|
||
|
|
$(COMPOSE) down --volumes --remove-orphans; \
|
||
|
|
else \
|
||
|
|
echo "docker compose unavailable; nothing to tear down"; \
|
||
|
|
fi
|
||
|
|
|
||
|
|
infra-logs: ## Tail infrastructure logs
|
||
|
|
$(COMPOSE) logs -f
|
||
|
|
|
||
|
|
docker-build: ## Build the container images
|
||
|
|
$(COMPOSE) build
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Run
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
backend-run: ## Run the Go API natively on 0.0.0.0:8080
|
||
|
|
@mkdir -p $(DATA_DIR)
|
||
|
|
@echo "→ backend http://$(HOST_ADDR)"
|
||
|
|
@cd $(BACKEND_DIR) && GO_DOC_DATA_DIR=$(DATA_DIR) $(GO) run main.go -addr $(BACKEND_ADDR)
|
||
|
|
|
||
|
|
frontend-run: ## Run the Vite dev server on port 5173
|
||
|
|
@echo "→ frontend http://$(VITE_PORT)"
|
||
|
|
@cd $(FRONTEND_DIR) && $(NPM) run dev -- --port $(VITE_PORT)
|
||
|
|
|
||
|
|
dev: ## Run backend, frontend and infrastructure concurrently
|
||
|
|
@$(MAKE) --no-print-directory infra-up
|
||
|
|
@echo "→ backend http://$(HOST_ADDR)"
|
||
|
|
@echo "→ frontend http://$(VITE_PORT) (Ctrl-C stops everything)"
|
||
|
|
@trap 'echo; echo "→ stopping dev stack"; kill 0' EXIT INT TERM; \
|
||
|
|
( cd $(BACKEND_DIR) && GO_DOC_DATA_DIR=$(DATA_DIR) $(GO) run main.go -addr $(BACKEND_ADDR) ) & \
|
||
|
|
( cd $(FRONTEND_DIR) && $(NPM) run dev -- --port $(VITE_PORT) ) & \
|
||
|
|
wait
|
||
|
|
|
||
|
|
run: build ## Build the single-file binary and run it
|
||
|
|
@echo "→ serving SPA + API on http://$(HOST_ADDR)"
|
||
|
|
@$(BINARY) -addr $(BACKEND_ADDR) -data $(DATA_DIR)
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Test
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
test: fmt vet ## Run every suite: unit, integration, BDD, race
|
||
|
|
@echo "→ go test ./... -count=1"
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./... -count=1
|
||
|
|
@echo "→ race detector on the storage engine and API"
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./storage/... ./tests/... -race -count=1
|
||
|
|
@echo "✓ all suites passed"
|
||
|
|
|
||
|
|
test-unit: ## Run storage engine unit tests only
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./storage/... -count=1 -v
|
||
|
|
|
||
|
|
test-integration: ## Run end-to-end API tests against the real filesystem
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./tests/ -run Integration -count=1 -v
|
||
|
|
|
||
|
|
test-bdd: ## Run the BDD feature suites
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./tests/bdd/... -count=1 -v
|
||
|
|
|
||
|
|
test-race: ## Run all tests under the race detector
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) test ./... -race -count=1
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Build
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
build: build-frontend build-backend ## Build the SPA and embed it in the Go binary
|
||
|
|
@echo "✓ $(BINARY) serves both the SPA and /api"
|
||
|
|
|
||
|
|
build-frontend: $(FRONTEND_SOURCES) ## Compile the React bundle into frontend/dist
|
||
|
|
@cd $(FRONTEND_DIR) && $(NPM) install --no-audit --no-fund
|
||
|
|
@cd $(FRONTEND_DIR) && $(NPM) run build
|
||
|
|
|
||
|
|
build-backend: $(GO_SOURCES) ## Stage assets into webui/dist and compile the binary
|
||
|
|
@test -f $(FRONTEND_DIR)/dist/index.html || { \
|
||
|
|
echo "error: frontend/dist/index.html missing — run 'make build-frontend' first" >&2; \
|
||
|
|
exit 1; \
|
||
|
|
}
|
||
|
|
@mkdir -p $(WEBUI_DIST) $(dir $(BINARY))
|
||
|
|
@rm -rf $(WEBUI_DIST)
|
||
|
|
@mkdir -p $(WEBUI_DIST)
|
||
|
|
@cp -r $(FRONTEND_DIR)/dist/. $(WEBUI_DIST)/
|
||
|
|
@echo "→ embedded assets: $$(find $(WEBUI_DIST) -type f | wc -l) files"
|
||
|
|
@cd $(BACKEND_DIR) && CGO_ENABLED=0 $(GO) build -trimpath -ldflags '-s -w' -o $(BINARY) .
|
||
|
|
@echo "✓ built $(BINARY) ($$(du -h $(BINARY) | cut -f1))"
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Quality
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
fmt: ## gofmt the backend
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) fmt ./... >/dev/null
|
||
|
|
@echo "✓ gofmt"
|
||
|
|
|
||
|
|
vet: ## go vet the backend
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) vet ./...
|
||
|
|
@echo "✓ go vet"
|
||
|
|
|
||
|
|
tidy: ## Tidy go.mod
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) mod tidy
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Documentation generation
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Every go-* project under WORKSPACE is analysed and imported into data/docs.
|
||
|
|
## Generated pages are wrapped in <!-- go-doc:generated ---> markers, so a
|
||
|
|
## re-sync replaces only the machine-written part and keeps anything you wrote
|
||
|
|
## outside the markers. Pass DOCGEN_ARGS to reach the CLI directly, e.g.
|
||
|
|
## make docs-sync DOCGEN_ARGS="-apps go-tell -force"
|
||
|
|
|
||
|
|
docs-sync: ## Analyse every go-* project under WORKSPACE and import its docs (DOCGEN_ARGS)
|
||
|
|
@mkdir -p $(DATA_DIR)/docs
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) run ./scripts/docgen \
|
||
|
|
-root $(DOCS_WORKSPACE) -data $(DATA_DIR) $(DOCGEN_ARGS)
|
||
|
|
|
||
|
|
docs-watch: ## Keep importing documentation as projects change (Ctrl-C to stop)
|
||
|
|
@mkdir -p $(DATA_DIR)/docs
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) run ./scripts/docgen \
|
||
|
|
-root $(DOCS_WORKSPACE) -data $(DATA_DIR) -watch -interval $(DOCGEN_INTERVAL) $(DOCGEN_ARGS)
|
||
|
|
|
||
|
|
docs-dry-run: ## Analyse and render without writing anything
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) run ./scripts/docgen \
|
||
|
|
-root $(DOCS_WORKSPACE) -data $(DATA_DIR) -dry-run $(DOCGEN_ARGS)
|
||
|
|
|
||
|
|
docs-list: ## List the go-* projects that a sync would import
|
||
|
|
@printf 'workspace: %s\n\n' '$(DOCS_WORKSPACE)'
|
||
|
|
@ls -1 $(DOCS_WORKSPACE) 2>/dev/null | grep '^go-' | grep -v '^go-doc$$' | sed 's/^/ /'
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Data
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
seed: ## Seed 120 generated documents + thousands of comments (DOCS_COUNT, COMMENTS_PER_DOC)
|
||
|
|
@cd $(BACKEND_DIR) && $(GO) run ./scripts/seed_perf_data.go \
|
||
|
|
-data $(DATA_DIR) -docs $(DOCS_COUNT) -comments $(COMMENTS_PER_DOC) -workers $(SEED_WORKERS)
|
||
|
|
|
||
|
|
seed-perf: seed ## Alias for seed
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Clean
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
clean: ## Remove build artefacts
|
||
|
|
@rm -rf $(ROOT)/bin $(FRONTEND_DIR)/dist
|
||
|
|
@echo "✓ cleaned build artefacts (backend/webui/dist left intact)"
|
||
|
|
|
||
|
|
distclean: clean ## Also restore the placeholder frontend bundle
|
||
|
|
@rm -rf $(WEBUI_DIST)
|
||
|
|
@mkdir -p $(WEBUI_DIST)
|
||
|
|
@cp $(BACKEND_DIR)/webui/dist.placeholder/index.html $(WEBUI_DIST)/index.html
|
||
|
|
@echo "✓ webui/dist reset to the placeholder bundle"
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Docker
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
docker: ## Build the all-in-one image
|
||
|
|
docker build -t $(IMAGE):$(TAG) -f $(BACKEND_DIR)/Dockerfile .
|
||
|
|
|
||
|
|
docker-push: ## Build and push the image to the private registry
|
||
|
|
docker tag $(IMAGE):$(TAG) $(REGISTRY_IMAGE):$(TAG)
|
||
|
|
docker push $(REGISTRY_IMAGE):$(TAG)
|
||
|
|
|
||
|
|
docker-run: ## Run the image on :8080
|
||
|
|
docker run --rm -p 8080:8080 --env-file $(ROOT)/.env $(IMAGE):$(TAG)
|
||
|
|
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
## Helm
|
||
|
|
## ---------------------------------------------------------------------------
|
||
|
|
helm-lint: ## Lint the helm chart
|
||
|
|
$(HELM) lint $(HELM_CHART) -f $(HELM_CHART)/values-dev.yaml
|
||
|
|
$(HELM) lint $(HELM_CHART) -f $(HELM_CHART)/values-prd.yaml
|
||
|
|
$(HELM) template $(HELM_RELEASE) $(HELM_CHART) \
|
||
|
|
-f $(HELM_CHART)/values-dev.yaml >/dev/null
|
||
|
|
$(HELM) template $(HELM_RELEASE) $(HELM_CHART) \
|
||
|
|
-f $(HELM_CHART)/values-prd.yaml \
|
||
|
|
--set-string goLoose.clientID=lint --set-string goLoose.clientSecret=lint >/dev/null
|
||
|
|
|
||
|
|
# Go Loose credentials are never stored in the values files. Pass them on the
|
||
|
|
# command line, from a secret store, or with --set-file:
|
||
|
|
# make helm-deploy-production \
|
||
|
|
# --set goLoose.clientID=$(GO_LOOSE_CLIENT_ID) \
|
||
|
|
# --set goLoose.clientSecret=$(GO_LOOSE_CLIENT_SECRET) \
|
||
|
|
# --set goLoose.ca.existingSecret=local-ca
|
||
|
|
helm-deploy-development: ## Deploy to development
|
||
|
|
KUBECONFIG="$(KUBECONFIG)" $(HELM) upgrade --install $(HELM_RELEASE) $(HELM_CHART) \
|
||
|
|
--namespace $(HELM_NAMESPACE)-development --create-namespace \
|
||
|
|
-f $(HELM_CHART)/values-dev.yaml \
|
||
|
|
--rollback-on-failure --wait --timeout 10m
|
||
|
|
|
||
|
|
helm-deploy-production: ## Deploy to production
|
||
|
|
set -a; [ ! -f $(ROOT)/.env ] || . $(ROOT)/.env; set +a; \
|
||
|
|
KUBECONFIG="$(KUBECONFIG)" $(HELM) upgrade --install $(HELM_RELEASE) $(HELM_CHART) \
|
||
|
|
--namespace go-insane-prd --create-namespace \
|
||
|
|
-f $(HELM_CHART)/values-prd.yaml \
|
||
|
|
$(GO_LOOSE_SET) \
|
||
|
|
--rollback-on-failure --wait --timeout 10m
|
||
|
|
|
||
|
|
helm-down-development: ## Tear down development release
|
||
|
|
KUBECONFIG="$(KUBECONFIG)" $(HELM) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-development
|
||
|
|
|
||
|
|
helm-down-production: ## Tear down production release
|
||
|
|
KUBECONFIG="$(KUBECONFIG)" $(HELM) uninstall $(HELM_RELEASE) -n $(HELM_NAMESPACE)-production
|