cargo fmt 在 CI 报 cargo-fmt 未安装:为实际工具链添加 rustfmt
CI 报 cargo-fmt 未安装时,为实际选中的 Rust 工具链添加 rustfmt,核对项目覆盖与安装步骤;区分组件缺失和格式检查差异。
CI 执行 cargo fmt 时出现 'cargo-fmt' is not installed for the toolchain,通常要检查实际选中的 Rust 工具链有没有 rustfmt 组件。把 rustfmt-nightly 写进 Cargo.toml 的 dev-dependencies,并不等于给 rustup 管理的工具链安装 cargo fmt 所需的组件。
这条错误发生在格式检查启动前。先解决组件与工具链的对应关系,再处理格式差异;不要把“没有格式化程序”与“代码未按规则格式化”当成同一种 CI 失败。
在失败步骤的工作目录确认工具链
在相同 CI 环境和项目目录查看 rustup 的工具链状态:
rustup show
核对活动工具链、项目的 rust-toolchain 或 rust-toolchain.toml、CI 中的 RUSTUP_TOOLCHAIN,以及命令是否写了 cargo +某个工具链。显式命令、环境变量、目录覆盖和项目文件都可能改变选择;另一个终端的默认 stable 不能证明失败步骤也使用 stable。
例如报错指定一个按日期固定的 nightly,而安装步骤只给 stable 添加组件,后面的检查仍可能找不到 rustfmt。安装步骤成功,只能证明那一步对应的工具链有组件。
同一目录存在旧式 rust-toolchain 和 rust-toolchain.toml 时,rustup 会优先使用旧式文件。还应确认 CI 的运行目录与查看配置的目录一致,不把子目录覆盖或另一份检出配置漏掉。
给实际使用的工具链添加组件
以下命令示例只适用于已经确认使用 stable 的项目。若项目固定其他工具链,应保留该工具链选择,并将 stable 换成实际名称:
rustup component add rustfmt --toolchain stable
cargo +stable fmt --all -- --check
第一条下载并安装组件,会改变该工具链的本机状态;第二条检查工作区格式,不应改写源码文件。项目只要求检查部分包时,仍按原有检查范围执行,不要因为示例含 --all 就擅自扩大 CI 契约。
不要为了组件缺失随意把固定 nightly 改成最新 nightly。项目可能依赖某个版本的编译能力或格式规则,工具链升级应独立评估。指定版本或目标平台确实没有可用组件时,核对项目认可的工具链与组件可用性,不能认为反复执行安装命令就会产生缺失的构建产物。
将组件要求纳入项目工具链配置
如果团队依靠 rust-toolchain.toml 创建环境,可以在已有配置中保留原 channel、profile 等选项,并将 rustfmt 加入 components。下面只是采用 stable 的完整简化示例:
[toolchain]
channel = "stable"
components = ["rustfmt"]
已有 components 还包含 clippy 等要求时,应保留它们,不能用这个数组覆盖其他必需组件。实际环境使用自定义 path 工具链时,组件管理方式不同,不能只加 components 就假定 rustup 会补齐程序。
调整前保存原配置,确认 CI 的安装流程会读取这份工具链文件,并让安装与检查发生在正确的运行环境。一个容器或步骤中安装的组件,不会自动出现在隔离的另一个容器或机器里。
若 Cargo.toml 中的 rustfmt-nightly 仅为解决这条组件错误而添加,核对它没有其他用途后撤回这项依赖修改,并按项目规则更新锁文件。业务确实依赖相应 crate 时,不应只凭名称相同就删除它。
程序能启动后,再看格式检查结果
rustfmt 的 --check 会报告需要调整的格式。存在差异时返回非零,表示检查已经运行,不能再把它解释为组件没装上。应在开发环境按项目规则调整代码并审查差异,而不是删除 --check 让 CI 不再检查。
直接运行 cargo fmt 会改写源码;需要格式化时先确保工作区中的未提交修改已保存,检查生成的差异后再提交。直接调用 rustfmt 与 cargo fmt 的 edition 推断还可能不同,应保持项目既定入口和配置,避免仅更换调用方式制造新的差异。
最终验收应从原来失败的 CI 步骤确认:实际工具链与配置一致、cargo fmt 可以启动、检查范围和格式规则符合项目要求。组件安装成功不代表整个构建或测试都已通过。需要回退时恢复原工具链声明和 CI 配置;源码被格式化后的更改则通过版本控制单独恢复。


