-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathMakefile
More file actions
271 lines (232 loc) · 10.4 KB
/
Copy pathMakefile
File metadata and controls
271 lines (232 loc) · 10.4 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# Praxis Policy Engine — Rust workspace Makefile
# =============================================================================
# Targets mirror CI (.github/workflows/) so a green `make ci` locally means a
# green pipeline.
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c
CARGO ?= cargo
# rustfmt runs on nightly to match the rest of the org and the tree's committed
# formatting (see the `style: apply nightly rustfmt formatting` commit). Stable
# rustfmt would reformat it. Override to pin a specific nightly.
NIGHTLY ?= nightly
# `make release LEVEL=patch` or `make release VERSION=0.1.1`. VERSION wins.
RELEASE_ARG = $(if $(VERSION),$(VERSION),$(if $(LEVEL),$(LEVEL),patch))
# =============================================================================
# Help
# =============================================================================
.PHONY: help
help:
@echo "Praxis Policy Engine — Makefile"
@echo ""
@echo "Build:"
@echo " build Build the workspace (debug)"
@echo " build-release Build the workspace (release)"
@echo " check cargo check the workspace"
@echo " clean Remove the target/ directory"
@echo ""
@echo "Lint & format:"
@echo " fmt Format Rust code (nightly rustfmt)"
@echo " lint CI lint gate: fmt --check + clippy -D warnings"
@echo " lint-extra Extra lint checks: typos + taplo fmt --check"
@echo " clippy Run clippy on the workspace (-D warnings)"
@echo " lint-fix Auto-fix: cargo fmt + clippy --fix"
@echo " machete Report unused dependencies (advisory)"
@echo ""
@echo "Test:"
@echo " test Run all workspace tests"
@echo ""
@echo "Supply chain & coverage:"
@echo " audit cargo deny check (advisories, licenses, bans, sources)"
@echo " coverage Coverage summary, gated at COVERAGE_FLOOR percent"
@echo " mutants Run mutation testing (cargo-mutants)"
@echo " semver Check semver compatibility (cargo-semver-checks)"
@echo ""
@echo "Docs:"
@echo " doc cargo doc with warnings denied"
@echo ""
@echo "Setup:"
@echo " setup-hooks Install git pre-commit hook"
@echo ""
@echo "CI:"
@echo " ci What CI runs: lint + test"
@echo ""
@echo "Release:"
@echo " release-dry Preview a release (no changes)"
@echo " release-version Rewrite versions only; no commit, no tag"
@echo " release Bump + commit + tag, then stop"
@echo " publish-dry Package every publishable crate without uploading"
@echo " tag Tag VERSION and push it to trigger the CI publish"
# =============================================================================
# Build
# =============================================================================
.PHONY: build
build:
@$(CARGO) build --workspace
.PHONY: build-release
build-release:
@$(CARGO) build --release --workspace
# The inner loop. Covers test and example code as well as the libraries, and
# both feature sets, because most compile errors while editing live in tests.
#
# Prefer this over `make test` while iterating. `cargo check` never links an
# executable, and on macOS with an Endpoint Security agent installed, linking and
# first-running a test binary is what costs the wall clock, not compiling it. See
# AGENTS.md, Conventions -> Tests.
.PHONY: check
check:
@$(CARGO) check --workspace --all-targets
@$(CARGO) check --workspace --all-targets --all-features
.PHONY: clean
clean:
@$(CARGO) clean
# =============================================================================
# Lint & format
# =============================================================================
.PHONY: fmt
fmt:
@$(CARGO) +$(NIGHTLY) fmt --all
.PHONY: clippy
clippy:
@$(CARGO) clippy --workspace --all-targets -- -D warnings
# CI-safe gate: read-only fmt check plus clippy. Lint levels come from
# [workspace.lints] in Cargo.toml.
.PHONY: lint
lint:
@echo "fmt --check + clippy -D warnings ..."
@$(CARGO) +$(NIGHTLY) fmt --all -- --check
@$(CARGO) clippy --workspace --all-targets -- -D warnings
@echo "lint passed"
.PHONY: lint-fix
lint-fix:
@$(CARGO) +$(NIGHTLY) fmt --all
@$(CARGO) clippy --workspace --all-targets --fix --allow-dirty --allow-staged -- -D warnings
# Advisory, not part of the blocking gate: machete is wrong in both directions. It
# reports macro- and derive-only crates as unused, and it misses a genuinely
# unused dependency whose name appears in a comment.
# Extra lint checks: spell checker and TOML formatting. Not part of the
# blocking CI gate; run manually or by lint-extra CI.
.PHONY: lint-extra
lint-extra:
@command -v typos >/dev/null 2>&1 || $(CARGO) install typos-cli --locked
@typos
@command -v taplo >/dev/null 2>&1 || $(CARGO) install taplo-cli --locked
@taplo fmt --check
@echo "lint-extra passed"
.PHONY: machete
machete:
@command -v cargo-machete >/dev/null 2>&1 || $(CARGO) install cargo-machete --locked
@cargo machete || true
# =============================================================================
# Setup
# =============================================================================
.PHONY: setup-hooks
setup-hooks:
@git config core.hooksPath .hooks
@echo "pre-commit hook installed"
# =============================================================================
# Test
# =============================================================================
# Two passes. The first is what a host gets naming no features. The second is the
# only way to reach `#[cfg(feature = ...)]` test modules, and the facade's tests
# are gated that way because its `default` is empty: the bare dependency is the
# engine alone. Dropping either pass hides tests without failing.
.PHONY: test
test:
@$(CARGO) test --workspace
@$(CARGO) test --workspace --all-features
# =============================================================================
# Supply chain & coverage
# =============================================================================
# `cargo deny check` covers advisories against the same RustSec database that
# cargo-audit reads, and honors the reviewed exceptions in deny.toml. cargo-audit
# reads audit.toml instead, so running both meant a second ignore list that had
# to agree with the first, and without one it re-reported every accepted
# dev-only advisory.
.PHONY: audit
audit:
@command -v cargo-deny >/dev/null 2>&1 || $(CARGO) install cargo-deny --locked
@cargo deny check
# Minimum line coverage. Raise it, never lower it: a drop means coverage
# regressed. There is no headroom above the floor, so if a platform difference of
# a few lines turns the gate red, cover something rather than lowering it.
#
# 100 percent is not the goal. Some production lines are unreachable defensive
# guards, marked as such where they appear, and cargo-llvm-cov cannot exclude
# lines on stable.
#
# The coverage workflow calls this target rather than repeating the threshold, so
# this is the only copy of the number.
COVERAGE_FLOOR ?= 95
# `--all-features` reaches the test targets behind `test-util`, without which the
# compiler's test scaffolding and everything it covers fall outside the floor.
#
# `--include-ignored` reaches the Valkey integration tests, much of which needs no
# Valkey at all. `VALKEY_TESTS_OPTIONAL=1` lets them skip instead of fail, because
# this target measures and `make test` is what asserts. Set `VALKEY_TEST_URL` to
# measure the paths that do need a server.
.PHONY: coverage
coverage:
@command -v cargo-llvm-cov >/dev/null 2>&1 || $(CARGO) install cargo-llvm-cov --locked
@VALKEY_TESTS_OPTIONAL=1 cargo llvm-cov --workspace --all-features --summary-only \
--fail-under-lines $(COVERAGE_FLOOR) -- --include-ignored
# Mutation testing. Advisory, not part of the blocking CI gate.
.PHONY: mutants
mutants:
@command -v cargo-mutants >/dev/null 2>&1 || $(CARGO) install cargo-mutants --locked
@cargo mutants --workspace
# Semver compatibility check against the last published version.
.PHONY: semver
semver:
@command -v cargo-semver-checks >/dev/null 2>&1 || $(CARGO) install cargo-semver-checks --locked
@cargo semver-checks
# =============================================================================
# Docs
# =============================================================================
.PHONY: doc
doc:
@RUSTDOCFLAGS="-D warnings" $(CARGO) doc --workspace --no-deps
# =============================================================================
# CI
# =============================================================================
.PHONY: ci
ci: lint test
# =============================================================================
# Release
# =============================================================================
#
# CI publishes on tag push. The local mechanics stop at the tag.
.PHONY: release-tool
release-tool:
@command -v cargo-release >/dev/null 2>&1 || $(CARGO) install cargo-release --locked
# Preview only. cargo-release makes no changes without --execute.
.PHONY: release-dry
release-dry: release-tool
@$(CARGO) release $(RELEASE_ARG) --workspace
# Rewrite the version in [workspace.package] and [workspace.dependencies] only;
# no commit, no tag. For a manual, reviewed bump.
.PHONY: release-version
release-version: release-tool
@$(CARGO) release version $(RELEASE_ARG) --workspace --execute --no-confirm
# Bump, commit, tag, then stop. --no-publish and --no-push enforce the
# "CI publishes on tag push" model at the CLI level as well, so the guarantee
# does not depend on release.toml being parsed as expected. Afterwards run
# `make tag` or push the tag directly.
.PHONY: release
release: release-tool
@$(CARGO) release $(RELEASE_ARG) --workspace --no-publish --no-push --execute
# Build and verify a .crate for every publishable member without uploading, the
# same check the release workflow's dry run performs. CI runs this on a clean
# checkout; --allow-dirty lets it run locally with work in progress.
.PHONY: publish-dry
publish-dry:
@$(CARGO) package --workspace --locked --allow-dirty
# Tag the current commit and push it. The tag is what the release workflow
# triggers on. VERSION must be semver with no leading `v`.
# make tag VERSION=0.1.0
.PHONY: tag
tag:
@test -n "$(VERSION)" || { echo "usage: make tag VERSION=X.Y.Z[-prerelease]"; exit 1; }
@echo "$(VERSION)" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$$' \
|| { echo "error: VERSION '$(VERSION)' is not semver (e.g. 0.1.0; no leading 'v')"; exit 1; }
git tag v$(VERSION)
git push origin v$(VERSION)