Azure Bicep with GitHub Actions
Azure Bicepにはv0.4.1からLinter機能が搭載されています。 AZ CLIにも組み込まれておりいつでも利用可能です。また、Visual Studio Code Extensionにも含まれているためBicepコードを記述しながらLint結果を確認することができます。
ここまで来ると、Pull Request発行時にもLinterを実行したくなるというものです。 ということで今回実現したいのは次の2点です。
- Azure Bicep LinterをGitHub Actionsで実現する
- 同時にProblem Matcherでエラー・ワーニング箇所がすぐにわかるようにする
Azure Bicep LinterをGitHub Actionsで実現する
BicepにはLinter専用コマンドやコマンドオプションは用意されていません。Azureにデプロイする際、またはBicepのBuildを実行する(ARM Templateを作成する)際に実行されます。ということで、GitHub ActionsでのLint実行はbicep buildを利用することにしました。 ここで問題が1つ。BicepのLint結果は通常Warningレベルで出力されます。コマンド実行結果もコード0(正常)となります。これだとGitHub Actionsは正常終了と認識してしまい、通知を行ってくれません。当初この問題を linter-rulesをbicepconfig.jsonで変更することで解消しようとしました。しかし、以下のワーニングはどうやらbicepconfig.jsonで出力レベルを変更することができませんでした。
BCP036: The property "omsagent" expected a value of type "ManagedClusterAddonProfile" but the provided value is of type "null | object".
ここからが戦いの始まりでした。
上記のBCP036ワーニングのような場合もlinter-rulesのワーニング同様のメッセージフォーマットで出力されるようです。であれば、grepでWarningを検索し、あればエラーexit 1、なければexit 0で終了してやればいいのではないか。
仕組みは簡単です。GitHub Actionsのワークフロー上でスクリプトを直接書いてやればよい。よいはずでしたが、そう簡単にはいかない。実はGitHub Actionsのワークフロー上でコマンドを実行した場合、exit 0以外のコマンド実行を検知するとその時点で止まってしまいます。さて、ここで問題になるのがgrepです。ご存じの通り、grepは検索対象が見つかった場合は0を、見つからなかった場合はそれ以外を終了時に返します。そうです、grepの実行でWarningがなかった場合は0以外が返りますので、この時点でワークフローが終了してしまいます。
ということでスクリプトファイルを作成し、lintやgrepはそのスクリプト内で実行し、ワークフローからはこのスクリプトファイルを実行するのみとします。これで問題は解消。
そこで作成したスクリプトファイルは次のようなものです。
#!/bin/bash exitCode=0 for file in `ls **/*.bicep`; do az bicep build --file $file --stdout 2>&1 > /dev/null | grep -iE '^warning|^error' if [ $? -eq 0 ]; then exitCode=1 fi done exit $exitCode
これでLinterは実行できるようになりました。
Problem Matcherでエラー・ワーニング箇所がすぐにわかるようにする
次は、ワーニングやエラー発生時にPull Requestの画面でエラーの内容がわかりやすくすることにします。
GitHub Actionsには検出したエラーやワーニングを表示する機能があります。以下がそのサンプルです。ここまでlint実行時も表示してくれれば便利ですね。
でも、さきほど作成したスクリプトを実行した際はここまで表示してくれません。 エラーメッセージの形式がGitHub Actionsが用意しているものとは異なるためです。
この形式を指定するのがProblem Matchersです。(詳細は本家のドキュメントをご覧ください)
指定した内容は Warning用
{ "problemMatcher": [ { "owner": "bicep-linter-warning", "severity": "warning", "pattern": [ { "regexp": "(^[Ww].+) (/.+\\.bicep)\\((\\d+),(\\d+)\\)\\s:\\s(.*)$", "file": 2, "line": 3, "column": 4, "message": 5 } ] } ] }
Error用
{ "problemMatcher": [ { "owner": "bicep-linter-error", "severity": "error", "pattern": [ { "regexp": "(^[Ee].+) (/.+\\.bicep)\\((\\d+),(\\d+)\\)\\s:\\s(.*)$", "file": 2, "line": 3, "column": 4, "message": 5 } ] } ] }
の2つです。
regexp
の部分をメッセージフォーマットに合致するよう正規表現で記載します。そのあとのfile
、line
,column
、message
でGitHub Actionsがメッセージの内容を理解できるようにします。
これをGitHub Actionsのワークフローで
- name: Add problem matcher run: | echo "::add-matcher::.github/matcher/bicep-linter-warning.json" echo "::add-matcher::.github/matcher/bicep-linter-error.json"
と指定すればOK.
以下が実際のワークフローのyamlです。
name: Check on pull-request on: pull_request: push: branches: - main jobs: lint: name: Lint check runs-on: ubuntu-latest steps: - name: Chckout pull request uses: actions/checkout@v2 - name: Setup Bicep uses: anthony-c-martin/setup-bicep@v0.1 with: version: v0.4.613 - name: Add problem matcher run: | echo "::add-matcher::.github/matcher/bicep-linter-warning.json" echo "::add-matcher::.github/matcher/bicep-linter-error.json" - name: Run Bicep build shell: bash run: | bash .github/commands/lint.bash
これで以下のようにワーニングやエラーの内容を画面上に表示できます。
これでBicep LinterをGitHub Actionsでも実行可能になりました。最低限のチェックはPull Requestで行ってくれるので安心ですね。