Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
114 lines (94 loc) · 4.59 KB
/
Copy pathMakefile
File metadata and controls
114 lines (94 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
.PHONY: all test test-hooks lint build build-linux install install-hooks mutants bench fuzz fuzz-manifest fuzz-path semver validate-plan docs-debt schema
# Derived from the tracked set (git ls-files), not a hand-maintained list --
# an omitted file would leave a hand-list's coverage unchanged rather than
# lowering it (tdd.md "Coverage Denominators"). The env -u prefix strips a
# GIT_DIR that git exports into a worktree pre-push hook's environment
# (ci.md/shell.md); without it this parse-time assignment can silently
# resolve against the wrong repository.
SHELLCHECK := $(shell command -v shellcheck 2>/dev/null)
SHELL_FILES := $(shell env -u GIT_DIR -u GIT_WORK_TREE -u GIT_COMMON_DIR -u GIT_INDEX_FILE \
git ls-files '*.sh' '*.bash' 'scripts/pre-commit' 'scripts/pre-push' 'scripts/commit-msg')
all: test build
test: lint test-hooks
cargo nextest run
pytest tests/ -v
# Hook tests: shellcheck, then bats. scripts/pre-push is already covered by
# `make lint`. A missing tool degrades locally (remedy printed, skipped, exit 0) so
# it cannot lock a machine out of committing (core.md shell-004), but fails when CI
# is set so CI cannot skip silently.
test-hooks:
@missing=""; \
command -v shellcheck >/dev/null 2>&1 || missing="shellcheck (install: sudo apt-get install shellcheck; CI pins shellcheck 0.11.0; apt may differ)"; \
command -v bats >/dev/null 2>&1 || missing="$${missing:+$$missing; }bats (install: sudo apt-get install bats)"; \
if [ -n "$$missing" ]; then \
printf 'test-hooks: %s not found, skipping\n' "$$missing" >&2; \
if [ -n "$${CI:-}" ]; then exit 1; fi; \
exit 0; \
fi; \
shellcheck --severity=warning tests/pre_push.bats && \
bats tests/pre_push.bats < /dev/null
lint:
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo machete
ruff check scripts/ tests/
ruff format --check scripts/ tests/
@if [ -z "$(SHELL_FILES)" ]; then \
printf 'lint: derived shell file list is EMPTY — refusing to report a pass having linted nothing.\n' >&2; \
exit 1; \
fi
@if [ -n "$(SHELLCHECK)" ]; then \
if [ -n "$(SHELL_FILES)" ]; then shellcheck $(SHELL_FILES) && printf "shellcheck OK\n" || exit 1; fi; \
else \
printf "shellcheck not found, skipping (install: brew install shellcheck)\n"; \
fi
# `grep -c` exits 1 when it counts zero matches, so without the `|| true` this
# target would fail at exactly the moment the debt is cleared — the success
# state. The count still prints; only the exit status is suppressed.
docs-debt:
@cargo clippy --workspace --all-targets --quiet -- -W missing_docs 2>&1 \
| grep -c 'missing documentation' || true
# Regenerate the committed manifest schema. The temp file keeps a failed run
# from truncating schema.json; jsonschemagen's own test fails while it is stale.
schema:
cargo run --quiet -p jsonschemagen > jsonschemagen/schema.json.tmp \
|| { rm -f jsonschemagen/schema.json.tmp; exit 1; }
mv jsonschemagen/schema.json.tmp jsonschemagen/schema.json
build:
cargo build --release
build-linux:
cargo zigbuild --release --target x86_64-unknown-linux-gnu
# make treats an empty XDG_BIN_HOME as unset in $(or ...), so it falls back to HOME.
INSTALL_DIR ?= $(or $(XDG_BIN_HOME),$(HOME)/.local/bin)
install: build
mkdir -p "$(INSTALL_DIR)"
install -m 755 target/release/etch "$(INSTALL_DIR)/etch"
install-hooks:
cp scripts/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
cp scripts/pre-push .git/hooks/pre-push
chmod +x .git/hooks/pre-push
cp scripts/commit-msg .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg
mutants:
cd lib && cargo mutants --timeout 120 --no-shuffle
FUZZ_TIMEOUT ?= 60
# Resolve nightly cargo via rustup to support both rustup-managed and Homebrew-installed rustup
CARGO_NIGHTLY := $(shell PATH="$$PATH:/opt/homebrew/bin" rustup which --toolchain nightly cargo 2>/dev/null)
NIGHTLY_BIN := $(shell dirname $(CARGO_NIGHTLY) 2>/dev/null)
fuzz-manifest:
cd fuzz && PATH="$(NIGHTLY_BIN):$(HOME)/.cargo/bin:$(PATH)" $(CARGO_NIGHTLY) fuzz run fuzz_manifest corpus/fuzz_manifest -- -max_total_time=$(FUZZ_TIMEOUT)
fuzz-path:
cd fuzz && PATH="$(NIGHTLY_BIN):$(HOME)/.cargo/bin:$(PATH)" $(CARGO_NIGHTLY) fuzz run fuzz_path_resolve corpus/fuzz_path_resolve -- -max_total_time=$(FUZZ_TIMEOUT)
fuzz: fuzz-manifest fuzz-path
bench:
cargo bench -p etch-lib
semver:
cargo semver-checks check-release -p etch-lib --baseline-rev origin/main
# 10-80-10 cycle (ai-config ADR-0009/0010) — validate a plan file
validate-plan:
ifndef PLAN
@printf "error: PLAN is required, e.g. make validate-plan PLAN=docs/superpowers/plans/foo.md\n" >&2
@exit 2
endif
@python3 ~/.claude/scripts/validate-plan.py "$(PLAN)"