SHELL := /bin/bash
.SUFFIXES:
.DELETE_ON_ERROR:
.ONESHELL:
.PHONY: all build test test-fast test-quick test-full lint fmt clean doc book book-build book-serve book-test tier1 tier2 tier3 tier4 coverage coverage-fast profile hooks-install hooks-verify lint-scripts bashrs-score bashrs-lint-makefile chaos-test chaos-test-full chaos-test-lite fuzz bench dev pre-push ci check run-ci run-bench audit deps-validate deny pmat-score pmat-gates quality-report semantic-search examples mutants mutants-fast property-test
all: tier2
build:
cargo build --release
test-fast:
@echo "โก Running fast tests (target: <30s)..."
@if command -v cargo-nextest >/dev/null 2>&1; then \
time env PROPTEST_CASES=50 cargo nextest run --workspace --lib \
--status-level skip \
--failure-output immediate \
-E 'not test(/prop_gbm_expected_value_convergence/)'; \
else \
echo "๐ก Install cargo-nextest for faster tests: cargo install cargo-nextest"; \
time env PROPTEST_CASES=50 cargo test --workspace --lib -- --skip prop_gbm_expected_value_convergence; \
fi
@echo "โ
Fast tests passed"
test-quick: test-fast
test:
@echo "๐งช Running standard tests (target: <2min)..."
@if command -v cargo-nextest >/dev/null 2>&1; then \
time cargo nextest run --workspace \
--status-level skip \
--failure-output immediate; \
else \
time cargo test --workspace; \
fi
@echo "โ
Standard tests passed"
test-full:
@echo "๐ฌ Running full comprehensive tests..."
@if command -v cargo-nextest >/dev/null 2>&1; then \
time cargo nextest run --workspace --all-features; \
else \
time cargo test --workspace --all-features; \
fi
@echo "โ
Full tests passed"
lint:
cargo clippy -- -D warnings
fmt:
cargo fmt
fmt-check:
cargo fmt --check
clean:
cargo clean
doc:
cargo doc --no-deps --open
book: book-build
book-build:
@echo "๐ Building EXTREME TDD book..."
@if command -v mdbook >/dev/null 2>&1; then \
mdbook build book; \
echo "โ
Book built: book/book/index.html"; \
else \
echo "โ mdbook not found. Install with: cargo install mdbook"; \
exit 1; \
fi
book-serve:
@echo "๐ Serving book at http://localhost:3000..."
@mdbook serve book --open
book-test:
@echo "๐ Testing book synchronization..."
@for example in examples/*.rs; do \
if [ -f "$$example" ]; then \
EXAMPLE_NAME=$$(basename "$$example" .rs); \
CASE_STUDY=$$(echo "$$EXAMPLE_NAME" | sed 's/_/-/g'); \
if [ ! -f "book/src/examples/$$CASE_STUDY.md" ]; then \
echo "โ Missing case study for $$EXAMPLE_NAME"; \
exit 1; \
fi; \
fi; \
done
@echo "โ
All examples have corresponding book chapters"
tier1:
@echo "Running Tier 1: Fast feedback..."
@cargo fmt --check
@cargo clippy -- -W clippy::all
@cargo check
@echo "Tier 1: PASSED"
tier2:
@echo "Running Tier 2: Pre-commit checks..."
@cargo test --lib
@cargo clippy -- -D warnings
@echo "Tier 2: PASSED"
tier3:
@echo "Running Tier 3: Full validation..."
@cargo test --all
@cargo clippy -- -D warnings
@echo "Tier 3: PASSED"
tier4: tier3
@echo "Running Tier 4: CI/CD validation..."
@cargo test --release
@echo "Running pmat analysis..."
-pmat tdg . --include-components
-pmat rust-project-score
-pmat quality-gates --report
@echo "Tier 4: PASSED"
coverage:
@echo "๐ Running coverage analysis (target: <5 min)..."
@echo "๐ Checking for cargo-llvm-cov and cargo-nextest..."
@which cargo-llvm-cov > /dev/null 2>&1 || (echo "๐ฆ Installing cargo-llvm-cov..." && cargo install cargo-llvm-cov --locked)
@which cargo-nextest > /dev/null 2>&1 || (echo "๐ฆ Installing cargo-nextest..." && cargo install cargo-nextest --locked)
@echo "โ๏ธ Temporarily disabling global cargo config (sccache/mold break coverage)..."
@test -f ~/.cargo/config.toml && mv ~/.cargo/config.toml ~/.cargo/config.toml.cov-backup || true
@echo "๐งน Cleaning old coverage data..."
@cargo llvm-cov clean --workspace
@mkdir -p target/coverage
@echo "๐งช Phase 1: Running tests with instrumentation (no report)..."
@echo " Using PROPTEST_CASES=100 for faster coverage (bashrs pattern)"
@echo " Excluding slow property tests for faster coverage"
@env PROPTEST_CASES=100 cargo llvm-cov --no-report --ignore-filename-regex '(crates/|fuzz/|golden_traces/)' nextest --no-tests=warn --workspace --no-fail-fast --all-features \
-E 'not test(/prop_gbm_expected_value_convergence/)'
@echo "๐ Phase 2: Generating coverage reports..."
@cargo llvm-cov report --html --output-dir target/coverage/html
@cargo llvm-cov report --lcov --output-path target/coverage/lcov.info
@echo "โ๏ธ Restoring global cargo config..."
@test -f ~/.cargo/config.toml.cov-backup && mv ~/.cargo/config.toml.cov-backup ~/.cargo/config.toml || true
@echo ""
@echo "๐ Coverage Summary:"
@echo "=================="
@cargo llvm-cov report --summary-only
@echo ""
@echo "๐ก Reports:"
@echo "- HTML: target/coverage/html/index.html"
@echo "- LCOV: target/coverage/lcov.info"
@echo ""
coverage-fast: coverage
coverage-full:
@echo "๐ Running full coverage analysis (all features)..."
@which cargo-llvm-cov > /dev/null 2>&1 || cargo install cargo-llvm-cov --locked
@which cargo-nextest > /dev/null 2>&1 || cargo install cargo-nextest --locked
@cargo llvm-cov clean --workspace
@mkdir -p target/coverage
@test -f ~/.cargo/config.toml && mv ~/.cargo/config.toml ~/.cargo/config.toml.cov-backup || true
@cargo llvm-cov --no-report --ignore-filename-regex '(crates/|fuzz/|golden_traces/)' nextest --no-tests=warn --workspace --all-features
@cargo llvm-cov report --html --output-dir target/coverage/html
@cargo llvm-cov report --lcov --output-path target/coverage/lcov.info
@test -f ~/.cargo/config.toml.cov-backup && mv ~/.cargo/config.toml.cov-backup ~/.cargo/config.toml || true
@echo ""
@cargo llvm-cov report --summary-only
coverage-open:
@if [ -f target/coverage/html/index.html ]; then \
xdg-open target/coverage/html/index.html 2>/dev/null || \
open target/coverage/html/index.html 2>/dev/null || \
echo "Open: target/coverage/html/index.html"; \
else \
echo "โ Run 'make coverage' first"; \
fi
profile:
renacer --function-time --source -- cargo bench
bench:
cargo bench
chaos-test: build
@echo "๐ฅ Running chaos engineering tests..."
@if command -v renacer >/dev/null 2>&1; then \
./crates/aprender-shell/scripts/chaos-baseline.sh ci; \
else \
echo "โ ๏ธ renacer not found. Install with: cargo install --git https://github.com/paiml/renacer"; \
echo "๐ก Running lightweight chaos simulation instead..."; \
$(MAKE) chaos-test-lite; \
fi
@echo "โ
Chaos tests completed"
chaos-test-full: build
@echo "๐ฅ Running full chaos engineering tests..."
@./crates/aprender-shell/scripts/chaos-baseline.sh full
chaos-test-lite:
@echo "๐งช Running lightweight chaos simulation..."
@cargo test -p aprender-shell --test cli_integration -- chaos --nocapture 2>/dev/null || true
@echo "โ
Lite chaos tests completed"
fuzz:
@echo "๐ฒ Running fuzz tests (60s)..."
@cargo +nightly fuzz run fuzz_target_1 -- -max_total_time=60 || echo "โ ๏ธ Fuzz testing requires nightly Rust: rustup default nightly"
@echo "โ
Fuzz testing complete"
dev: tier1
pre-push: tier3
ci: tier4
check:
cargo check --all
audit:
@echo "๐ Running security audit..."
@cargo audit
@echo "โ
Security audit completed"
deps-validate:
@echo "๐ Validating dependencies..."
@cargo tree --duplicate | grep -v "^$$" || echo "โ
No duplicate dependencies"
@cargo audit || echo "โ ๏ธ Security issues found"
deny:
@echo "๐ Running cargo-deny checks..."
@if command -v cargo-deny >/dev/null 2>&1; then \
cargo deny check; \
else \
echo "โ cargo-deny not installed. Install with: cargo install cargo-deny"; \
exit 1; \
fi
@echo "โ
cargo-deny checks passed"
hooks-install:
@echo "๐ง Installing PMAT pre-commit hooks..."
@pmat hooks install || exit 1
@echo "โ
Hooks installed successfully"
hooks-verify:
@echo "๐ Verifying PMAT hooks..."
@pmat hooks verify
@pmat hooks run
lint-scripts:
@echo "๐ Linting shell scripts with bashrs..."
@if command -v bashrs >/dev/null 2>&1; then \
for script in scripts/*.sh; do \
echo " Linting $$script..."; \
bashrs lint "$$script" || exit 1; \
done; \
echo "โ
All shell scripts pass bashrs lint"; \
else \
echo "โ bashrs not installed. Install with: cargo install bashrs"; \
exit 1; \
fi
bashrs-score:
@echo "๐ Scoring shell scripts..."
@for script in scripts/*.sh; do \
echo ""; \
echo "Scoring $$script:"; \
bashrs score "$$script"; \
done
bashrs-lint-makefile:
@echo "๐ Linting Makefile with bashrs..."
@bashrs make lint Makefile || echo "โ ๏ธ Makefile linting found issues"
run-ci:
@./scripts/ci.sh
run-bench:
@./scripts/bench.sh
pmat-score:
@echo "๐ Calculating Rust project quality score..."
@pmat rust-project-score || echo "โ ๏ธ pmat not found. Install with: cargo install pmat"
@echo ""
pmat-gates:
@echo "๐ Running pmat quality gates..."
@pmat quality-gates --report || echo "โ ๏ธ pmat not found or gates failed"
@echo ""
quality-report:
@echo "๐ Generating comprehensive quality report..."
@mkdir -p docs/quality-reports
@echo "# Aprender Quality Report" > docs/quality-reports/latest.md
@echo "" >> docs/quality-reports/latest.md
@echo "Generated: $$(date)" >> docs/quality-reports/latest.md
@echo "" >> docs/quality-reports/latest.md
@echo "## Rust Project Score" >> docs/quality-reports/latest.md
@pmat rust-project-score >> docs/quality-reports/latest.md 2>&1 || echo "Error getting score" >> docs/quality-reports/latest.md
@echo "" >> docs/quality-reports/latest.md
@echo "## Quality Gates" >> docs/quality-reports/latest.md
@pmat quality-gates --report >> docs/quality-reports/latest.md 2>&1 || echo "Error running gates" >> docs/quality-reports/latest.md
@echo "" >> docs/quality-reports/latest.md
@echo "## TDG Score" >> docs/quality-reports/latest.md
@pmat tdg . --include-components >> docs/quality-reports/latest.md 2>&1 || echo "Error getting TDG" >> docs/quality-reports/latest.md
@echo "โ
Report generated: docs/quality-reports/latest.md"
semantic-search:
@echo "๐ Semantic code search..."
@echo "First run will build embeddings (may take a few minutes)..."
@pmat semantic || echo "โ ๏ธ pmat semantic search not available"
examples:
@echo "๐ฏ Running all examples..."
@failed=0; \
total=0; \
for example in examples/*.rs; do \
name=$$(basename "$$example" .rs); \
total=$$((total + 1)); \
echo " Running $$name..."; \
if cargo run --example "$$name" --quiet 2>/dev/null; then \
echo " โ
$$name passed"; \
else \
echo " โ $$name failed"; \
failed=$$((failed + 1)); \
fi; \
done; \
echo ""; \
echo "๐ Results: $$((total - failed))/$$total examples passed"; \
if [ $$failed -gt 0 ]; then exit 1; fi
@echo "โ
All examples passed"
examples-fast:
@echo "โก Running examples in release mode..."
@for example in examples/*.rs; do \
name=$$(basename "$$example" .rs); \
echo " Running $$name..."; \
cargo run --example "$$name" --release --quiet 2>/dev/null || echo " โ ๏ธ $$name failed"; \
done
@echo "โ
Examples complete"
examples-list:
@echo "๐ Available examples:"
@for example in examples/*.rs; do \
name=$$(basename "$$example" .rs); \
echo " - $$name"; \
done
@echo ""
@echo "Run with: cargo run --example <name>"
mutants:
@echo "๐งฌ Running mutation testing (full suite)..."
@echo "โ ๏ธ This may take 30-60 minutes for full coverage"
@which cargo-mutants > /dev/null 2>&1 || (echo "๐ฆ Installing cargo-mutants..." && cargo install cargo-mutants --locked)
@cargo mutants --no-times --timeout 300 -- --all-features
@echo "โ
Mutation testing complete"
mutants-fast:
@echo "โก Running mutation testing (fast sample)..."
@which cargo-mutants > /dev/null 2>&1 || (echo "๐ฆ Installing cargo-mutants..." && cargo install cargo-mutants --locked)
@cargo mutants --no-times --timeout 120 --shard 1/10 -- --lib
@echo "โ
Mutation sample complete"
mutants-file: ## Run mutation testing on specific file (usage: make mutants-file FILE=src/metrics/mod.rs)
@echo "๐งฌ Running mutation testing on $(FILE)..."
@if [ -z "$(FILE)" ]; then \
echo "โ Usage: make mutants-file FILE=src/path/to/file.rs"; \
exit 1; \
fi
@which cargo-mutants > /dev/null 2>&1 || cargo install cargo-mutants --locked
@cargo mutants --no-times --timeout 120 --file "$(FILE)" -- --all-features
@echo "โ
Mutation testing on $(FILE) complete"
mutants-list:
@echo "๐ Listing potential mutants..."
@cargo mutants --list 2>/dev/null | head -100
@echo "..."
@echo "(showing first 100 mutants)"
property-test:
@echo "๐ฒ Running property-based tests..."
@if command -v cargo-nextest >/dev/null 2>&1; then \
PROPTEST_CASES=1000 cargo nextest run --test property_tests --no-fail-fast; \
else \
PROPTEST_CASES=1000 cargo test --test property_tests; \
fi
@echo "โ
Property tests passed"
property-test-fast:
@echo "โก Running property tests (fast mode)..."
@if command -v cargo-nextest >/dev/null 2>&1; then \
cargo nextest run --test property_tests; \
else \
cargo test --test property_tests; \
fi
@echo "โ
Property tests passed"
property-test-extensive:
@echo "๐ฌ Running extensive property tests (10K cases per test)..."
@PROPTEST_CASES=10000 cargo test --test property_tests -- --test-threads=1
@echo "โ
Extensive property tests complete"