55# 1. cargo fmt --check -> consistent formatting
66# 2. cargo clippy (deny) -> zero lint warnings (all+pedantic+nursery)
77# 3. cargo test --locked -> all tests pass, Cargo.lock respected
8- # 4. cargo build -> library compiles
9- # 5. cargo doc -> documentation + doc-comment format valid
10- # 6. cargo deny check -> no vulnerable/banned dependencies
8+ # 4. cargo bench --no-run -> benchmarks compile without errors
9+ # 5. cargo build -> library compiles
10+ # 6. cargo doc -> documentation + doc-comment format valid
11+ # 7. cargo deny check -> no vulnerable/banned dependencies
12+ #
13+ # Linux benchmark execution:
14+ # - gungraun instruction-count regressions vs PR merge-base
1115
1216name : CI
1317
@@ -64,15 +68,21 @@ jobs:
6468
6569 # Gate 3: Tests - rejects broken logic; --locked ensures Cargo.lock is honoured
6670 - name : " Gate 3: cargo test"
67- run : cargo test --locked --all-targets
71+ run : |
72+ cargo test --locked --lib --tests
73+ cargo test --locked --doc
74+
75+ # Gate 4: Benchmarks - rejects benchmarks that do not compile
76+ - name : " Gate 4: cargo bench --no-run"
77+ run : cargo bench --locked --no-run
6878
69- # Gate 4 : Build - rejects code that does not compile
70- - name : " Gate 4 : cargo build"
79+ # Gate 5 : Build - rejects code that does not compile
80+ - name : " Gate 5 : cargo build"
7181 run : cargo build --locked
7282
73- # Gate 5 : Documentation & doc-comment format - rejects broken links, bare URLs,
83+ # Gate 6 : Documentation & doc-comment format - rejects broken links, bare URLs,
7484 # invalid code blocks, and missing crate-level docs.
75- - name : " Gate 5 : cargo doc"
85+ - name : " Gate 6 : cargo doc"
7686 run : cargo doc --locked --no-deps
7787 env :
7888 RUSTDOCFLAGS : >-
8292 -D rustdoc::private_intra_doc_links
8393 -D rustdoc::unescaped_backticks
8494
85- # Gate 6: Dependency audit - rejects vulnerable/banned/unlicensed dependencies.
95+ # Linux-only instruction-count benchmarks with gungraun.
96+ #
97+ # Gungraun executes under valgrind, so benchmark execution is unavailable on
98+ # Windows runners. Pull requests compare the PR head against a merge-base
99+ # baseline from `main` and fail on instruction regressions above the chosen
100+ # Ir limit. Pushes to `main` still run the benchmark suite as a smoke check.
101+ benchmark-regression :
102+ name : Benchmark Regression (Linux)
103+ runs-on : ubuntu-latest
104+ timeout-minutes : 30
105+ env :
106+ GUNGRAUN_SEPARATE_TARGETS : " true"
107+ steps :
108+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
109+ with :
110+ fetch-depth : 0
111+
112+ - name : Install Rust toolchain
113+ uses : dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # 1.94.1
114+ with :
115+ toolchain : stable
116+
117+ - name : Cache Rust dependencies and build artifacts
118+ uses : Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
119+ with :
120+ cache-on-failure : true
121+ key : bench
122+
123+ - name : Install Valgrind
124+ run : |
125+ sudo apt-get update
126+ sudo apt-get install -y valgrind
127+
128+ - name : Install gungraun-runner
129+ run : |
130+ version=$(cargo metadata --format-version=1 --no-deps | python -c "import json, sys; data = json.load(sys.stdin); print(next(pkg['version'] for pkg in data['packages'] if pkg['name'] == 'gungraun'))")
131+ cargo install --locked gungraun-runner --version "$version"
132+
133+ - name : Resolve merge-base
134+ id : base
135+ if : github.event_name == 'pull_request'
136+ run : |
137+ base=$(git merge-base HEAD origin/${{ github.base_ref }})
138+ echo "sha=$base" >> "$GITHUB_OUTPUT"
139+ echo "Merge-base: $base"
140+
141+ - name : Run benchmarks on merge-base (establish baseline)
142+ if : github.event_name == 'pull_request'
143+ run : |
144+ head_sha=$(git rev-parse HEAD)
145+ git checkout --detach ${{ steps.base.outputs.sha }}
146+ cargo bench --locked --bench benchmarks -- \
147+ --save-baseline main \
148+ --callgrind-metrics=ir \
149+ --save-summary=json
150+ git checkout --detach "$head_sha"
151+
152+ - name : Run PR benchmark comparison
153+ if : github.event_name == 'pull_request'
154+ run : |
155+ cargo bench --locked --bench benchmarks -- \
156+ --baseline main \
157+ --callgrind-metrics=ir \
158+ --callgrind-limits='ir=1.0%' \
159+ --save-summary=json \
160+ | tee bench_output.txt
161+
162+ - name : Run benchmark smoke check on main pushes
163+ if : github.event_name != 'pull_request'
164+ run : |
165+ cargo bench --locked --bench benchmarks \
166+ -- \
167+ --callgrind-metrics=ir \
168+ --save-summary=json \
169+ | tee bench_output.txt
170+
171+ - name : Upload benchmark reports
172+ if : always()
173+ uses : actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
174+ with :
175+ name : benchmark-reports-${{ github.sha }}
176+ path : |
177+ bench_output.txt
178+ target/gungraun
179+ retention-days : 7
180+ if-no-files-found : warn
181+
182+ # Gate 7: Dependency audit - rejects vulnerable/banned/unlicensed dependencies.
86183 # Uses EmbarkStudios/cargo-deny-action (Docker-based, pre-built binary - no
87184 # manual install or caching needed). Advisories are split into a separate
88185 # matrix entry with continue-on-error so a sudden new advisory announcement
@@ -101,7 +198,7 @@ jobs:
101198 steps :
102199 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
103200
104- - name : " Gate 6 : cargo deny check ${{ matrix.checks }}"
201+ - name : " Gate 7 : cargo deny check ${{ matrix.checks }}"
105202 uses : EmbarkStudios/cargo-deny-action@82eb9f621fbc699dd0918f3ea06864c14cc84246 # v2
106203 with :
107204 command : check ${{ matrix.checks }}
0 commit comments