ESLintの解析結果をGitLabのMRに連携する

以前の記事で、Violationsツールを使い、Javaプロジェクトの静的解析結果をGitLabのマージリクエストに連携した。

最近、Next.jsによる開発を行っており、エディタとして使用しているVSCode上ではリアルタイムでESLintによる解析をしているため、エラーがpushされることはほとんどない(あっても next build でエラーになる)が、警告は見過ごされることがある。

ViolationsがESLintに対応しているのは以前の記事の段階で確認しており、今回のプロジェクトでも、静的解析結果をGitLabのMRに連携してみたのでメモ。

環境

Violation Comments To GitLab Command Line v1.30.2。

Gitサーバーとしては、GitLab.comを使用。

Node.jsのパッケージマネージャーにはYarn v1.22.15を使用。

ツール概要

以前の記事を参照。

今回はGitLabのマージリクエスト(MR)連携を行うが、GitHubやBitbucketのプルリクエスト(PR)連携も可能。

これらのコマンドラインツールは、いずれも npx で実行可能。ただし、内部で利用されるViolations LibJavaライブラリのため、Java実行環境が必要。ないと Error: spawn java ENOENT といったエラーが発生する。

使用例

今回は、GitLab CI/CDによるパイプライン実行にて、ESLintの解析およびMR連携を行う。GitLabのCIランナーや、ESLintの設定等は省略。

GitLab設定

以前の記事と同様に、コメント用のユーザーを作成し、ユーザー設定 > アクセストークンから、apiスコープのパーソナルアクセストークンを作成。

GitLab CI/CD Variablesとして、作成したユーザーのアクセストークンを保存する。名前も前回と同様、 VIOLATION_API_TOKEN とした。

ESLint実行コマンドの作成

src/ 配下のJavaScriptまたはTypeScriptを対象として、解析結果をCheckstyle形式で lint/eslint.xml に出力する。ディレクトリが存在しなくても、ファイルごと作成してくれた。

yarn eslint --ext .js,.jsx,.ts,.tsx -o lint/eslint.xml -f checkstyle src/

GitLab MR連携コマンドの作成

Javaインストール済みの環境で、 npx violation-comments-to-gitlab-command-line にて実行可能。指定可能な引数はGitHubのREADME参照。

以前の記事で、Gradleにて設定したものと基本は同じ。

severitycomment-only-changed-contentsingle-file-comments 系の設定など、省略可能なものは省略。デフォルトで、差分のあるファイルにのみ、ディスカッション形式でコメントされるようになっていた。

コメントのテンプレートは文字列で指定する必要あり。複雑なテンプレートであれば、ファイルに記述して $(cat commentTemplate.txt) あたりで読み込んだほうがスッキリしそう。

npx violation-comments-to-gitlab-command-line \
  -gitlab-url "<GitLab URL>" \
  -project-id "<GitLab Project ID>" \
  -mr-iid "<Merge Request IID>" \
  -api-token "<API Token>" \
  -comment-template "**重大度**: {{violation.severity}}, **解析ツール**: {{violation.reporter}}{{#violation.rule}}, **ルール**: {{violation.rule}}{{/violation.rule}}\n\n**対象**: {{changedFile.filename}} \\# {{violation.startLine}}行目{{#violation.endLine}}~{{violation.endLine}}行目{{/violation.endLine}}\n\n**内容**: {{violation.message}}" \
  --violations "CHECKSTYLE" "lint" ".*/eslint.xml$" "ESLint"

ファイルパスの指定が上手くいかないことが多かったが、第2引数で指定したディレクトリ配下のファイルを再帰し、そのファイルパスが第3引数の正規表現パターン(java.util.regex.Pattern を使用)にマッチすれば処理対象として抽出している模様。第3引数の先頭には .*/ を指定しないと、まずマッチしない。

.gitlab-ci.yml設定

CI実行時のDockerイメージとして node:<version>-alpine を利用している。

Node.jsやYarnはインストール済みだが、Javaは未インストールされていないので、 before_script でインストールした。

コマンドで指定したGitLabのURL、プロジェクトID、MR IIDは、すべて対応する変数が存在するため、置き換えている。

また、 yarn eslint を実行した際に、解析結果にエラーが含まれると、exit codeが1となり、ジョブが中断してしまうため、 yarn eslint ... || true で、エラーが含まれる場合もexit codeを0にしている。

default:
  image: node:16.15-alpine

stages:
  - violation

violation:
  stage: violation
  allow_failure: true
  before_script:
    - apk update
    - apk --no-cache add openjdk17
    - yarn install
  script:
    - yarn eslint --ext .js,.jsx,.ts,.tsx -o lint/eslint.xml -f checkstyle src/ || true
    - |-
      npx violation-comments-to-gitlab-command-line \
        -gitlab-url "${CI_SERVER_URL}" \
        -project-id "${CI_PROJECT_ID}" \
        -mr-iid "${CI_MERGE_REQUEST_IID}" \
        -api-token "${VIOLATION_API_TOKEN}" \
        -comment-template "**重大度**: {{violation.severity}}, **解析ツール**: {{violation.reporter}}{{#violation.rule}}, **ルール**: {{violation.rule}}{{/violation.rule}}\n\n**対象**: {{changedFile.filename}} \\# {{violation.startLine}}行目{{#violation.endLine}}~{{violation.endLine}}行目{{/violation.endLine}}\n\n**内容**: {{violation.message}}" \
        --violations "CHECKSTYLE" "lint" ".*/eslint.xml$" "ESLint"
  rules:
    # マージリクエストの場合のみ実行
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
  tags:
    - violation

実行結果

以下のようなコメントが、解析結果に対応する変更行にコメントされるようになった。

振り返り

「なぜかわからないが出ている警告」みたいなものが、今回の作業でレビューしやすくなった。

早く修正したほうが、コストが少なく済むので、こうした警告を見落としにくくなったのはありがたい。

余談

久しぶりにGitLabのCI/CD設定を触ったら、デフォルトで Protect variable が有効になっていたのに気づかず。

保護されていないブランチだと、APIトークンが取れずに結構悩んだ。