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


あらまし

弊社LIFULLではQiita以外にLIFULL Creators Blogでも社外発信を行っています。

このブログの運用フローを考えるにあたって、.md ファイルに対してPRを作ったタイミングでtextlintをかけて修正を促すということに取り組みました。

その中で、GitHub Actionsを使っていて便利だと感じたProblem Matchersについて書きます。

検証に利用したソースコードはこちらに公開しています。

最初に設定した内容

GitHub Actionsのワークフローにおいて、.md ファイルを含むPRが作成されたときにはNode.jsのバージョン14でtextlintを実行するように設定しています。

.github/workflows/main.yml
name: Exec textlint
on:
  pull_request:
    types:
      - opened
      - synchronize
    paths:
      - "articles/**.md"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js environment
        uses: actions/[email protected]
        with:
          node-version: "14"
      - name: Install dependencies
        run: npm ci
      - name: Exec textlint
        run: |
          git diff origin/${GITHUB_BASE_REF}..origin/${GITHUB_HEAD_REF} \
            --diff-filter=AM \
            --name-only -- '*.md' \
            | xargs npm run lint

参考: GitHub Actions を用いて Pull-Request で shellcheck をする方法

textlintの設定は記事の本筋ではありませんが、いくつかそれらしいものを利用しています。

.textlintrc
{
  "rules": {
    "preset-japanese": true,
    "ja-no-abusage": true,
    "ja-no-mixed-period": true,
    "ja-unnatural-alphabet": true,
    "prh": {
      "rulePaths": [
        "node_modules/prh/prh-rules/media/WEB+DB_PRESS.yml"
      ]
    }
  }
}

これらを設定したうえでPRを作成するとワークフローは正常に動きます。

何もやってないのにインラインコメントまで入っている!賢い!

ただしなんだかチェック項目が偏っていそう…?

ローカルで実行するともっとたくさんあるので、どうやらなんだかおかしそうです。

動作の解釈

自動でインラインコメントが入る理由

正確には一部の結果がAnnotationsに書き出されています。私の疑問はこちらの記事を拝見して解消しました。

  • 出力から正規表現でパターンを抜き出して表示する機能 -> Problem Matchers
  • .githubディレクトリ以下に定義ファイルが存在
  • アクション(setup-node)の中でeslintの設定を有効化

つまり、setup-nodeアクションを利用することでeslintの結果をアノテーションに表示する機能が有効になり、それがtextlintの出力も拾ってしまっているようです。

ちなみにtextlintも自分がeslintに似ていることを自覚しています。

The pluggable linting tool for text and markdown.
textlint is similar to ESLint, but it's for use with natural language.

textlintの指摘内容を部分的に拾う理由

eslint向きの正規表現でマッチする箇所だけが表示されるようです。下記のような記述がされており、textlintの指摘で「✓」が入る場合は考慮されず対象から外れるように見えます。

eslint-stylish.json
"regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$"

※ textlintではautofixが可能な場合に「✔」が表示されます

textlint用の設定追加

すべての指摘内容を表示できるように、textlint用のProblem Matchersを設定します。

Problem Matchers

.github/textlint-matcher.jsonを作成します。eslintの設定とほとんど変わらないので、コピペさせていただいたうえで少し書き換えています。

owner

Problem Matchersを無効にしたり差し替える場合に利用するIDです。今回は使いませんがユニークっぽいものにしておきます。

github/textlint-matcher.json
"owner": "textlint-matcher"

regexp

「✔」と直後の半角スペースを考慮するため ✓*\\s* を追記します。

github/textlint-matcher.json
"regexp": "^\\s+(\\d+):(\\d+)\\s+✓*\\s*(error|warning|info)\\s+(.*)\\s\\s+(.*)$"

補足

ドキュメントを呼んでも下記の記述の意味がさっぱりわからなかったのですが、regexp においてどの箇所からその要素が取得できるかを示しているようです。

github/textlint-matcher.json
"line": 1,
"column": 2,
"severity": 3,
"message": 4,
"code": 5,

例: 行数は1ブロック目の (\\d+)、重大度は3ブロック目の (error|warning|info) から取得できる)

ワークフローからの利用

echoで出力することで設定ができます。

github/workflows/main.yml
- name: Enable problem matcher
  run: echo "::add-matcher::.github/textlint-matcher.json"

動作確認

「✔」が入っていた箇所もアノテーションに表示されるようになりました。

ただし、textlintのルールによっては表示の形式が変わるため、下記の17行目のようにうまく抽出できない箇所もありました。

運用するためにはもう少し改良が必要そうです。

注意

ワークフロー内で生成できるアノテーションの数には上限があるため、ここですべての指摘を表示しきるのは難しいかもしれません。私はここでアノテーションを利用しないreviewdogを利用する方針に切り替えました。

まとめ

textlintの指摘表示に取り組んでみました。が、Problem Matchersはもう少し出力の量が限られるユースケースの方がより良く利用できそうです。

ちなみにこの記事にはtextlintをかけていませんが、読みづらい箇所はありませんでしたか。明日以降もLIFULLアドベントカレンダーは続きますので、ご期待ください!