GitHub ActionsでRustプロジェクトを複数ツールチェイン&複数OSでビルドする
背景
こちらの本を読んでRustを勉強しています。
「10-5 自動テストを行う」でTravis CIとAppVeyorを使ったCI環境の構築方法が紹介されていたのですが、せっかくなので同じことをGitHub Actionsで実現しようとして、調べたことをメモ。
やりたいこと
- Rustの Stable/Beta/Nightly チャネルそれぞれでビルド・テストを実行したい
- 加えて、Windows/macOS/Linux でビルド・テストを実行したい
- Nightly チャネルでのテスト失敗は無視したい
1 については、書籍によると
本章でも行っているとおり、beta チャネルでもテストするのがベストプラクティスとされています。
とあります。また 3 については
一方で nightly は正常に動くことは保証されていないので、テストをするとしても失敗を許可した方がよいでしょ う。
という記載があります。
最終的な設定ファイル
先に、できたもの。
以下を .github/workflows/test.yml
などとしてプロジェクトに置きます。
name: test on: [push, pull_request] jobs: build: name: Rust ${{ matrix.os }} ${{ matrix.rust }} runs-on: ${{ matrix.os }} strategy: matrix: rust: - stable - beta - nightly os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v2 - name: Setup Rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true - name: Build run: cargo build - name: Run tests run: cargo test continue-on-error: ${{ matrix.rust == 'nightly' }}
以下、設定ファイルの解説。
基本は actions-rs を使う
自分が調べた限りですが、Rust 向けの GitHub Actions としては actions-rs というアクション集があるようです。
Organization の説明を見ると
Unofficial GitHub Actions for Rust programming language
とあるので公式ではないようですが、ググった中ではこれが一般的に使われている印象を受けました。
- Building Rust for Multiple Platforms Using Github Actions | by Dotan Nahum | Medium
- Rust and GitHub Actions - DEV
- Travis CIからGitHub Actionsへの移行 - Laboratory of Scarlet
一番よく使われるであろう actions-rs/rust-toolchain も GitHub での Star 数は120程度ですが、
Marketplace にあるその他の Rust 向けアクションよりはだいぶ Star 数が多いようです。
https://github.com/marketplace?type=actions&query=rust
※ Organization の member が一人なのが若干気になりますが。。。
また、この Organization 内にある actions-rs/meta の #Recipes や actions-rs/example には
actions-rs 内のアクションを使ったサンプルがいくつか置かれており、参考になります。
今回はこのうちの Matrix CI Workflow というレシピをベースにしています。
複数ツールチェイン、複数プラットフォームは matrix ビルドで
Stable/Beta/Nightly といった複数のツールチェイン、ならびに Windows/macOS/Linux といった複数の OS 環境での実行は matrix
パラメータを使います。
Rust ツールチェインのインストールは actions-rs/toolchain
rustup を使って各ツールチェインをインストールしてくれるようです。指定可能なオプションは #Inputs の項に書いてあります。
profile: minimal
とは?
https://github.com/rust-lang/rustup#profiles
によれば、rustup には profile という概念があり、minimal
, default
, complete
の順にインストールされるコンポーネントが増えるようです。
minimal
: コンパイラを動かすための最低限 (rustc
,rust-std
,cargo
) しかインストールしないdefault
:minimal
に加えrust-docs
,rustfmt
,clippy
complete
: すべて
今回は cargo build
および cargo test
だけできれば十分なので minimal
を指定していますが、将来フォーマッターやリンターもかけたいとなった場合は default
がいいのかもしれません。
(もしくは components
パラメータで必要なコンポーネントを直接個別に指定する)
override: true
とは?
#Inputs の項には
Set installed toolchain as an override for the current directory
と書かれており、rustup の Directory overrides に相当します。
このディレクトリで使うツールチェインをデフォルトから上書きしたい場合は指定します。
インストールしたチャネルのツールチェインを使いたいので、指定する必要があります。
Nightly チャネルではテストの失敗を許可する(TravisCI や AppVeyor の allow_failures
相当)
書籍の TravisCI や AppVeyor の設定例では、 allow_failures
というオプションを使用しています。
これを GitHub Actions でどう実現するか調べた結果、以下の記事を参考に continue-on-error
を Nightly チャネルのときだけ true にすることにしました。
GitHub ActionsでTravis CIのallow_failures的なやつをやりたい - くりにっき
リンク先では
strategy: matrix: rust: - stable - beta - nightly os: [ubuntu-latest, windows-latest, macos-latest] include: - rust: nightly allow_failures: "true" steps: ... - name: Run tests run: cargo test continue-on-error: ${{ matrix.allow_failures == 'true' }}
のように専用の変数を設けていましたが、今回は allow_failures: true
にしたい条件が単純で、かつ continue-on-error
を指定してる箇所も1箇所なので
単純にツールチェインのチャネルの値 (matrix.rust
) によって判断しています。
問題点としては、(参考リンク先でも指摘されていますが)現状GitHub Actionsの continue-on-error
ではエラーが出ていてもパスしたときと同じ緑色で表示されるため、エラーに気づけないという点があります。
actions-rs/cargo は必要?
レシピやブログ記事を見ていると、cargo build
や cargo test
しているところに actions-rs/cargo というアクションを指定しているものがありました。
# たとえば、cargo build と cargo test の代わりに以下のように指定する - uses: actions-rs/cargo@v1 with: command: build - uses: actions-rs/cargo@v1 with: command: test
こちらをわざわざ導入すべきか?というところは少し迷ったんですが、 #Use Cases の項には
Note that this Action is not required usually and you can just use
run
step instead as in example below:(コード略)
Why would you want to use this Action instead:
- Transparent
cross
installation and execution withuse-cross: true
input enabled- Warnings and errors issued by
cargo
will be displayed in GitHub UI
というわけで、単に cargo build
や cargo test
を実行したいだけなら使う必要はないが、↑に書いたようなメリットがあるとのことでした。
1点めの cross
とは https://github.com/rust-embedded/cross のことで、試したことはありませんがcargoと同じように扱えてクロスコンパイルを簡単に実現するためのツールのようです。
2点めの GitHub UI については、たとえばアクション実行結果のAnnotationsの部分にwarningやerrorが表示されるようになることは確認できました。
余談: actions-rs/toolchain の override: true
は必要?
最初、actions-rs/toolchain の override: true
オプションおよびそこから rustup の Directory overrides について調べたとき、
このオプションは必ず指定した方がいいのかどうか疑問でした。
rustup の挙動はよく理解していませんが、インストールされるツールチェインが1つであれば自動的にそれがデフォルトになって指定しなくても挙動は変わらないはず...と。
で、確認してみたところ、GitHub Actions で使われる VM にプリインストールされているツールの一覧が
https://github.com/actions/virtual-environments
というリポジトリにあるのですが、これによると Rust および rustup
は最初からインストールされています。
そのため、actions-rs/toolchain での指定に関わらず Stable チャネルはインストール済みかつデフォルトに指定されている、と推測しました。
念のため、 override: true
なしだと期待したツールチェインを使ってくれないことは
GitHub Actions 内で rustup show
や rustup toolchain list
を実行するとわかります。
# beta チャネルを指定したビルドでの結果 Default host: x86_64-unknown-linux-gnu rustup home: /home/runner/.rustup installed toolchains -------------------- stable-x86_64-unknown-linux-gnu beta-x86_64-unknown-linux-gnu active toolchain ---------------- stable-x86_64-unknown-linux-gnu (default) rustc 1.45.0 (5c1f21c3b 2020-07-13)
また、 actions-rs/toolchain 側の挙動を追っていったときのメモは以下。
- actions-rs/toolchain は ここ で @actions-rs/core の
getOrInstall()
を呼んでおり、ここで rustup をインストールしていそう getOrInstall()
は、rustup がすでにあればそれを使うし(このへん)、インストール時も--default-toolchain none
で実行する(このへん)- rustup がインストールされてなければ ここ にかかれているデバッグログを出力するはずだが、アクションの実行結果を見る限り出力されてなかった
- ちなみに
core.debug
を出力するにはACTIONS_STEP_DEBUG = true
というシークレットを登録する必要がある(参考)
- ちなみに