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.
147 lines
4.4 KiB
Makefile
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
|