Skip to content

Commit 69eb028

Browse files
committed
ci: restructure CI pipeline with change detection and sccache
- add detect-changes job to skip full CI on docs-only pushes - replace OS matrix with single ubuntu-latest runner - add sccache for faster compilation in test and coverage jobs - fix fmt job to use dtolnay/rust-toolchain nightly instead of rustup command - align all commands with CLAUDE.md: add --workspace flag to clippy and nextest - add concurrency group to cancel superseded runs - restrict coverage to main branch pushes only - add msrv job pinned to rust-version 1.88 from Cargo.toml - improve ci-gate to list all jobs explicitly
1 parent 4e3621f commit 69eb028

1 file changed

Lines changed: 156 additions & 59 deletions

File tree

.github/workflows/ci.yml

Lines changed: 156 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,109 +4,192 @@ on:
44
push:
55
branches: [main]
66
pull_request:
7-
branches: [main]
7+
8+
permissions: {}
89

910
env:
1011
CARGO_TERM_COLOR: always
11-
RUST_BACKTRACE: 1
12+
RUSTFLAGS: "-D warnings"
1213

13-
permissions: {}
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
1417

1518
jobs:
16-
check:
17-
name: Check
19+
detect-changes:
20+
name: Detect Changes
1821
runs-on: ubuntu-latest
19-
permissions:
20-
contents: read
22+
timeout-minutes: 2
23+
outputs:
24+
run-full-ci: ${{ steps.classify.outputs.run-full-ci }}
2125
steps:
22-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
23-
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # dtolnay/rust-toolchain stable
24-
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # Swatinem/rust-cache v2
25-
- run: cargo check --all-targets --all-features
26+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
27+
- name: Filter changed paths
28+
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
29+
id: filter
30+
with:
31+
filters: |
32+
code:
33+
- 'crates/**'
34+
- 'Cargo.toml'
35+
- 'Cargo.lock'
36+
workflows:
37+
- '.github/workflows/**'
38+
- '.cargo/**'
39+
- name: Classify changes
40+
id: classify
41+
run: |
42+
CODE="${{ steps.filter.outputs.code }}"
43+
WORKFLOWS="${{ steps.filter.outputs.workflows }}"
44+
45+
if [[ "$CODE" == "true" || "$WORKFLOWS" == "true" ]]; then
46+
echo "run-full-ci=true" >> "$GITHUB_OUTPUT"
47+
else
48+
echo "run-full-ci=false" >> "$GITHUB_OUTPUT"
49+
fi
2650
2751
fmt:
28-
name: Format
52+
name: Lint (fmt)
53+
needs: detect-changes
54+
if: needs.detect-changes.outputs.run-full-ci == 'true'
2955
runs-on: ubuntu-latest
56+
timeout-minutes: 5
3057
permissions:
3158
contents: read
3259
steps:
33-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
34-
- run: rustup toolchain install nightly --component rustfmt --allow-downgrade
35-
- run: cargo +nightly fmt --all -- --check
60+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
61+
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
62+
with:
63+
toolchain: nightly
64+
components: rustfmt
65+
- name: Check formatting
66+
run: cargo +nightly fmt --all -- --check
3667

3768
clippy:
38-
name: Clippy
69+
name: Lint (clippy)
70+
needs: detect-changes
71+
if: needs.detect-changes.outputs.run-full-ci == 'true'
3972
runs-on: ubuntu-latest
73+
timeout-minutes: 10
4074
permissions:
4175
contents: read
4276
steps:
43-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
44-
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # dtolnay/rust-toolchain stable
77+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
78+
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
4579
with:
80+
toolchain: stable
4681
components: clippy
47-
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # Swatinem/rust-cache v2
48-
- run: cargo clippy --all-targets --all-features -- -D warnings
82+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
83+
with:
84+
shared-key: "ci"
85+
- name: Clippy
86+
run: cargo clippy --all-targets --all-features --workspace -- -D warnings
4987

5088
test:
5189
name: Test
52-
runs-on: ${{ matrix.os }}
90+
needs: [detect-changes, fmt, clippy]
91+
if: needs.detect-changes.outputs.run-full-ci == 'true'
92+
runs-on: ubuntu-latest
93+
timeout-minutes: 20
5394
permissions:
5495
contents: read
55-
strategy:
56-
fail-fast: false
57-
matrix:
58-
os: [ubuntu-latest, macos-latest, windows-latest]
59-
rust: [stable]
60-
include:
61-
- os: ubuntu-latest
62-
rust: beta
63-
- os: ubuntu-latest
64-
rust: "1.88" # MSRV
96+
env:
97+
RUSTC_WRAPPER: sccache
98+
SCCACHE_GHA_ENABLED: "true"
6599
steps:
66-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
67-
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # dtolnay/rust-toolchain master
100+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
101+
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
68102
with:
69-
toolchain: ${{ matrix.rust }}
70-
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # Swatinem/rust-cache v2
71-
- uses: taiki-e/install-action@dee540ee3f3ff5c6a0665fed9996875d0ba04ca2 # taiki-e/install-action nextest
72-
- run: cargo nextest run --all-features
103+
toolchain: stable
104+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
105+
with:
106+
cache-targets: "false"
107+
shared-key: "ci"
108+
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
109+
- uses: taiki-e/install-action@dee540ee3f3ff5c6a0665fed9996875d0ba04ca2 # nextest
110+
- name: Run tests
111+
run: cargo nextest run --workspace --all-features --lib --bins
112+
113+
msrv:
114+
name: MSRV check (1.88)
115+
needs: detect-changes
116+
if: needs.detect-changes.outputs.run-full-ci == 'true'
117+
runs-on: ubuntu-latest
118+
timeout-minutes: 15
119+
permissions:
120+
contents: read
121+
steps:
122+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
123+
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
124+
with:
125+
toolchain: "1.88"
126+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
127+
with:
128+
shared-key: "msrv"
129+
- name: cargo check (MSRV)
130+
run: cargo check --workspace --all-targets --all-features --locked
73131

74132
docs:
75-
name: Documentation
133+
name: Rustdoc
134+
needs: detect-changes
135+
if: needs.detect-changes.outputs.run-full-ci == 'true'
76136
runs-on: ubuntu-latest
137+
timeout-minutes: 10
77138
permissions:
78139
contents: read
140+
env:
141+
RUSTDOCFLAGS: "-D warnings"
79142
steps:
80-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
81-
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # dtolnay/rust-toolchain stable
82-
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # Swatinem/rust-cache v2
83-
- run: cargo doc --no-deps --all-features
84-
env:
85-
RUSTDOCFLAGS: -D warnings
143+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
144+
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
145+
with:
146+
toolchain: stable
147+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
148+
with:
149+
shared-key: "ci"
150+
- name: Build docs
151+
run: cargo doc --no-deps --all-features
86152

87153
security:
88154
name: Security Audit
89155
runs-on: ubuntu-latest
156+
timeout-minutes: 5
90157
permissions:
91158
contents: read
92159
steps:
93-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
94-
- uses: EmbarkStudios/cargo-deny-action@91bf2b620e09e18d6eb78b92e7861937469acedb # EmbarkStudios/cargo-deny-action v2
160+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
161+
- uses: EmbarkStudios/cargo-deny-action@91bf2b620e09e18d6eb78b92e7861937469acedb # v2
95162

96163
coverage:
97164
name: Coverage
165+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.detect-changes.outputs.run-full-ci == 'true'
166+
needs: [detect-changes, fmt, clippy]
98167
runs-on: ubuntu-latest
168+
timeout-minutes: 20
99169
permissions:
100170
contents: read
171+
# RUSTFLAGS reset: -C instrument-coverage conflicts with -D warnings from the
172+
# global env; linting is enforced by the dedicated clippy job.
173+
env:
174+
RUSTC_WRAPPER: sccache
175+
SCCACHE_GHA_ENABLED: "true"
176+
RUSTFLAGS: ""
101177
steps:
102-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # actions/checkout v6
103-
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # dtolnay/rust-toolchain stable
178+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
179+
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
180+
with:
181+
toolchain: stable
182+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
104183
with:
105-
components: llvm-tools-preview
106-
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # Swatinem/rust-cache v2
107-
- uses: taiki-e/install-action@caf4aedf2bfe5bfb679703b29290921f4711b2f3 # taiki-e/install-action cargo-llvm-cov
108-
- run: cargo llvm-cov --all-features --lcov --output-path lcov.info
109-
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # codecov/codecov-action v6
184+
cache-targets: "false"
185+
shared-key: "coverage"
186+
- uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
187+
- uses: taiki-e/install-action@caf4aedf2bfe5bfb679703b29290921f4711b2f3 # cargo-llvm-cov
188+
- uses: taiki-e/install-action@dee540ee3f3ff5c6a0665fed9996875d0ba04ca2 # nextest
189+
- name: Generate coverage
190+
run: cargo llvm-cov nextest --workspace --all-features --lib --bins --lcov --output-path lcov.info
191+
- name: Upload coverage
192+
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6
110193
with:
111194
token: ${{ secrets.CODECOV_TOKEN }}
112195
files: lcov.info
@@ -115,11 +198,25 @@ jobs:
115198
ci-gate:
116199
name: CI Gate
117200
if: always()
118-
needs: [check, fmt, clippy, test, docs, security, coverage]
201+
needs: [fmt, clippy, test, msrv, docs, security, coverage]
119202
runs-on: ubuntu-latest
203+
timeout-minutes: 1
120204
steps:
121-
- run: |
122-
if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
123-
echo "::error::One or more CI jobs failed or were cancelled"
124-
exit 1
125-
fi
205+
- name: Check all jobs
206+
run: |
207+
results=(
208+
"${{ needs.fmt.result }}"
209+
"${{ needs.clippy.result }}"
210+
"${{ needs.test.result }}"
211+
"${{ needs.msrv.result }}"
212+
"${{ needs.docs.result }}"
213+
"${{ needs.security.result }}"
214+
"${{ needs.coverage.result }}"
215+
)
216+
for r in "${results[@]}"; do
217+
if [[ "$r" != "success" && "$r" != "skipped" ]]; then
218+
echo "::error::One or more CI jobs failed or were cancelled"
219+
exit 1
220+
fi
221+
done
222+
echo "All jobs passed"

0 commit comments

Comments
 (0)