mediba Advent Calendar 2020 の18日目担当の @h-sugawara です。
担当している各種プロジェクトでは、CI/CD に CircleCI というサービスを使わせて頂いています。
しかし、最近、諸事情により CircleCI から Github Actions への移行を検討していて、Github Actions の導入検証を行いました。
今回は、Github Actions で頻出して使うことが多くて調べたものを、毎度調べ直すのが面倒だったため、情報を集約する Tips を作成しました。
Workflow Tips
コミットにソースコードを含む開発用ブランチをプッシュした時に実行する
開発用ブランチfeature/hogehoge
にソースコードbatch/foobar/main.go
を含むファイルをコミットして、Github へプッシュした時に、テストや構文チェックを行う Workflow を実行させたいとします。
このような場合、次の例のようにプッシュイベントのトリガーを設定します。
on:
push:
branches:
- 'feature/*'
paths:
- '**.go'
on.push.branches
の'feature/*'
は、feature/
から始まるブランチが対象です。
しかし、__*
は/
を除く0文字以上の文字列を示すフィルタ__であるため、feature/issue-1234/hogehoge
のようなブランチは対象外となることに注意が必要です。
これらの対象外となるブランチも含める場合は、0文字以上のすべての文字列を対象とする**
を用いて'feature/**'
とします。
on.push.paths
も同様のルールで、上述の例の場合はすべての.go
ファイルがコミットに含まれているかが対象となります。
これを、'*.go'
と書き換えた場合は、レポジトリのルートにある.go
ファイルだけが対象となります。
指定ブランチ以外をプッシュした時に実行する
特定のブランチのプッシュを無視する場合は、on.push.branches-ignore
で指定します。
ただし、これをトリガーに設定すると Github Actions の仕様上、__タグのプッシュはすべて無視される__ことに留意しておきましょう。
タグのプッシュも含めるには、次のようにon.push.tags
に'*'
または'**'
を、トリガーに設定します。
on:
push:
branches-ignore:
- 'develop'
- 'release/**'
tags:
- '*'
このようにすると、例えば、feature/
から始まるブランチをプッシュしたり、v1.0.0
のようなタグをプッシュしたりすると Workflow が実行されます。
反対に、develop
ブランチやrelease/
から始まるブランチをプッシュしても Workflow は実行されません。
なお、タグのプッシュが無視されても構わない場合は、on.push.tags
の指定は不要です。
指定タグ以外をプッシュした時に実行する
特定のタグのプッシュを無視する場合は、on.push.tags-ignore
で指定します。
前述のbranches-ignore
と同様に GitHub Actions の仕様により、__ブランチのプッシュはすべて無視__されます。
ブランチのプッシュも含めるには、下記のようにon.push.branches
に'**'
を、トリガーに設定します。
※'*'
を指定した場合、ブランチ名に/
が含まれるとうまく動かないため、'**'
の利用を推奨。
on:
push:
branches:
- '**'
tags-ignore:
- 'dev-*'
- 'stg-*'
この設定例では、develop
ブランチや、feature/
またはrelease/
などから始まるブランチをプッシュしたり、v1.0.0
のようなタグをプッシュしたりすると Workflow が実行されます。
反対に、dev-
やstg-
で始まるタグがプッシュされた場合は、Workflow は実行されません。
もちろん、特定のタグ以外のタグのプッシュを対象とするだけなら、on.push.branches
は不要です。
プルリクエストがマージされた時に実行する
プルリクエストのマージをトリガーとする Workflow を作成する時は、次の2点に注意が必要です。
- compare ブランチ(マージ元)ではなく、base ブランチ(マージ先)が対象である
- プルリクエストイベントのアクティビティタイプにはマージされたことを示すものはない
そのため、以下の例のように、on.pull_request.types
がclosed
であり、job
などでgithub.event.pull_request.merged
がtrue
であることを確かめる必要があります。
on:
pull_request:
branches:
- my_base_branch
types:
- closed
jobs:
my_job_name:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: my_step_name
run: echo "Hello world!"
renovate などのツールやプルリクエストの作成などを定期的に実行する
on:
schedule:
- cron: '*/15 * * * *'
Job Tips
2つ以上前に実行された Job の出力値を参照する
例えば、first_job
、second_job
、last_job
の順で Job を実行するとします。
この時、last_job
のneeds
に、直前に実行されることを意図してsecond_job
だけを指定すると、Job の実行順はその通りになります。
しかし、second_job
の前に実行されたfirst_job
の出力値は参照できません。
なぜなら、Job が参照できる出力値は、依存関係によって以前に実行したすべての Job ではなく、needs
で指定した Job のみだからです。
そのため、実行する Job から見て依存関係にあるすべての Jobを needs
に指定する必要があります。
jobs:
first_job:
runs-on: ubuntu-latest
outputs:
first_val: ${{ steps.echo_step.outputs.first }}
steps:
name: set output
id: echo_step
run: echo "::set-output name=first::hogehoge"
second_job:
runs-on: ubuntu-latest
needs: [first_job]
outputs:
second_val: ${{ steps.echo_step.outputs.second }}
steps:
name: set output
id: echo_step
run: echo "::set-output name=second::foobar"
last_job:
runs-on: ubuntu-latest
needs: [first_job, second_job]
steps:
name: echo before job output
run: |
echo "${{ needs.first_job.outputs.first_val }}"
echo "${{ needs.second_job.outputs.second_val }}"
直前の Job の結果が success 以外でも必ず実行する
Job の実行条件は、if: success()
(成功時のみ実行)がデフォルトで設定されています。
そのため、jobs.<job_id>.needs
で指定した Job のいずれか一つでも実行結果がsuccess
以外になった場合、<job_id>
の実行はスキップされます。
必ず実行させる必要がある Job には、下記のようにif: always()
を指定しましょう。
jobs:
first_job:
runs-on: ubuntu-latest
steps:
name: failure job
run: exit 1
second_job:
runs-on: ubuntu-latest
steps:
name: success job
run: exit 0
last_job:
runs-on: ubuntu-latest
needs: [first_job, second_job]
if: always()
steps:
name: echo
run: echo "running second_job."
この方法は、テストやビルド、デプロイなどの Job の後に、Slack などでそれらの実行結果を通知する Job を実行する場合に活用できます。