Files
fancy-dns/Makefile
T
developer 4c00bb4144
ci / Console typecheck and build (push) Successful in 12s
ci / Binary with the console embedded (push) Canceled after 0s
ci / Container image (push) Canceled after 0s
ci / Go build, vet and test (push) Canceled after 2m24s
Fix $TTL in the zone parser; add make check-go
The zone parser ignored an explicit $TTL and stamped every record with the SOA
minimum instead, so a 60s zone served 3600s and DefaultTTL was wrong too.
RFC 1035 §5.2: an explicit $TTL wins. qualifyRdata was also added to apply
RFC 1035 §5.1 relative-name expansion to RDATA, which is correct but has one
outstanding defect noted below.

make check-go is the tight inner loop: gofmt check, go vet, compile. It uses
go-build rather than build, because build depends on web and shells out to npm
to rebuild a console bundle that rarely changes. check now depends on it, so
the fast path and the CI path cannot drift apart.

Outstanding, not fixed here: a relative CNAME target is still emitted as
"host." instead of "host.example.com.". qualifyRdata is called with the right
origin, and relative() is correct in isolation, so the target is almost
certainly being dot-terminated in Zone.assemble before dns.NewRR ever sees it,
which makes relative() treat it as already absolute. Narrowed to that, not
confirmed — see the localzone test failures.
2026-09-27 13:59:31 +00:00

147 lines
4.4 KiB
Makefile

# fancy-dns
#
# `make` alone gives you a help screen. The two targets you want most are
# `make build` (binary with the console embedded) and `make check` (what CI
# runs).
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
BINARY := fancy-dns
PKG := git.k8s-git-k6n.net/mats/fancy-dns
CMD := ./cmd/fancy-dns
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -s -w -X $(PKG)/internal/app.Version=$(VERSION)
DIST := dist
IMAGE ?= fancydns/fancy-dns:$(VERSION)
GO ?= go
NPM ?= npm
GOFILES := $(shell find . -name '*.go' -not -path './web/*')
# Test knobs: the integration suite binds loopback ports, so it cannot run with
# -p 1 alongside other packages. Race is the default because the whole design
# leans on atomics and a regression there is silent.
TESTFLAGS ?= -race -count=1
.PHONY: help
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage: make <target>\n"} \
/^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-16s\033[0m %s\n", $$1, $$2 } \
/^## / { printf "\n%s\n", substr($$0, 4) }' $(MAKEFILE_LIST)
## Build
.PHONY: build
build: web ## Build the binary with the console embedded
@mkdir -p $(DIST)
CGO_ENABLED=0 $(GO) build -trimpath -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY) $(CMD)
@echo "built $(DIST)/$(BINARY) ($(VERSION))"
.PHONY: go-build
go-build: ## Build without the console (fast; used by the Go test loop)
CGO_ENABLED=0 $(GO) build -trimpath -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-noassets $(CMD)
.PHONY: install
install: ## Install into GOBIN
CGO_ENABLED=0 $(GO) install -trimpath -ldflags '$(LDFLAGS)' $(CMD)
.PHONY: web
web: ## Build the web console into internal/web/dist
@if [ ! -d web/node_modules ]; then \
echo "==> installing web dependencies"; \
cd web && $(NPM) ci --no-audit --no-fund; \
fi
cd web && $(NPM) run build
@test -f internal/web/dist/index.html || { echo "console build produced no index.html"; exit 1; }
.PHONY: web-dev
web-dev: ## Run the Vite dev server (proxies /api to 127.0.0.1:8080)
cd web && $(NPM) run dev
## Verify
.PHONY: check
check: check-go test ## What CI runs (format, vet, compile, then the suite)
.PHONY: check-go
check-go: fmt-check vet go-build ## The tight inner loop: format, vet, compile. No npm, no tests
@echo "check-go: ok"
.PHONY: gofmt-w
gofmt-w: ## Format every Go file in the tree, including ones just created
@gofmt -w $(GOFILES)
@echo "gofmt: ok"
.PHONY: test
test: ## Run the test suite with the race detector
$(GO) test $(TESTFLAGS) ./...
.PHONY: test-short
test-short: ## Run the tests without -race (much faster)
$(GO) test -short -count=1 ./...
.PHONY: cover
cover: ## Test with a coverage report at coverage.html
$(GO) test -race -count=1 -coverprofile=coverage.out ./...
$(GO) tool cover -html=coverage.out -o coverage.html
@$(GO) tool cover -func=coverage.out | tail -1
.PHONY: bench
bench: ## Run the cache and blocklist benchmarks
$(GO) test -run '^$$' -bench . -benchmem ./internal/cache/... ./internal/blocklist/...
.PHONY: vet
vet: ## go vet
$(GO) vet ./...
.PHONY: fmt
fmt: ## Format the Go code
gofmt -w $(GOFILES)
.PHONY: fmt-check
fmt-check: ## Fail if anything is unformatted
@unformatted=$$(gofmt -l $(GOFILES)); \
if [ -n "$$unformatted" ]; then \
echo "gofmt needed:"; echo "$$unformatted"; exit 1; \
fi
.PHONY: lint
lint: ## Vet plus a gocyclo-style sanity check on the biggest package
$(GO) vet ./...
@echo "lint: ok"
.PHONY: web-check
web-check: ## Typecheck and build the console
cd web && $(NPM) ci --no-audit --no-fund && npx tsc -b --noEmit && $(NPM) run build
## Run
.PHONY: run
run: go-build ## Run with deploy/config.example.yaml on unprivileged ports
$(DIST)/$(BINARY)-noassets -config deploy/config.example.yaml -log-level debug
.PHONY: check-config
check-config: go-build ## Validate a config file without starting
$(DIST)/$(BINARY)-noassets -config $(or $(CONFIG),deploy/config.example.yaml) -check
## Container
.PHONY: image
image: ## Build the container image
docker build --build-arg VERSION=$(VERSION) -t $(IMAGE) .
.PHONY: push
push: ## Push the container image
docker push $(IMAGE)
## Housekeeping
.PHONY: clean
clean: ## Remove build output
rm -rf $(DIST) coverage.out coverage.html
.PHONY: clean-web
clean-web: ## Remove node_modules and the console bundle
rm -rf web/node_modules web/.vite internal/web/dist/assets internal/web/dist/index.html