YannickLeRoux/cargo-aged

GitHub: YannickLeRoux/cargo-aged

cargo-aged 是一个 Cargo 子命令,仅在依赖的最新稳定版发布超过可配置的时长后才执行更新,帮助团队规避过早引入未经生态验证的新版本。

Stars: 1 | Forks: 0

# cargo-aged 一个 Cargo 子命令,它**仅在依赖项的最新稳定版发布时间超过可配置的阈值后**才更新依赖。这对于希望避免在生态系统有机会解决错误、供应链问题或版本撤回(yank)之前引入最新发布的 crate 版本的团队非常有用。 对于你的 `Cargo.toml` 中的每个依赖项,`cargo-aged` 会查询 crates.io API 以获取最新的非预发布、非撤回(non-yanked)版本。如果该版本在至少 *N* 天前发布,它会运行 `cargo update -p --precise ` 将你的 `Cargo.lock` 锁定到该版本。 ## 安装 从源码(从本仓库)安装: ``` cargo install --path . ``` 或者直接从 git checkout 安装: ``` cargo install --git https://github.com/YannickLeRoux/cargo-aged.git ``` 安装完成后,`cargo-aged` 二进制文件会存放在 `~/.cargo/bin/` 中,Cargo 会将其识别为 `cargo aged` 子命令。 ## 用法 在任何 Cargo 项目中运行: ``` cargo aged # default: 30-day minimum age cargo aged --min-age 14 # more aggressive cargo aged --min-age 90 --dry-run ``` ### CI 用法 在 CI 中使用 `--check` 作为只读门禁,当 `Cargo.lock` 偏离到比配置阈值更年轻的版本时,导致构建失败: ``` cargo aged --check # inherits min-age from .cargo/config.toml cargo aged --check --min-age 14 # or set it inline ``` **退出代码:** | 代码 | 含义 | | --- | --- | | `0` | 每个直接的 registry 依赖都已经锁定到符合年龄要求的版本,或者因为正当理由被跳过(path/git 依赖、`=` 锁定、没有稳定版发布、不存在符合年龄要求的版本,或者 crates.io 查询失败)。 | | `1` | 至少有一个直接的 registry 依赖锁定到了比 `min-age` 更年轻的版本,**并且** crates.io 上存在更旧的、符合年龄要求的版本——即运行 `cargo aged`(不带 `--check`)会将某些依赖回退。任何其他错误(缺少阈值、清单错误、HTTP 失败)也会使用退出代码 `1`。 | `--check` 与 `--dry-run` 和 `--iterate` 互斥:它们都是非修改性的,但只有 `--check` 会设置状态码。 ## 配置 `min-publish-age` `cargo-aged` 读取与即将推出的 Cargo `-Zmin-publish-age` 支持([追踪 issue #17009](https://github.com/rust-lang/cargo/issues/17009),[RFC #3923](https://github.com/rust-lang/rfcs/pull/3923))相同的配置键。将其放入你项目的 `.cargo/config.toml` 中: ``` [registry] min-publish-age = "14 days" ``` 接受的值:`"N days"` / `"N day"` / `"N weeks"` / `"N week"`,或一个表示天数的纯整数。 **优先级(最高者生效)**: 1. CLI 上的 `--min-age ` 2. `.cargo/config.toml` 中的 `[registry].min-publish-age` —— 从清单目录向上搜索至根目录,然后是 `$CARGO_HOME/config.toml`(默认为 `~/.cargo/config.toml`) 如果两者均未设置,`cargo-aged` 会报错退出,而不是猜测一个默认值——你必须显式选择一个特定的阈值。如果你不需要任何年龄过滤,请使用普通的 `cargo update`。 当值来自配置文件时,有效的阈值及其来源会在运行开始时打印出来。 一旦 Cargo 的 `-Zmin-publish-age` 稳定后,相同的配置文件将同时管理解析器和此工具。 ### 选项 | 标志 | 默认值 | 描述 | | --- | --- | --- | | `--min-age ` | 见下文 | crate 有资格进行更新前的最小发布天数。覆盖 `.cargo/config.toml`。如果配置文件未提供此值,则为必填项——否则工具会报错退出。 | | `--manifest-path ` | `./Cargo.toml` | 要读取的 `Cargo.toml` 路径。 | | `--dry-run` | off | 打印将要更新的内容,而不修改 `Cargo.lock`。 | | `--verbose` | off | 同时打印每个 crate 的发布时间戳。 | | `--iterate` | off | 重复执行直到一次完整的过程不再产生更改(上限为 10 次)。对于像 `serde` + `serde_json` 这样紧密耦合且只能分阶段降级的依赖家族非常有用。 | | `--check` | off | 只读 CI 门禁。如果 `Cargo.lock` 包含任何锁定到比阈值更年轻版本的直接 registry 依赖,**并且** crates.io 上存在符合年龄要求的替代版本,则退出代码为 `1`。不会修改 `Cargo.lock` 或调用 `cargo update`。与 `--dry-run` 和 `--iterate` 互斥。 | | `-h`, `--help` | | 打印帮助信息。 | | `-V`, `--version` | | 打印版本信息。 | ### 跳过的内容 - **Path 依赖** (`path = "..."`) —— 无需从 crates.io 获取。 - **Git 依赖** (`git = "..."`) —— 同上。 - **`=` 锁定的要求** (`serde = "=1.0.210"`) —— 该锁定被视为显式选择并保持不变。 - **最新稳定版本比 `--min-age` 更年轻的 crate。** - **已经锁定到符合年龄要求版本的 crate** —— 会报告为 `= serde 1.0.210 — already age-eligible` 并保持不变。请注意,这意味着 `cargo-aged` 不会主动将同一个大版本下的一个符合年龄要求的版本升级到另一个更新的符合年龄要求的版本;如果你想先跟进最新版本再进行老化回退,请结合普通的 `cargo update` 使用。 - **在 crates.io 上报 404 或 API 调用失败的 crate** —— 会打印警告并跳过该 crate。 在选择“最新稳定”版本时,会忽略被撤回(yanked)的发布和预发布版本(任何带有 `-` 后缀的版本,例如 `1.0.0-rc.1`)。 ### 示例输出 ``` Checking 12 dependencies (min-age: 30 days)... ✓ serde 1.0.210 — 45 days old, updating... ✗ tokio 1.38.0 — 8 days old, skipping ✗ reqwest (git dep) — skipping ✓ clap 4.5.4 — 62 days old, updating... ... Summary: 3 updated, 9 skipped. ``` 使用 `--dry-run` 时,`updating...` 行会变为 `would update (dry-run)`,并且不会调用 `cargo update`。 ## 工作原理 1. 解析你的 `Cargo.toml`(包括 `[dev-dependencies]`、`[build-dependencies]`、`[target.*.dependencies]` 和 `[workspace.dependencies]`)。 2. 对于每个 registry 依赖,使用描述性的 `User-Agent` GET 请求 `https://crates.io/api/v1/crates/`(根据 crates.io 合理使用政策)。 3. 选择未被撤回且非预发布的最新版本。 4. 读取 `Cargo.lock`,如果已经锁定了任何符合年龄要求的版本,则跳过该 crate(防止冗余工作并使 `--iterate` 收敛)。 5. 如果 `(当前时间 - 发布时间) >= 最小年龄`,则调用 `cargo update -p --precise --manifest-path `。 6. 如果该 `cargo update` 失败(通常是因为另一个直接依赖传递性地将此 crate 限制在更新的版本范围内),则使用次旧的、符合年龄要求的版本重试——每个 crate 最多尝试 5 次——并报告成功的锁定,或者在所有尝试均失败时报告最后的错误。 7. 使用 `--iterate` 时,重复整个过程,直到某次过程产生零次更新(不动点),最多 10 次。 8. 打印已更新与已跳过计数的摘要。 年龄限制**仅应用于你在 `Cargo.toml` 中声明的直接依赖**。传递性依赖则交由 Cargo 的常规解析器处理。 你的 `Cargo.toml` 绝不会被修改——只有 `Cargo.lock` 会通过 `cargo update` 被触及。 ## 开发 ``` cargo build cargo run -- aged --dry-run # test against this repo's own manifest cargo run -- aged --dry-run --manifest-path ../other-project/Cargo.toml ``` ## 许可证 MIT OR Apache-2.0
标签:Cargo插件, Rust, SOC Prime, 依赖管理, 可视化界面, 开发工具, 网络流量审计, 通知系统