ワークフローテンプレート


このドキュメントでは、GitHub Actions(GHA)を使ってExercismの言語トラックの継続的インテグレーション(CI)ワークフローを設定する方法を説明します。速く、信頼でき、堅牢なCIワークフローを自分で作るために活用できるベストプラクティスと例を紹介します。このフォルダーにあるGHAワークフローは、基本構造が同じままなので、どんなCIにも合わせて応用できます。

内容は次のとおりです。

  • 理想的なCIワークフローの概要
  • 検討事項と推奨事項
  • すぐに使えるテンプレート
  • Travisからの移行ガイド

これらのワークフローファイルの実装例はexercism/javascriptで見つけられます。

助けて: かなりの_大仕事_に見えます 😓

このドキュメントの残りは、ワークフローがどのように動作するかを説明するために書かれています。急いでいて、PRスクリプトを最適化せずにTravisやCircleからGHAに切り替えたいだけなら、Travisからの移行の約10分ガイドをご覧ください。

トラックのCIアクション

リポジトリの内容が整合しているかを確認するために推奨されるアクションは次のとおりです。

  1. config.jsonを確認するためのconfigletリンティング
  2. スタブの確認
  3. ドキュメントの確認(v3では新しいファイルが必要です。これはconfigletに移るかもしれません)
  4. "maintainers"構成を使って演習をリントする
  5. 例(example/exemplar)ファイルを使って演習をテストする(ビルド手順を含む場合もあります)

トラック固有のアクションを追加することもできます。たとえば、次のようなものです。

  1. 演習の構成の整合性を確認する
  2. 演習ファイルのフォーマットを確認する

さらに、次のように、あると便利なチェックを追加したくなるかもしれません。

  1. CONTRIBUTINGが存在することを確認する
  2. 依存関係に適切なロックファイルがあることを確認する
  3. Markdownファイル内のリンクが有効であることを確認する
  4. ...

推奨事項

チェックを実行する頻度

各アクションについて、どれくらいの頻度で実行すべきかを考えましょう。

  • configletのリンティングは非常に重要です(config.jsonが壊れるとトラックが壊れてしまうため)。そのため、おそらく常に実行すべきですが、ただしコミットごとに1回実行すれば十分です。
  • ファイルの存在や整合性の確認は、コミットごとに1回実行すれば十分です。
  • トラックが複数のランタイムバージョンやコンパイラーバージョンで動作することを想定しているなら、演習のビルドとテストはサポートする各バージョンに対して実行しましょう。
  • PRでは、_追加_または_変更_されたファイルに対してのみアクションを実行すれば_おそらく_十分ですが、あるファイルが演習全体に影響を与えることもあるため、演習のファイルが1つでも変更されたら、その_演習_に対してアクションを実行するほうが安全です。

実行すべきアクションをローカルでも利用できるようにしておくと、とても役立ちます。つまり、実際の処理を行うスクリプトを手動でも実行できるようにするということです。そのためには、ワークフローファイルの中にアクションをインラインで書かず、独立したスクリプトを作成します。たとえば、スタブの確認はワークフローファイルの中にシェルで書ききることもできますが、ここでは代わりに新しい実行可能スクリプトscripts/ci-checkを作成することをおすすめします。

「でも、コマンドはとても短いですよ。たとえばeslint . --ext ts --ext tsxのように」。

このコマンドを更新する必要が出たとき、ドキュメント、ワークフローファイル、そして_メンテナーの頭の中_という、あらゆる場所で更新しなければならなくなります。これをスクリプトに切り出せば、そうした問題はすべて解決します。また、ワークフローファイルを読むのはとても大変に感じられることもあります。

演習が変更されたPRでのチェック

scripts/prとscripts/pr-checkスクリプト(テンプレートを参照)は、このPRで変更または追加されたファイルごとに1つずつ、複数の引数を付けて実行されます。たとえば、two-ferが更新された場合、呼び出しは次のようになります。

scripts/pr exercises/two-fer/README.md exercises/two-fer/.meta/example.ext

アクションは、変更された_ファイル_ではなく、変更された_演習_に対して実行することをおすすめします。ファイルを変更すると、演習全体に影響が及ぶ可能性が高いからです(構成やパッケージなどを考えてみてください)。

まだ準備ができていない? / 複雑すぎる?

この最適化を実装する前なら、無視しても問題ありません! 移行ガイドでも、後の段階で追加することをほのめかしています。入力引数を無視すれば、すべてのチェックがすべての演習で実行されます。これはまったく問題ありません。単に時間がかかるだけです。

整合性チェック

トラックに単一の「トップレベル」の依存関係ファイルやその他の構成ファイルがある場合は、整合性のステップを追加します(これはscripts/syncやbin/syncと並んで存在し、すべての構成ファイルをすべての演習にコピーするものです)。このステップは、トップレベル/ベースのファイルが演習ディレクトリにコピーされたものと同じであることを確認します。これで依存関係を更新し、リポジトリ全体に同期でき、すべての演習が同じ構成を持つことを確認できます。

これを実現する一般的な方法は、チェックサムを使うことです。Ubuntu(およびその他さまざまなLinuxディストリビューション)にはsha1sumというツールが付属していますが、構成ファイルをハッシュ化または圧縮してチェックサム値にする(md5、sha1、crc32)_どのような_方法でも機能します。

$ sha1sum README.md
cd58091c5043bf21f00d39ff1740d8b2976deeff *README.md

セキュリティチェック

トラックがGitHubトークンやその他のシークレットへのアクセスを必要とする追加のワークフローを使っている場合、そのワークフローで使うすべてのアクションを特定のコミットに固定するのがベストプラクティスです。詳しくはGitHubのセキュリティ強化ガイドを参照してください。

たとえば、次のとおりです。

- uses: julia-actions/setup-julia@v1
+ uses: julia-actions/setup-julia@d26d1111976eae5f00db04f0515ab744ec9cd79e # 1.3.1

ツールに依存関係管理用のロックファイルがある場合は、それをリポジトリにコミットし、ワークフローファイル内で「フローズンロックファイル」を使うことを検討しましょう。たとえば、npm ci、yarn install --frozen-lockfile、bundle install --frozenです。これにより、依存関係を変更するときにロックファイルが最新であることが保証され、悪意のあるパッケージの混入を防げます。

テンプレート

このディレクトリには、少なくとも次のテンプレートがあります。

  • configlet.yml: このワークフローは最新のconfigletバイナリを取得して、このリポジトリをリントします。コミットごとに実行されます。PRでは、実際のコミットと「マージ後」のツリーに対して実行されます。
  • ci.yml: このワークフローはmainブランチでのみ、コミットごとに1回実行されます。
    1. すべての演習に対して'pre-check'コマンド(スタブ、リント、ドキュメントの確認など)を実行します
    2. すべての演習に対して、複数のバージョンで'ci'コマンド(ビルドとテスト)を実行します
  • pr.ci.yml: このワークフローはPRでのみ、コミットごとに1回実行されます。
    1. 変更されたファイルに対して'pre-check'コマンド(スタブ、リント、ドキュメントの確認など)を実行します
    2. 変更された演習に対して、複数のバージョンで'ci'コマンド(ビルドとテスト)を実行します

PR以外のワークフローは、workflow_dispatchから手動でトリガーすることもできます。

各ファイルの先頭には、どの「スクリプト」を用意すべきかが記載されています。これらをバイナリにしたい場合は、scripts/xxxをbin/xxxに置き換えます。ツールによっては、バイナリがbinフォルダー内にあることを_必須としている_ものもあります。

  • scripts/ci: 例の解答を使ってすべての演習をテストに対してビルドおよびテストするスクリプト
  • scripts/ci-check: すべての演習をリントし、オプションでスタブや構成の整合性などを確認するスクリプト
  • scripts/pr: scripts/ciと同じですが、入力として渡されたパスから解決された演習だけを実行します
  • scripts/pr-check: scripts/ci-checkと同じですが、入力として渡されたパスから解決されたファイルまたは演習だけを実行します

トラブルシューティング

問題が発生した場合や、ワークフローを誰かにレビューしてほしい場合は、@exercism/github-actionsチームにメンションしてください。

すべての演習でCIを実行すべきトップレベルのファイルを変更した

これを書いている時点では、pr.ci.ymlは「拡張子」によるテストしか許可していません。理想的には、特定のファイル(たとえばテストを実行するバイナリ)が変更されたときに常にトリガーされるように更新すべきです。ただし、こうした変更はめったになく、しかもメンテナーによって行われるため、ci.ymlがmainで常にすべてに対して実行されるという事実でおそらく十分安全です。

Windowsでscripts/xxxファイルを作成したら、{他のOS}で動作しなくなった

既定では、Windowsで作成されたファイルには、実行可能かどうかに関するメタデータがgit-indexに埋め込まれません。Windowsの権限のモデルが異なるためです。Gitは既定で、git-indexのメタデータを使って、POSIXベースのシステムでそのファイルを実行可能にすべきかどうかを判断するため、結果としてscripts/xxxファイルは実行可能になりません。

git update-index --chmod=+x scripts/xxx
git commit -m "Make scripts/xxx executable"