CI 就是把本地的检查命令放到一个每次提交都会跑的地方。这篇写了一个完整的 ci.yml,然后诚实地区分:哪些是真正验证过的(语法检查、命令本身、门禁行为),哪些只能在 GitHub 上运行才知道(这篇没有做)。
1 | name: ci
2 | on:
3 | push:
4 | branches: [main]
5 | pull_request:
6 | env:
7 | CARGO_TERM_COLOR: always
8 | jobs:
9 | fmt:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4
13 | - run: cargo fmt --all -- --check
14 | clippy:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | - run: cargo clippy --locked --all-targets -- -D warnings
19 | test:
20 | runs-on: ${{ matrix.os }}
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | os: [ubuntu-latest, macos-latest]
25 | toolchain: [stable, beta]
26 | steps:
27 | - uses: actions/checkout@v4
28 | - uses: dtolnay/rust-toolchain@master
29 | with:
30 | toolchain: ${{ matrix.toolchain }}
31 | - uses: actions/cache@v4
32 | with:
33 | path: |
34 | ~/.cargo/registry
35 | target
36 | key: ${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
37 | - run: cargo build --locked
38 | - run: cargo test --locked
39 | audit:
40 | runs-on: ubuntu-latest
41 | needs: [fmt, clippy, test]
42 | steps:
43 | - uses: actions/checkout@v4
44 | - run: cargo install cargo-audit --locked
45 | - run: cargo audit本篇串起前面几篇的检查:rustfmt 格式化、Clippy 静态检查、单元测试与集成测试、依赖安全审计、Cargo.lock。
actionlint ci.yml:退出码 0;输出:(无)
needs 写错 job 名:退出码 1
rsdata/u170_bad.yml:39:3: job "audit" needs job "tset" which does not exist in this workflow [job-needs]
|
39 | audit:
| ^~~~~~
matrix 属性写错:退出码 1
rsdata/u170_bad.yml:36:37: property "toolchian" is not defined in object type {os: string; toolchain: string} [expression]
|
36 | key: ${{ runner.os }}-${{ matrix.toolchian }}-${{ hashFiles('**/Cargo.lock') }}
| ^~~~~~~~~~~~~~~~
缺少 runs-on:退出码 1
rsdata/u170_bad.yml:9:3: "runs-on" section is missing in job "fmt" [syntax-check]
|
9 | fmt:
| ^~~~ 触发条件: {'push': {'branches': ['main']}, 'pull_request': None}
test 矩阵:os × toolchain = 2 × 2 = 4 个 job: ubuntu-latest/stable, ubuntu-latest/beta, macos-latest/stable, macos-latest/beta
整个工作流一次触发的 job 数:fmt 1 + clippy 1 + test 4 + audit 1 = 7;audit 声明 needs = ['fmt', 'clippy', 'test'](要等前面的 job 成功);test 里 fail-fast = False
每个 job 的 run 步骤:
fmt: ['cargo fmt --all -- --check']
clippy: ['cargo clippy --locked --all-targets -- -D warnings']
test: ['cargo build --locked', 'cargo test --locked']
audit: ['cargo install cargo-audit --locked', 'cargo audit'] job 结果 耗时(秒) 执行的命令
fmt 通过 0.1 cargo fmt --all -- --check
clippy 通过 1.6 cargo clippy --locked --all-targets -- -D warnings
test 通过 0.6 cargo build --locked; cargo test --locked
audit 通过 2.3 cargo audit
cargo test 的结果行:
test tests::adds ... ok
test tests::renders ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
缺陷 fmt clippy test audit
代码没格式化 失败 通过 通过 通过
clippy 警告(needless_return) 通过 失败 通过 通过
测试断言错误 通过 通过 失败 通过
依赖有已知漏洞(固定 smallvec 1.6.0) 通过 通过 通过 失败
各缺陷下失败 job 的第一条错误信息:
[代码没格式化] fmt:退出码 1;cargo fmt --all -- --check
Diff in <实验目录>/proj/u170/src/lib.rs:1:
-pub fn add(a:i32,b:i32)->i32{a+b}
+pub fn add(a: i32, b: i32) -> i32 {
[clippy 警告(needless_return)] clippy:退出码 101;cargo clippy --locked --all-targets -- -D warnings
Checking ci_demo v0.1.0 (<实验目录>/proj/u170)
error: unneeded `return` statement
--> src/lib.rs:2:5
[测试断言错误] test:退出码 101;cargo test --locked
running 2 tests
test tests::renders ... ok
test tests::adds ... FAILED
[依赖有已知漏洞(固定 smallvec 1.6.0)] audit:退出码 1;cargo audit
Crate: smallvec
Version: 1.6.0
Title: Buffer overflow in SmallVec::insert_many cargo build --locked:退出码 101
Updating crates.io index
error: cannot update the lock file <实验目录>/proj/u170/Cargo.lock because --locked was passed to prevent this
help: to generate the lock file without accessing the network, remove the --locked flag and use --offline instead.
不加 --locked 的 cargo build:退出码 0;Cargo.lock 被悄悄改写,新增的包:['tinyvec']冷缓存:2.6, 2.7, 2.6 秒(中位数 2.6);恢复缓存后没改动:0.18, 0.17, 0.18 秒;恢复缓存后改了 lib.rs:0.51, 0.51, 0.48 秒 缓存键(Cargo.lock 的 sha256 前 12 位):初始 beb799212c5f;改源码后 beb799212c5f(不变);新增依赖并重新生成锁文件后 e27d64fcd622(变化,缓存失效)