GitHub ActionsのProblem MatchersでShellCheckの指摘を表示する

Today I Learned

ShellCheckは、シェルスクリプト用のLintツールで、文法上の問題や想定外な実行結果が起こらないようにチェックするツールである。
シェルスクリプトは雰囲気で書いているので、Linterがあるのは嬉しい。

この記事では、ShellCheckの実行方法や、GitHub ActionsのProblem MatchersでShellCheckの指摘を表示する方法を説明する。

ShellCheck をインストールする

Macであればhomebrewを使ってインストールできる。

$ brew install shellcheck

ShellCheck を実行する

ShellCheckは次のコマンドで実行できる。

$ shellcheck *.sh

例えば次のような、定義されていない変数を使っているようなスクリプトに対してチェックをしたとする。

invalid.sh
#!/bin/bash

echo "$foo"

ShellCheckを実行すると、構文エラーとなる項目が表示される。

$ shellcheck -f gcc *.sh

test.sh:3:7: warning: foo is referenced but not assigned. [SC2154]

GitHub Actions で ShellCheck を実行する

GitHub Actionsでは、ランナーがLinuxの場合のみ、ShellCheckがプリインストールされている。
そのため、他のLintツールのように事前にインストールする必要がない。
Ref. https://github.com/koalaman/shellcheck#in-your-build-or-test-suites

ShellCheckをGitHub Actionsで動かすためのアクションはいくつか公開されているが、開発元が公開したActionsはなかった。
今回は、Problem Matchersを使って、指摘内容をGitHub Actionsのアノテーションに表示させる。
ちなみに、ludeeus/action-shellcheckというアクションでは、Problem Matchersを使ってアノテーション表示できるようだった。

エラー結果をキャプチャするルールファイルを追加する

Problem Matchersとは、GitHub Actionの出力結果を正規表現のパターンとして解析し、アノテーションを表示する機能である。
出力結果のパターンをどのようにキャプチャするかのルールは、jsonファイルで定義する。
あとでGitHub Actionsのワークフロー側で指定するため、ファイル名や位置は何でも良い。
ただ、GitHub.comの機能なので、.github以下に置くと行儀が良さそう。

ownerにProblem Matchersの固有のIDを割り振り、pattern以下に正規表現のパターンを定義する。
今回のShellCheckerはgcc形式で出力するので、regexpはgcc形式に合わせた正規表現とした。
また、キャプチャしたグループの順番を、file(ファイル名)やline(行番号)といったプロパティに指定する。

.github/shellcheck-matcher.json
{
  "problemMatcher": [
    {
      "owner": "shellcheck-matcher",
      "pattern": [
        {
          "regexp": "^(.+):(\\d+):(\\d+):\\s(note|warning|error):\\s(.*)\\s\\[(SC\\d+)\\]$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5,
          "code": 6
        }
      ]
    }
  ]
}

GitHub Actions のワークフローを追加する

ShellCheckerを実行するGitHub Actionsのワークフローを追加する。
Problem Matchersを使って実行結果をキャプチャするには、ツールの実行前にecho "::add-matcher::ルールファイルのパス"を実行すれば良い。

.github/workflows/shellcheck.yml
name: shellcheck

on:
  pull_request:
    paths:
      - "*.sh"

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Enable Problem Matchers
        run: echo "::add-matcher::.github/shellcheck-matcher.json"
      - name: Exec shellcheck
        run: |
          shellcheck -f gcc *.sh
          echo "::remove-matcher owner=shellcheck-matcher::"

先ほどの、定義していない変数を使ったシェルスクリプトに対し、このワークフローを実行すると、アノテーションにエラー内容が表示された。

画面キャプチャ:GitHub Actions のアノテーションに、ShellChecker の指摘が表示されている