Edited at

新GitHub ActionsはCIに使えるか

GitHub Actionsは執筆時の2019/08/12時点でまだbetaであり、ここに記載されている内容やリンクは正式版リリースに伴って変更される可能性がありますので、注意してください


tl;dr;


  • matrix buildが可能になったのでOSSのCIとしてTravisCIの代替になりえる

  • 細かい機能はまだ色々足りていない(TravisCIは老舗中の老舗なので比べてしまうのは酷ですが)

  • 単純にTravisCIの置き換えとしてmatrix buildしたい場合は以下のサンプルコードを参照

nodejs(ubuntu-18.04, ubuntu-16.04 x nodejs 10, 12の4パターン)

name: "CI"

on: [push]

jobs:
check_pr:
strategy:
matrix:
node: [10.x, 12.x]
os: [ubuntu-18.04, ubuntu-16.04]

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Setup node version
uses: actions/setup-node@master
with:
version: ${{ matrix.node }}

- name: "npm ci"
run: npm ci

- name: "npm run test"
run: npm run test

ruby(ubuntu-latest x ruby 2.4, 2.5, 2.6の3パターン)

name: CI

on: [push]

jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
ruby: [ '2.4.x', '2.5.x', '2.6.x' ]

steps:
- uses: actions/checkout@master
- name: Set up Ruby version
uses: actions/setup-ruby@master
with:
version: ${{ matrix.ruby }}

- name: Set up bundler
run: gem install bundler

- name: bundle install
run: bundle install --jobs 4 --retry 3

- name: test
run: bundle exec rake spec


新しいGitHub Actionsについて

2019/08/09にGitHub Actionsが新しくなると発表され、従来に比べて特にCIとしての機能が強化されました。特に目玉機能としてTravisCIのようなmatrix buildが追加されました。

CIサービスは老舗、新興合わせて無数に存在しますが、OSS界隈ではほぼTravisCI一択だったと思います。TravisCIが使われるのは老舗という理由が大きいと思いますが、OS x 言語バージョンのmatrixでテストを行うことが非常に簡単というのも大きな理由だと思います。

matrixビルドの結果画面のUIも非常によくできており、どの組み合わせでテストが成功、失敗したかがひと目で分かるようになっています。

travis_matrix_result_ui.png

GitHub Actionsでmatrix buildを行った場合でもpull-reqの画面に組み合わせごとのビルド結果が並びます。TravisCIのUIほどではないですが、実用的には十分な分かりやすさでしょう。

github_actions_matrix.png

また、大きな変更として今までのHCL(HashiCorp Configuration Language)から他のCIサービス同様にyamlで設定するようになりました。そのため、従来までの.workflowファイルは書き直す必要がありそうです。

自分はまだ使用していないですが、マイグレーションツールも用意されているようです。

https://help.github.com/en/articles/migrating-github-actions-from-hcl-syntax-to-yaml-syntax


ドキュメント一覧


matrix build

yamlの書き方については冒頭のサンプルを参照してください。

公式ドキュメント内にサンプルとなりそうなコードは乏しいですが、以下のリポジトリのREADMEを見れば大体分かると思います。


actions/setup-xxxについて

TravisCIでは言語のバージョン切り替えは既存のツールを使用しており、例えばrubyのバージョン切り替えにはrvmが使われていました。GitHub Actionsではhttps://github.com/actions/ に存在するsetup-xxxxを使うのをデファクトにしたいらしい?

少なくとも、リポジトリで新しいGitHub Actionsを有効にして最初にテンプレを選択する画面でnodejsを選択した場合は、このようにactions/setup-nodeを使用するyamlのサンプルが表示されます。

github_actions_wizard.png

setup-xxxxの実装は言語毎に異なっているようです。例えばsetup-rubyはVMにインストールされているruby(2.3.7, 2.4.6, 2.5.5, 2.6.2)を切り替えているだけのように見えます。 一方、setup-nodeはVM内のバージョンを切り替えるのではなく、指定したバージョンのバイナリをダウンロードしてからPATHを通しているようです。

なぜrvmのような既存のツールを使わないのか分からないですが、とにかくsetup-xxxは独自の実装になっているため、rvmのようなツールでインストールできるバージョンが全て使えるわけではないことに注意しましょう。(少なくとも今は)

rubyに関しては既にrvmを使う方法を紹介されている方もいましたので、どうしてもその類のツールを使いたい場合は参考になると思います。

GitHub Actions がローンチされたのでマイグレートしてる


dockerでmatrix buildはおそらく使えない?

前述のようにVMに言語の特定バージョンをインストールする代わりに、dockerイメージのタグ指定にmatrixの変数を使えれば解決"でした"。

試してみたのですが、どうもusesの指定では変数の展開が許されていないのか、文法エラーになってしまいました・・・。

on: [push]

jobs:
check_pr:
strategy:
matrix:
node: [10.x, 12.x]
os: [ubuntu-18.04, ubuntu-16.04]

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: "node version"
uses: docker://node:${{ matrix.node }} # ここがエラーになる
continue-on-error: true
with:
args: node --version

エラーメッセージ:

### ERRORED 06:07:27Z

- Your workflow file was invalid: .github/workflows/blog.yml (Line: 15, Col: 13): Unrecognized named-value: 'matrix'. Located at position 1 within expression: matrix.node

自分の調査不足の可能性はありますが、今後のバージョンアップで対応される可能性もあるかもしれません。自分は一旦諦めて今後のアップデートを期待することにしました。


docker imageを使う場合

runに普通にコマンドを渡すとVM上で実行されますが、uses: docker://node:10のようにdockerイメージやタグを指定することで、旧Actionsのようにdockerを使用できます。

実際に使ってみてハマったポイントをいくつか紹介します。


実行コマンドの指定

uses だけしか指定しなかった場合はENTRYPOINTのコマンドが実行されるようです。従って、例えばdocker://node:10を使用してnpm installを実行したい場合はこのように書く必要があります。

- name: "npm install"

uses: docker://node:10
with:
args: npm install

ドキュメントを読んだ感じではargswithにネストさせる必要はないように見えるのですが、実際にはこのように書く必要がありました。

実際に実験して動作を確認したリポジトリはこちらです。


DockerfileでUSERを指定してはいけない

サラッと書いてあるので見逃しやすいのですが、ドキュメントにその記述があります。


/github/workspace - Note: GitHub Actions must be run by the default Docker user (root). Ensure your Dockerfile does not set the USER instruction, otherwise you will not be able to access GITHUB_WORKSPACE.


root以外のユーザで実行されてしまうと$GITHUB_WORKSPACEに書き込むことができないようです。


docker://nodeのようにDockerfileにUSERが指定されていない場合はデフォルトのrootユーザで実行されるので問題はないです。


一方で、docker://circleci/nodeのようにUSERが指定されているイメージの場合はnpm installなどを行った際にPermission deniedが起きてしまいます。

その場合でもsudoを付けてsudo npm installなどとすることで動作はしました。(他に副作用があるかもしれませんが、詳しくは調査していないです)

CircleCIからの移行組は注意すべきポイントだと思います。


その他のCIサービスで一般的な機能の有無


バッジ

OSSのREADME冒頭に置いてある最新のビルドが成功しているかどうかを示しているあれです。 ドキュメントにそのような記述はなかったので、少なくとも今の所は提供されていないようです。

3rdパーティ製ではありますがLambdaなどを使って自作した方が使わせてくれるものがいくつかあるので、それを使わせてもらうことで一応対応はできます。

このようなものです https://github.com/atrox/github-actions-badge


ci skip

多分効かないっぽい?コミットメッセージに[ci skip]を付けても普通に実行されてしまったと思います。

Actions自体がpushやpr以外のトリガーでも動作するものなので仕方ないか。


secret

GitHub以外のサービスと連携する場合などのために、トークン等の文字列を管理する仕組みが通常のCIサービスには存在します。

GitHub Actionsにも同等の仕組みはあるようです。今回試してはいないのですが、ドキュメントに記載があったのでおそらく普通に使えそうです。

https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables


キャッシュ

npm installのnode_modulesや、bundle install —path=vendorのvendorディレクトリを保存しておいて、次回の実行時に依存ライブラリをダウンロードしてくる工程をスキップするための仕組みです。

一般的なCIサービスでは当然用意されているのですが、GitHub Actionsでは少なくともドキュメントにこれについての記述が見つけられませんでした。

OSSのように依存が少ない場合は毎回ダウンロードしてもそれほど時間はかからないのでそれほど問題ではないですが、RailsやiOS/Androidのビルドなど依存ライブラリがどうしても多くなるリポジトリの場合は、キャッシュの仕組みがあるかないかでビルド時間がかなり変わってきます。

自前でS3やGCSに保存するロジックを書けば同等のことは可能でしょうが、公式でサポートしてくれないと使いづらいですね。まだβですし今後に期待。

(actions/setup-nodeの挙動やソースを見るとキャッシュの仕組みは何らかあるようなので、それをハックすることで自分でも使えるようにすることは可能かもしれません。ですが少なくともドキュメントに書かれていない時点で非公式でしょうし、やるとしても安定はしていないという心構えはしておいた方が良いでしょう)


総評

OSSのCI用途としてTravisCIの代替にはなるという印象。ですが、まだ細かいところは機能が足りなかったりするため、今すぐ乗り換える必要があるほどではないかなと思います。

バックにMS様のAzureが付いているので、matrixの並列数が多くてもクラウドの力で何とかしてくれそう。

OSS以外のWebサーバーやiOS/AndroidのビルドにはCircleCIを使っている方が多いと思います。Linux/macOS/WindowsのVMが揃っているのでCircleCIでできることは基本的に置き換えられるはずですが、メリットがあるかと言われるとまだ微妙という印象。

少なくともキャッシュの仕組みを誰かが3rdパーティ製actionsとして公開してくれるか、公式が用意してくれないと厳しいと思います。

一方で、GitHub Actionsはpushやpr以外のトリガー(issueのコメントとかラベルを付けたタイミング)で起動することもできます。最初はCIとして使わずとも、CircleCIでは自動化できずにGitHubのwebhookを使ったbotなどで対応してきた部分からGitHub Actionsに置き換えていくと良いのではないかと思います。

最後に自分が実験したリポジトリのurlを貼っておきます。これから新しいGitHub Actionsを試してみたい方は参考にしてみてください。