【Elixir】compile, lint, formatの結果をGitHub ActionのJob Summaryに表示する
GitHub Actionsを利用してElixirプロジェクトのlint, formatのチェックをPRごとに行うことでコードの品質を担保できます。
この記事ではlintやformat, testの実行結果をWorkflowのSummary画面にmarkdown形式のコンテンツとして生成する方法を解説します。
Job Summaryとは
GitHub Actionsにはworkflowのsummaryページに、markdown形式のコンテンツを追加できる機能があります。
次の2つの方法でサマリーを生成できます。
-
$GITHUB_STEP_SUMMARY
という環境変数にコンテンツを出力する -
@actions/core
パッケージで提供されているcore.summary
クラスのメソッドを使う
この記事では後者の @action/core
を使った実装をしています。後者の場合は addTable
や addDetails
などマークダウン形式のコンテンツを作成するためのメソッドが提供されており、実装がしやすいためオススメです。
ElixirのCI例
早速CIのサンプルです。以下のfly.ioのブログ記事のCIをベースにしていますので、合わせて参照してください。
name: CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
env:
MIX_ENV: test
permissions:
pull-requests: write
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Elixir
uses: erlef/setup-beam@v1
with:
otp-version: 25.1.2
elixir-version: 1.14.2
- name: Cache deps
id: cache-deps
uses: actions/cache@v3
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: |
${{ runner.os }}-mix-
- name: Cache compiled build
id: cache-build
uses: actions/cache@v3
with:
path: _build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: |
${{ runner.os }}-mix-
- name: Install dependencies
run: mix deps.get
- name: Compile
id: compile
# 1. continue-on-error: trueを設定して、mixコマンドの終了ステータスが0ではない場合でもjobを続行させる
continue-on-error: true
# 2. `&>` を指定して標準出力と標準エラー出力をtmpファイルに出力する
run: mix compile --warnings-as-errors &> /tmp/result
- name: Report compile result
# 3. tmpファイルに書き出した内容をGitHubのsummaryに出力する
# summaryを出力する部分は使いまわせるため、composite actionとして実装
uses: ./.github/actions/command-summary
with:
body: /tmp/result
header: Compile
- name: Compile status
# 4. mixコマンドの終了ステータスが0でない場合はこのタイミングでjobを停止させる
if: steps.compile.outcome == 'failure'
run: exit 1
- name: Format
id: format
continue-on-error: true
run: mix format --check-formatted &> /tmp/result
- name: Report format result
uses: ./.github/actions/command-summary
with:
body: /tmp/result
header: Format
- name: Format status
if: steps.format.outcome == 'failure'
run: exit 1
- name: Credo
id: credo
continue-on-error: true
run: mix credo > /tmp/result
- name: Report credo result
uses: ./.github/actions/command-summary
with:
body: /tmp/result
header: Credo
- name: Credo status
if: steps.credo.outcome == 'failure'
run: exit 1
- name: Test
id: test
continue-on-error: true
run: mix test > /tmp/result
- name: Report test result
uses: ./.github/actions/command-summary
with:
body: /tmp/result
header: Test
- name: Test status
if: steps.test.outcome == 'failure'
run: exit 1
name: Command Summary
description: create job summary
inputs:
header:
description: header
required: true
body:
description: filepath where the command execution result is saved
required: true
runs:
using: "composite"
steps:
- uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const body = await fs.readFileSync("${{ inputs.body }}");
await core.summary
.addHeading("${{ inputs.header }}", 2)
.addCodeBlock(body)
.write();
compileの部分にコメントを書いています。他のmixコマンドも同様の構成です。ポイントは次のとおりです。
-
mixコマンドの終了ステータスが0ではない場合にそのタイミングでjobが終了してしまうとJob Summaryへの出力ができません。そのため、
continue-on-error: true
を設定してjobを継続させるようにします。 -
mixコマンドの結果をtmpファイルに書き出して後続のsummary作成時に参照します。
-
command-summary/action.yaml
というcomposite actionにheaderとtmpファイルのパスを渡しています。composite actionの中ではactions/github-script
を使用し、core.summary
クラスを利用してサマリーを作成しています。 -
1. の処理で
continue-on-error: true
としていた分をsummary作成後に回収します。stepの結果をsteps.<id>.outcome
で取得し、failure
であればjobを終了させます。
formatやcredoでエラーになってもtestまで回したいということであればここは割愛してもOKです。
実際の使用例
このyamlの状態でmainブランチに対してPRを出すなりしてCIを回すと、次の画像のようにjobのsummary画面にMarkdownのコンテンツが生成できます。
さらにアレンジする
このworkflowをベースに、次のようなアレンジが考えられそうです。
- 成功✅、失敗❌の絵文字などを追加してよりリッチにする
- compile, testなどログが長く生成されうるものは
<details>
で括る-
core.summary
クラスにはaddDetails
のようなメソッドもあるので容易に実装できます
-
- コンパイルの時間やテストの実行時間を表形式で出力する
- これも
addTable
メソッドが提供されているので実装しやすいです
- これも
- job sumamryではなくPRに対してコメントをする運用にする
- この記事のテーマと外れますが、1つの選択肢としてアリだと思います
- PRに対してコメントする方式で運用する場合はmarocchino/sticky-pull-request-commentが便利です
コンパイルやテストなどの基本的に成功する前提のものはsummaryに出力し、terraformのplan結果など毎回確認したいものはPRにコメントするなど、ニーズに合わせて運用を考えるのが良さそうです。
まとめ
ElixirのCIでGitHub ActionsのJob Summariesを使った場合のworkflow例を紹介しました。ここまで書いたものの、コンパイルやテストが落ちたらjobのログを見にいっちゃう気がします。テストのカバレッジを表示するなど、ログを見るより視認性が良いコンテンツが刺さるのかなと思います。
参考
Discussion