ローカルで Super-Linter を実行する

## はじめに

GitHub Actions で様々な静的解析を実行してくれる Super-Linter

https://github.com/github/super-linter

おかしなコードをマージされないように、プルリクエスト時に実行しています

パブリックリポジトリーでやっている分にはいくら実行しても無償なので問題ないのですが、

プライベートリポジトリーで無闇矢鱈に実行していると、無駄に料金がかかってしまいます

ローカルで先に実行してエラーが出ないことを確認しておけば、 GitHub Actions の実行を最小限に抑えることが可能です

というわけで、ローカルで Super-Linter を実行してみました

実装例のリポジトリーはこちら

https://github.com/RyoWakabayashi/ci-example

:::note
2023/9/4 最新版の記事を書きました

「ローカルで変更差分だけに Super-Linter を実行し、効率的に品質を上げる」
https://qiita.com/RyoWakabayashi/items/d9c9a5995820645b3037
:::

## 実行環境

- macOS Big Sur 11.5.2
- Docker 20.10.7

## コンテナ定義

Super-Linter は Docker コンテナで動いているため、 Docker さえあれば簡単に実行できます

公式のマニュアル

https://github.com/github/super-linter/blob/master/docs/run-linter-locally.md

実行時に毎回環境変数などを設定するのは面倒なので、 docker-compose で定義してしまいましょう

以下の内容で `super-linter/docker-compose.yml` を作ります

```yaml
---

version: '3'
services:
  linter:
    image: "github/super-linter"
    environment:
      - RUN_LOCAL=true
    volumes:
      - ../:/tmp/lint
```

ローカルで実行する場合、環境変数 `RUN_LOCAL` を　true にします

GitHub Actions での実行時は、実行時間短縮のため、 `VALIDATE_ALL_CODEBASE` を false にして、追加・変更があったコードだけを対象にしますが、

`RUN_LOCAL` を　true にすると強制的に `VALIDATE_ALL_CODEBASE` は true 扱いになり、全ファイルが対象になります

volumes で　 `../:/tmp/lint` とすることで、プロジェクトのルートディレクトリー配下をコンテナから参照します

## 対象外の指定

ローカルでの実行時は全ファイルを対象にするので、場合によっては結構時間がかかります

特に jscpd （コードの重複チェック）は見境なく全ファイルを対象にするため、画像ファイルなどは対象外にしたほうがいいかもしれません

環境変数 `FILTER_REGEX_EXCLUDE` に正規表現で指定することで、静的解析の対象外にすることができます

```yaml
    environment:
      - RUN_LOCAL=true
      - FILTER_REGEX_EXCLUDE=.*\.(jpg|jpeg|png|gif|csv|mp4)
```

## 実行

今回は `super-linter` 配下に docker-compose の定義を作ったので、定義ファイルを指定して起動します

```shell
$ docker-compose -f super-linter/docker-compose.yml up                                                           
Starting super-linter_linter_1 ... done
Attaching to super-linter_linter_1
linter_1  | --------------------------------------------------------------------------------
linter_1  | 
linter_1  |                               /@@#///////@@/(@//@%/(@.@(       @@
linter_1  |                           @@//////////////////////////////#*  @@@
linter_1  |                         @////@//(///////////@@@@@///@//@/@**//@@(
linter_1  |                       @///////@///////////////@@@@    (           @,
linter_1  |                      @/(&/@////////////////////                     @
linter_1  |                     @////////////////////////@@                      @
linter_1  |                   @%////////(//////////%/////&@            @@       *,@           ______________
linter_1  |              @@@@@/@/#/////(&//////////////////                       .@         /              \
linter_1  |         *@@@@@.    .%///(//@//////////////////&.   .@@,                 @%      / Don't mind me  \
linter_1  |       @@%           .&@&&/@.@//&/////(//////////    @@@@@@@@@         .. &@    / I'm just looking \
linter_1  |     @@%               @@@@@   @&/////////////////#   @/       V  @@/ ,@@@ @   <  for some trash... |
linter_1  | @@@%                   @@@@        .%@@@@//////#@ @   @@         @     .,.     \__________________/
linter_1  |                                           @@@/@(  (@@@@% @/\      %
linter_1  |                                            @@@@(    .     .@@/\   #
linter_1  |                                              @                  %@%
linter_1  | 
linter_1  | --------------------------------------------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   ---------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   --- GitHub Actions Multi Language Linter ----
linter_1  | 2021-08-23 01:37:48 [INFO]    - Image Creation Date:[]
linter_1  | 2021-08-23 01:37:48 [INFO]    - Image Revision:[efafcc9f1e2422444e1e48606d2535338018f235]
linter_1  | 2021-08-23 01:37:48 [INFO]    - Image Version:[efafcc9f1e2422444e1e48606d2535338018f235]
linter_1  | 2021-08-23 01:37:48 [INFO]   ---------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   ---------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   The Super-Linter source code can be found at:
linter_1  | 2021-08-23 01:37:48 [INFO]    - https://github.com/github/super-linter
linter_1  | 2021-08-23 01:37:48 [INFO]   ---------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   --------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   Gathering GitHub information...
linter_1  | 2021-08-23 01:37:48 [INFO]   NOTE: ENV VAR [RUN_LOCAL] has been set to:[true]
linter_1  | 2021-08-23 01:37:48 [INFO]   bypassing GitHub Actions variables...
linter_1  | 2021-08-23 01:37:48 [INFO]   Linting all files in mapped directory:[/tmp/lint]
linter_1  | 2021-08-23 01:37:48 [INFO]   Successfully found:[GITHUB_TOKEN]
linter_1  | 2021-08-23 01:37:48 [INFO]   --------------------------------------------
linter_1  | 2021-08-23 01:37:48 [INFO]   Gathering user validation information...
linter_1  | 2021-08-23 01:38:00 [INFO]   ---------------------------------
linter_1  | 2021-08-23 01:38:00 [INFO]   ------ File list to check: ------
linter_1  | 2021-08-23 01:38:00 [INFO]   ---------------------------------
linter_1  | 2021-08-23 01:38:02 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:38:02 [INFO]   Successfully gathered list of files...
linter_1  | 2021-08-23 01:38:02 [INFO]   
linter_1  | 2021-08-23 01:38:02 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:38:02 [INFO]   --------------

...

linter_1  | 2021-08-23 01:38:47 [NOTICE]   All file(s) linted successfully with no errors detected
linter_1  | 2021-08-23 01:38:47 [INFO]   ----------------------------------------------
super-linter_linter_1 exited with code 0
```

エラーがなければ `All file(s) linted successfully with no errors detected` と表示されます

エラーがある場合は以下のようにエラー箇所が表示されます

```shell
linter_1  | 2021-08-23 01:45:17 [INFO]   File:[/tmp/lint/README.md]
linter_1  | 2021-08-23 01:45:18 [ERROR]   Found errors in [markdownlint] linter!
linter_1  | 2021-08-23 01:45:18 [ERROR]   Error code: 1. Command output:
linter_1  | ------
linter_1  | /tmp/lint/README.md:45 MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "# 手動で静的解析を実行する場合は以下のコマンドを実行する"]
linter_1  | ------
linter_1  | 2021-08-23 01:45:18 [INFO]   ---------------------------

...

linter_1  | 2021-08-23 01:45:20 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:45:20 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:45:20 [INFO]   The script has completed
linter_1  | 2021-08-23 01:45:20 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:45:20 [INFO]   ----------------------------------------------
linter_1  | 2021-08-23 01:45:20 [ERROR]   ERRORS FOUND in MARKDOWN:[1]
linter_1  | 2021-08-23 01:45:20 [FATAL]   Exiting with errors found!
super-linter_linter_1 exited with code 1
```

## package.json への追加

package.json にスクリプトで追加しておけばもっと簡単に実行できます

```json
  "scripts": {
    "super_lint": "docker-compose -f super-linter/docker-compose.yml up"
  },
```

実行コマンド

```shell
npm run super_lint
```

## まとめ

静的解析エラーが出て、何度も GitHub Actions で動かしたくない場合、ローカル実行でエラーがなくなるまで試しましょう