Ctrl K
ComunidadGuías…

Makefile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
BINARY := nself
MODULE := github.com/nself-org/cli
DIST_DIR := dist
VERSION := $(shell cat .github/VERSION 2>/dev/null || git describe --tags 2>/dev/null || echo "dev")
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -s -w \
	-X $(MODULE)/internal/version.Version=$(VERSION) \
	-X $(MODULE)/internal/version.Commit=$(COMMIT) \
	-X $(MODULE)/internal/version.BuildDate=$(BUILD_DATE)
BUILDFLAGS := -trimpath

.PHONY: FORCE build clean test vet install cross dist verify-prod sport-f21 sport-f02 cmd-inventory registry canon core-services wiki-commands wiki-check flag-drift-audit parity schemas schemas-check contract-check sbom man fmt fmt-check

verify-prod:
	@bash scripts/prod-verify/p87-verification.sh

## Generator tools (tools/<name>) are built once into $(TOOLS_BIN)/ and then run.
## `go run` would store a fresh 35-50 MB linked executable in GOCACHE for every
## changed tool (Go 1.24+, no size cap); `go build -o` keeps it in the ignored bin/.
## FORCE rebuilds on every make invocation so an edited tool is never stale; the
## compile itself stays cached.
TOOLS_BIN := bin
$(TOOLS_BIN)/%: FORCE
	@CGO_ENABLED=0 go build -mod=vendor -o $@ ./tools/$*
FORCE:

sport-f21:
	@bash scripts/sport/generate-f21.sh

## cmd-inventory — CLI-R06. Regenerate the command inventory from the cobra tree.
## Writes .github/command-inventory.json, .github/command-registry.json (the
## command registry, contract cli.command-registry v1) and the generated block
## of .github/wiki/Commands.md.
## Set NSELF_SPORT_DIR to also refresh SPORT F02 (it lives in the PPI, not here).
## internal/repoqa asserts the committed copies match, so run this after adding,
## renaming, or removing any command.
cmd-inventory:
	@bash scripts/sport/generate-f02.sh

sport-f02: cmd-inventory

## registry — P7-REG-07. Alias of cmd-inventory: regenerates the command registry
## .github/command-registry.json together with the inventory and wiki block.
registry: cmd-inventory

## canon — P7-CANON-21. Regenerate cmd/commands/canon_moves_gen.go (the canon engine's
## move table) from internal/canon/canon.yaml and domains/*.yaml. Run after editing
## a canon fragment's rows; TestCanonTableCurrent fails when the file is stale.
canon: $(TOOLS_BIN)/canongen
	@$(TOOLS_BIN)/canongen

## core-services — CLI-R07. Regenerate .github/wiki/Core-Services.md from the
## compose service catalog. Set NSELF_SPORT_DIR to also refresh SPORT F08.
core-services:
	@bash scripts/sport/generate-core-services.sh

## wiki-commands — CLI-R08. Regenerate one wiki page per top-level command, plus
## the sidebar index and llms.txt. Human prose inside PROSE blocks is preserved;
## only the cobra-derived parts are rewritten. Use -report to list pages that
## still carry placeholder prose.
wiki-commands: $(TOOLS_BIN)/wikigen
	@$(TOOLS_BIN)/wikigen -report

## wiki-check — verify the wiki is current and every [[link]] resolves.
wiki-check: $(TOOLS_BIN)/wikigen
	@$(TOOLS_BIN)/wikigen -check
	@bash scripts/ci/wiki-link-audit.sh

## flag-drift-audit — checks every `nself <path> --flag` invocation in
## .github/wiki/ and scripts/ against the live cobra tree, so a documented or
## scripted flag that was never registered on the command it names fails the
## build instead of shipping silently (see scripts/ci/flag-drift-audit.sh).
flag-drift-audit:
	@bash scripts/ci/flag-drift-audit.sh

## parity — CLI-R17. Regenerate the four-surface parity matrix (wiki page, MCP
## tools, env var docs, HTTP routes) for every top-level command. Writes
## .github/surface-parity.md and .github/surface-parity.json. internal/repoqa
## asserts the committed copies match; run this after adding, renaming, or
## removing a command, an MCP tool, or an env var.
parity: $(TOOLS_BIN)/parity
	@$(TOOLS_BIN)/parity

## schemas — P7-REG-08. Regenerate schemas/ (JSON Schemas for the envelope, error
## object, command registry and every envelope command's data) from the Go types
## with tools/schemagen. Commit the result; internal/repoqa and `schemas-check`
## fail when the committed files drift.
schemas: $(TOOLS_BIN)/schemagen
	@$(TOOLS_BIN)/schemagen

## schemas-check — fail (exit 1) when any schemas/*.json differs from what
## tools/schemagen generates. Non-JSON files under schemas/ are ignored.
schemas-check: $(TOOLS_BIN)/schemagen
	@$(TOOLS_BIN)/schemagen -check

## regen — Run every generator in order to regenerate all generated surfaces
## before verifying a unit. Invoked by .github/land-regen.
regen:
	go run -mod=vendor ./tools/regen

## contract-check — P7-REG-10. The one gate for every machine contract the CLI
## publishes: the committed schemas/, the registry and inventory, the compat
## marker table (cheap, so a drift fails in seconds), then the P7-REG Epic's go
## test lines run twice, with NSELF_V15 unset and =1 (ADR 0021). Nothing is skipped: a missing input, a hand-edited
## generated file or a Go type that drifted from its schema exits non-zero with
## a message naming the check and the fix. The registry check regenerates with
## `make cmd-inventory` into the tree, compares every file it writes (registry,
## inventory, Commands.md, Command-Canon.md, facts.json, the README facts blocks) against what was committed (or
## hand-edited) before, then restores them, so a failing run leaves the tree as
## it found it. The wiki check runs tools/wikigen -check (the generated tables in
## error-codes.md and Exit-Codes.md) and scripts/contract-check-wiki.sh (the
## hand tables in JSON-Output.md and Exit-Codes.md against schemas/index.json,
## the registry and error-codes.md; D-0254). The Linux smoke
## (scripts/ci/contract-smoke.sh) is separate: it drives the built binary.
CONTRACT_GOTEST := CGO_ENABLED=0 go test -mod=vendor -count=1
CONTRACT_PKGS := ./internal/errs/... ./internal/output/... ./internal/canon/... ./internal/cmdregistry/... \
	./internal/compat/... ./internal/portable/... ./internal/plugin/manifestv2/... ./tools/schemagen/...
CONTRACT_REGEN := .github/command-registry.json .github/command-inventory.json .github/wiki/Commands.md \
	.github/wiki/Command-Canon.md .github/facts.json README.md
contract-check: $(TOOLS_BIN)/schemagen $(TOOLS_BIN)/wikigen
	@set -e; \
	fail() { echo "contract-check: FAILED: $$1" >&2; echo "contract-check: fix: $$2" >&2; exit 1; }; \
	for f in $(CONTRACT_REGEN) schemas/index.json scripts/ci/compat-markers.sh; do \
	  [ -f "$$f" ] || fail "missing input $$f" "restore it; a gate input that is absent must fail, never pass"; \
	done; \
	echo "contract-check: schemas"; \
	$(TOOLS_BIN)/schemagen -check \
	  || fail "schemas/ differs from tools/schemagen output" "run make schemas and commit; never hand-edit schemas/"; \
	echo "contract-check: registry and inventory"; \
	snap=$$(mktemp -d "$${TMPDIR:-/tmp}/contract-check.XXXXXX"); \
	restore() { for f in $(CONTRACT_REGEN); do cp "$$snap/$$(basename $$f)" "$$f"; done; rm -rf "$$snap"; }; \
	for f in $(CONTRACT_REGEN); do cp "$$f" "$$snap/$$(basename $$f)"; done; \
	trap restore EXIT; \
	$(MAKE) --no-print-directory cmd-inventory >/dev/null \
	  || fail "make cmd-inventory failed (the registry did not build)" "read the error above; a command missing from internal/canon/canon.yaml is the usual cause"; \
	for f in $(CONTRACT_REGEN); do \
	  cmp -s "$$snap/$$(basename $$f)" "$$f" || { \
	    diff -u "$$snap/$$(basename $$f)" "$$f" | head -40 >&2; \
	    fail "$$f is not what the generator produces (hand edit or stale)" "run make cmd-inventory and commit; never hand-edit generated files"; }; \
	done; \
	restore; trap - EXIT; \
	echo "contract-check: wiki contract pages"; \
	$(TOOLS_BIN)/wikigen -check \
	  || fail "tools/wikigen -check found stale generated wiki pages" "run make wiki-commands and commit; never hand-edit a GENERATED block"; \
	bash scripts/contract-check-wiki.sh \
	  || fail "a hand table in JSON-Output.md or Exit-Codes.md disagrees with its source" "edit the row the message names (scripts/contract-check-wiki.sh lists each check)"; \
	echo "contract-check: compat markers"; \
	bash scripts/ci/compat-markers.sh --check \
	  || fail "compat-markers.sh --check failed" "run bash scripts/ci/compat-markers.sh --write-wiki and commit"; \
	for mode in unset 1; do \
	  if [ "$$mode" = 1 ]; then NSELF_V15=1; export NSELF_V15; else unset NSELF_V15; fi; \
	  echo "contract-check: go tests (NSELF_V15=$$mode)"; \
	  $(CONTRACT_GOTEST) $(CONTRACT_PKGS) \
	    || fail "contract packages failed (NSELF_V15=$$mode)" "fix the code or regenerate the contract it names"; \
	  $(CONTRACT_GOTEST) ./internal/cmdregistry/... -run Golden \
	    || fail "registry golden failed (NSELF_V15=$$mode)" "run make cmd-inventory and review the diff"; \
	  $(CONTRACT_GOTEST) ./internal/repoqa/... \
	    || fail "repoqa drift tests failed (NSELF_V15=$$mode)" "regenerate the file the test names"; \
	  $(CONTRACT_GOTEST) ./cmd/nself/... \
	    || fail "cmd/nself exit-code tests failed (NSELF_V15=$$mode)" "fix errs.ExitCodeFor wiring"; \
	  $(CONTRACT_GOTEST) ./cmd/commands/ -run 'Registry|Canon|JSONContract|Invocation|Help|Pilot|Surface' \
	    || fail "command contract tests failed (NSELF_V15=$$mode)" "fix the command or regenerate the contract it names"; \
	done; \
	unset NSELF_V15; \
	echo "contract-check: OK"

## Q04 — SBOM generation (local dev target)
## Requires: syft (https://github.com/anchore/syft)
## Generates sbom.spdx.json (SPDX) and sbom.cdx.json (CycloneDX 1.5) from the source tree.
## Run `make sbom` before a release to verify SBOM generation works locally.
sbom:
	@echo "Checking for syft..."
	@if ! command -v syft >/dev/null 2>&1; then \
		echo "syft not found. Install via:"; \
		echo "  curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin"; \
		exit 1; \
	fi
	@echo "Generating SPDX SBOM..."
	@syft packages . --output spdx-json=sbom.spdx.json
	@echo "Generating CycloneDX 1.5 SBOM (Q04)..."
	@syft packages . --output cyclonedx-json=sbom.cdx.json
	@echo ""
	@echo "SBOMs written:"
	@echo "  sbom.spdx.json  (SPDX 2.3)        $$(wc -c < sbom.spdx.json) bytes"
	@echo "  sbom.cdx.json   (CycloneDX 1.5)   $$(wc -c < sbom.cdx.json) bytes"
	@echo ""
	@echo "Verify a release SBOM signature:"
	@echo "  bash tools/sbom/verify.sh v$(VERSION)"
	@echo ""
	@echo "Query SBOM for a package:"
	@echo "  bash tools/sbom/query.sh --local sbom.cdx.json --pkg cobra"

## man — generate man pages for all nself commands into ./man/
man: build
	@mkdir -p man
	@./$(BINARY) man --output man
	@echo "Man pages written to man/"

build:
	CGO_ENABLED=0 go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(BINARY) ./cmd/nself/

install: build
	cp $(BINARY) /usr/local/bin/$(BINARY)

clean:
	rm -f $(BINARY)
	rm -rf $(DIST_DIR)

test:
	CGO_ENABLED=0 go test -mod=vendor ./...

vet:
	CGO_ENABLED=0 go vet -mod=vendor ./...

## fmt — format all first-party Go source (cmd/ internal/ tools/).
fmt:
	gofmt -w cmd internal tools

## fmt-check — CLI-R01 gate. Same script CI runs; fails on any unformatted file.
fmt-check:
	@bash scripts/ci/gofmt-check.sh

cross: cross-linux cross-darwin

cross-linux:
	CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(BINARY)-linux-amd64 ./cmd/nself/
	CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(BINARY)-linux-arm64 ./cmd/nself/

cross-darwin:
	CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(BINARY)-darwin-amd64 ./cmd/nself/
	CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(BINARY)-darwin-arm64 ./cmd/nself/

dist:
	@mkdir -p $(DIST_DIR)
	@for platform in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do \
		os=$$(echo $$platform | cut -d/ -f1); \
		arch=$$(echo $$platform | cut -d/ -f2); \
		name=$(BINARY)-$(VERSION)-$$os-$$arch; \
		echo "Building $$os/$$arch..."; \
		mkdir -p $(DIST_DIR)/$$name; \
		CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(DIST_DIR)/$$name/$(BINARY) ./cmd/nself/; \
		cp README.md LICENSE $(DIST_DIR)/$$name/; \
		tar -czf $(DIST_DIR)/$$name.tar.gz -C $(DIST_DIR) $$name; \
		rm -rf $(DIST_DIR)/$$name; \
	done
	@for arch in amd64 arm64; do \
		name=$(BINARY)-$(VERSION)-windows-$$arch; \
		echo "Building windows/$$arch..."; \
		mkdir -p $(DIST_DIR)/$$name; \
		CGO_ENABLED=0 GOOS=windows GOARCH=$$arch go build $(BUILDFLAGS) -mod=vendor -ldflags="$(LDFLAGS)" -o $(DIST_DIR)/$$name/$(BINARY).exe ./cmd/nself/; \
		cp README.md LICENSE $(DIST_DIR)/$$name/; \
		cd $(DIST_DIR) && zip -qr $$name.zip $$name && cd ..; \
		rm -rf $(DIST_DIR)/$$name; \
	done
	@cd $(DIST_DIR) && if command -v sha256sum >/dev/null 2>&1; then \
		sha256sum *.tar.gz *.zip > checksums.txt; \
	else \
		shasum -a 256 *.tar.gz *.zip > checksums.txt; \
	fi
	@echo "dist/ ready."