皆さん、あけましておめでとうございます! エンジニアの岡村です。
今年もSynamon's Engineer blogでは皆様の開発の参考になることを願って情報を発信していきます!
- GitHub Actions
- GITHUB_STEP_SUMMARYに、後から確認出来るようにワークフローのパラメータを書き出しておく
- ツールを動かすときはProblem Matchersを設定して、エラーの詳細をSummaryに出力するようにする
- workflow_callでトリガーと処理を分割する
- サンプル
- 以上
GitHub Actions
弊社ではマルチプラットフォーム向けのアプリをビルドすることが多いため、CIは重要です。以前はJenkinsを使っていましたが、SYNMNの開発にあたりGitHub Actionsへの移行を行いました。
開発もある程度軌道に乗り、GitHub Actionsもそこそこ慣れてきたので、現時点で感じているワークフローを運用する際に便利だったことを紹介しておきます。
GITHUB_STEP_SUMMARYに、後から確認出来るようにワークフローのパラメータを書き出しておく
GitHub Actionsのサマリー画面はデフォルトではごく僅かな情報しか載っていませんが、ワークフロー中にワークフローコマンドを実行することで追加情報を載せることが出来ます。
特にworkflow_dispatchなどでワークフローを手動実行した場合などは、ワークフローの引数を後から確認することが難しい為、そういった情報を出力しておくことで後で混乱せずに済みます。
GITHUB_STEP_SUMMARY
はmarkdownが使えるため、以下のように出力しておけば表形式になって視認性が向上します。
run: | echo "|Properties|Value|" >> $GITHUB_STEP_SUMMARY echo "|---|---|" >> $GITHUB_STEP_SUMMARY echo "|GitHub Ref|\`${{ github.ref }}\`|" >> $GITHUB_STEP_SUMMARY echo "|Commit Hash|\`${{ github.sha }}\`|" >> $GITHUB_STEP_SUMMARY echo "|Some Workflow Input|${{ inputs.hoge }}|" >> $GITHUB_STEP_SUMMARY
以下の画像は一例ですが、GITHUB_STEP_SUMMARY
に記述した内容は、このようにArtifactsの下に表示されます。
ツールを動かすときはProblem Matchersを設定して、エラーの詳細をSummaryに出力するようにする
GitHubにはproblem_matcherという機能があり、設定しておくとログ出力から正規表現で一致するログを検出して、わかりやすくSummeryに出してくれたりインラインコメントを付けてくれます。
例えばUnityビルドを行う場合、以下のようなMatcherを適用しておくとコンパイルエラーを拾ってくれます。
{ "problemMatcher": [ { "owner": "Unity", "severity": "error", "pattern": [ { "regexp": "^(.*\\.cs)\\((\\d+),(\\d+)\\):\\serror\\s(.+):\\s(.+)$", "file": 1, "line": 2, "column": 3, "code": 4, "message": 5 } ] } ] }
Matcherを有効化するには、そのステップの直前に以下のようなコマンドを実行します。
- run: echo ::add-matcher::.github/workflows/unity-problem-matcher.json
以下の画像はこれまた一例ですが、上の設定をすることで以下のようにコンパイルエラー発生時に検出してくれます。
コンパイルが成功し、テストが失敗した場合はテスト結果ファイルを解析するAction(こちらなど)に流す事が出来るのですが、テスト実行以前のエラーに関しては、通常はステップの中までログを見に行かなければならないので、Matcherを設定しておくことで時間が短縮できます。
あと、上記画像では何故か同じエラーが4つも出力されていますが、まあ何も出ないよりはマシという事で一旦放置しています……。
workflow_callでトリガーと処理を分割する
一つのワークフローを、ワークフローの実行条件等を記述する呼び出し側と、ビルドなどの実際の処理を書く側に分割したところ、見通しが良くなりました。
背景として、GitHub Actionsはyamlベースで記述し、基本的には問題なく使えるのですが、JenkinsのGroovy Scriptに比べてコードが重複しやすく、特にマルチプラットフォームで微妙にmatrix化し辛いような処理を書いているとすぐに同じコードだらけになってしまっていました。
JenkinsのGroovy Scriptなら関数を使って同じ処理を纏めることが出来るのですが、Actionsではそれが出来ません。yamlにはアンカーやエイリアスといった、定義したブロックを使いまわせる機能があるのですが、GitHub Actionsではそれが動作しない(2023年1月時点)ためです。
workflowは基本的にGitHub上でしか動かない(ローカルで検証しづらい)為、ローカルで叩いても問題ないような処理単位は外部スクリプトにまとめた方が良いのですが、キャッシュや成果物のアップロード、シークレット情報の管理などのGitHub Actions上で動かすためのステップに関しても中々の量になります。
そこで、最低限の分割として、Workflow callという機能を使い、トリガー専用のworkflowと処理専用のworkflowを分けてみました。
これによりdevelopブランチならテストとビルドを両方実施、featureブランチならテストだけ実施というように、実行タイミングの制御も各ワークフローに分散してしまうことがなくなりました。
サンプル
上で紹介したような機能を使い、現状クライアントアプリ用のリポジトリ内のActionsは以下のようになっています(見せられない所が多いので大幅にカットしていますが……)全体の形はこうなるという参考程度にしていただければ幸いです。
トリガー用ワークフロー
name: on-develop on: push: branches: - "develop" paths-ignore: - "**.md" workflow_dispatch: jobs: build: uses: ./.github/workflows/build.yml secrets: inherit with: environment-context: Development custom-build-number: ${{ github.run_number }} development-build: true deploy: runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/develop' needs: build steps: # 成果物をテスト環境にデプロイする処理など
処理用ワークフロー
name: build on: workflow_call: inputs: environment-context: required: true type: string custom-build-number: required: false type: string default: "0" development-build: required: false type: boolean default: false include-platforms: required: false type: string default: "Windows, macOS, Android, iOS" #workflow_dispatchを設定しておくとbuild単体を手動で実行できるのでおススメ workflow_dispatch: inputs: environment-context: description: Environment Context required: true type: choice options: - Release - Development custom-build-number: description: Custom Build Number required: false type: string default: "" include-platforms: description: Include Platforms required: false type: string default: "Windows, macOS, Android, iOS" # run-nameを設定しておくと手動実行した際にGitHub上の実行履歴で表示される名前をカスタマイズできるのでおススメ # workflow_callで実行された時は無視される run-name: Build as ${{ inputs.context }} on ${{ github.ref_type }} ${{ github.ref_name }} [${{ github.sha }}] jobs: dump-properties: runs-on: ubuntu-latest steps: - name: Build arguments summary run: | echo "|Build Properties|Value|" >> $GITHUB_STEP_SUMMARY echo "|---|---|" >> $GITHUB_STEP_SUMMARY echo "|GitHub Ref|\`${{ github.ref }}\`|" >> $GITHUB_STEP_SUMMARY echo "|Commit Hash|\`${{ github.sha }}\`|" >> $GITHUB_STEP_SUMMARY echo "|Environment Context|${{ inputs.environment-context }}|" >> $GITHUB_STEP_SUMMARY echo "|Custom Build Number|${{ inputs.custom-build-number }}|" >> $GITHUB_STEP_SUMMARY echo "|Include Platforms|${{ inputs.include-platforms }}|" >> $GITHUB_STEP_SUMMARY windows-build: runs-on: [self-hosted, windows, x64] if: contains(inputs.include-platforms, 'Windows') timeout-minutes: 90 steps: # Windowsプラットフォーム向けのビルド処理 android-build: runs-on: [self-hosted, windows, x64] if: contains(inputs.include-platforms, 'Android') timeout-minutes: 90 steps: # Androidプラットフォーム向けのビルド処理 ios-build: runs-on: [self-hosted, macOS, x64] if: contains(inputs.include-platforms, 'iOS') timeout-minutes: 90 steps: # iOSプラットフォーム向けのビルド処理 macos-build: runs-on: [self-hosted, macOS, x64] if: contains(inputs.include-platforms, 'macOS') timeout-minutes: 90 steps: # macOSプラットフォーム向けのビルド処理
以上
GitHub Actionsは去年あたりからだいぶ使いやすくなってきたように感じます。github-hosted runnerの選択肢や日本語ドキュメントの量、まだ欲しい機能などは色々あるのですが、現状でも他のCIサービスに引けを取らない充実度だと思います。ネット上の記事も充実してきたので、今年からGitHub Actionsを触り始めて見るのも良いのではないでしょうか。また何か面白い使い方などを発見したら記事にしようと思います。
記事を読んでいただきありがとうございました!今年もSynamonとSYNMNを宜しくお願いいたします!