#github #ci #cargo-command

ferrous-actions

Rust 的 GitHub actions,用 Rust 编写并编译成 WebAssembly

1 个不稳定版本

0.1.0-beta.12023年1月15日

#494WebAssembly

MIT 许可证

190KB
4.5K SLoC

Ferrous Actions

CI

Rust 的 GitHub actions,用 Rust 编写并编译成 WebAssembly。

关于

actions-rs,Rust 相关 GitHub actions 的默认选择似乎已被放弃。这个仓库是一个实验,用 Rust 编写的 actions 替换那些 actions,但编译成 WebAssembly。这应该使它们可以在不同平台上移植,并且更容易由只懂 Rust 的开发者维护。

使用方法

像所有 GitHub actions 一样,此操作通过 GitHub Actions YAML 文件 中的指令来使用。为了实用性和实现原因,Ferrous Actions 以“单一操作”结构构建,这意味着所有操作都作为单个操作的子命令实现,而不是分开。command 参数始终是必需的。

在所有后续示例中,FrancisRussell/ferrous-actions@v0.1.0-beta.1 应替换为 README 中此操作的版本。可以在 此处 找到 Ferrous actions 在实际项目中的使用示例。

请注意,默认情况下,GitHub 将使用操作名称作为其用户界面中构建步骤的名称。这可能令人困惑,因为对于单一操作,这些名称总是相同的。强烈建议使用 name 属性,并在下面的示例中使用它。

Cargo home 缓存

Cargo 下载的注册表索引(例如 crates.io 上的包列表)、crate 文件和 Git 仓库可以在 CI 作业之间缓存。

使用文件修改时间戳来检测缓存项是否未发生更改,以避免无谓地将其上传回缓存。

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Cargo cache
  with:
    command: cache
    cache-only: indices
    min-recache-crates: 1m
    min-recache-git-repos: 12h
    min-recache-indices: 7d

以下选项也可用

  • cache-only(可选):空格分隔的 git-reposcratesindices 令牌列表。如果提供,则仅缓存这些项。默认情况下,将缓存所有项。
  • min-recache-crates(可选):重新缓存 crates 的最小时间。
  • min-recache-git-repos(可选):重新缓存 Git 仓库的最小时间。
  • min-recache-indices(可选):重新缓存索引的最短时间。
  • cross-platform-sharing(可选,实验性):尝试在所有平台(all)、仅Unix-like平台(unix-like)或使所有缓存特定于平台(none)。默认为none

所有重新缓存间隔均以人类时间指定。指定重新缓存间隔可以在每次更改时避免上传缓存项的新版本。这对于索引很有用(在crates.io的情况下),可以很大(几百MiB),经常修改,但只有小的变化。目前,索引的最小重新缓存间隔为2天,对于crate文件或Git仓库没有指定。

使用Rustup安装Rust工具链

Ferrous动作可以下载Rustup并安装指定的Rust工具链。

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Install Rustup
  with:
    command: install-rustup
    toolchain: nightly
    target: wasm32-unknown-unknown
    profile: minimal
    default: true

以下选项也可用

  • toolchain(必需):要安装的工具链
  • target(可选):空格分隔的目标架构列表。
  • profile(可选):Rustup配置文件(例如minimaldefaultcomplete)。默认为default
  • default(可选):是否将此工具链设置为Rustup默认编译器。默认为true这与actions-rs的行为不同
  • override(可选):是否应为此当前目录设置Rustup 'override'。默认为false

Cargo命令

Cargo命令可以通过Ferrous动作调用。在这种情况下,command的值是cargo SUBCOMMAND,其中SUBCOMMAND是一个单独的标记。

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Cargo build
  with:
    command: cargo build
    toolchain: stable
    args: --release

以下选项在调用任何Cargo子命令时都可用

  • toolchain(可选):传递给cargo的工具链标识符,使用+toolchain语法(仅由Rustup安装的工具链支持)。
  • args(可选):传递给cargo的命令行标志。这些将使用Unix风格的shell引号规则解析,而不管平台如何。

使用Cargo install安装包

Ferrous动作将使用GitHub的缓存机制来提高安装二进制文件的性能,而不是每次都从头开始编译。请注意,Ferrous动作目前旨在实现透明的工具缓存 - 缓存不应导致您使用您本来不会使用缓存而使用的二进制文件的版本。

grcov install

这意味着Ferrous动作缓存的是构建工件文件夹,而不是构建的二进制文件本身。唯一只缓存后者的方法是完全确信构建前所有依赖项,Nix风格的

从用户的角度来看,这意味着

  • 当使用以前未见过的Rust工具链编译工具时,将从头开始重新编译工具。如果您跟踪nightly,这可能会相对频繁地发生。
  • 对工具的任何更改(因为它在注册表中或其依赖项已更新)将立即反映在安装操作的结果中。当发生这种情况时,更新的构建工件将被推送到GitHub缓存。

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Install grcov
  with:
    command: cargo install
    args: grcov

以下选项具有额外的约束

  • args(必需):与上述相同,但至少需要二进制名称。请注意,命令行将被哈希以生成缓存键,因此更改将导致工具从零开始重建。

当通过 Ferrous 操作调用时,cargo install 将在当前目录之外执行。这里的目的是避免 rust-toolchain.toml 或 Rustup 覆盖更改编译二进制所使用的编译器。

从 cargo build、check 或 clippy 获取注释

当通过 Ferrous 操作运行 buildcheckclippy Cargo 子命令时,会输出注释,可以通过 GitHub UI 查看这些注释。

Unused function annotation

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Cargo clippy
  with:
    command: cargo clippy
    annotations: true

以下选项也可用

  • annotations(可选):可以根据是否需要注释设置为 truefalse。默认为 true

跨平台支持

通过 Ferrous 操作调用 cargo build 也可以使用 cross 工具。

示例调用

- uses: FrancisRussell/ferrous-actions@v0.1.0-beta.1
  name: Cargo build
  with:
    command: cargo build
    args: --target=x86_64-apple-darwin
    use-cross: true

如果指定 use-crosstrue,则将使用 cross 进行编译。如果指定为 false 或未指定,则按常规调用 cargo。如果不可用现有 cross 二进制文件,则将构建并安装。

实现说明

单调递增缓存问题

缓存的一个主要问题是如何确保缓存的大小不会单调递增。这个问题可能发生在两个地方:缓存的 cargo home 艺术品和缓存的二进制中间构建艺术品。这个问题只部分解决。

在 Linux 和 Apple 系统上,使用文件访问时间来确定缓存的 cargo home 项目中哪些条目被访问,并修剪未访问的项目。这已经被实现,以便在存在“relatime”语义的情况下仍然有效 - 当文件访问时间戳只有在其修改时间戳之后才更新时。

在 Windows 下通常禁用文件访问时间 - 微软从未实现 relatime 的等效功能,这意味着它们仍然是一个重大的性能打击。在不更新文件访问时间戳的文件系统上,Ferrous 操作将把当前文件夹下所有 Cargo.lock 文件的哈希值纳入缓存键。这意味着每当更改 Cargo.lock 文件时,缓存都将从头开始重建。

这种解决方案远非理想,因为它会导致不必要的缓存,并且如果未将任何 Cargo.lock 文件提交到 Git 或以其他方式(例如,由于 cargo install)添加到缓存中,则无法工作。

对于构建艺术品文件夹大小增加的问题,尚无解决方案。由于 Rust 是一种快速发展的语言,因此预计编译器升级将导致在成为问题之前文件夹从头开始重建。由于很可能只是检查必要文件的日期而不是读取内容,因此文件访问时间戳技术可能无法在这里工作。

并发 CI 作业

大型项目将被分割成多个CI作业,这些作业具有不同的依赖关系。确保这些作业之间不相互竞争非常重要。这可能会发生,因为它们对所需的依赖关系有不同的看法(导致缓存项被反复移除和恢复),也可能因为它们都可能决定缓存项需要更新,并同时在同一时间推送新的副本。

每个CI作业被分配一个唯一的标识符(从工作流、作业ID和任何矩阵属性派生而来),其中记录了一个依赖项列表。这些依赖项中的每一个都称为“缓存组”,其名称包含其预期内容的哈希值。

缓存组表示一个或多个捆绑在一起的依赖关系(例如crate、git仓库)。单个依赖关系可能被更新,但从未添加或删除。这意味着任何CI作业都可以自由更新其使用的任何缓存组。具有不同依赖关系的作业将与不同的缓存组交互。

将缓存组作为可能的最细粒度缓存似乎是个好主意。目前对于缓存的索引和Git仓库来说是这样,但对于crate来说不是。许多crate相当小(几十KiB),而项目通常依赖于大量crate。为每个缓存的crate构建单独的缓存条目似乎不太理想,并且可能会让用户感到烦恼。因此,crate在特定索引使用的所有crate的级别上缓存。

为了避免所有并发CI作业同时推送类似的更新缓存组,我们使用cache action的内部API来确定我们打算更新的任何缓存组自我们下载以来是否有新版本被推送,在我们上传新版本之前。这将从几分钟减少到几秒钟的竞争窗口。

crate.io

此代码主要作为防止名称抢注和保持历史记录的主动措施推送到crates.io,因此可能已过时,应查阅主页以获取最新信息。

注释/免责声明

Ferrous actions是非常实验性的,不应在生产环境中或对业务关键目的进行依赖。请参阅LICENSE以获取更多详细信息。

Ferrous actions主要适用于小型Rust项目的使用。如果您需要复杂的缓存框架,那么是时候考虑设置基于云存储和/或Nixsccache了。

致谢

此存储库基于Peter Evans(@peter-evans)创建的模板此处

许可证

MIT

依赖关系

~10–20MB
~272K SLoC