🎉

golangci-lintの実行時間を短縮!PR差分があったディレクトリだけをlint対象にする方法

に公開

はじめに

GitHub ActionsでPRのたびにgolangci-lintを実行していますが、リポジトリが大きくなるにつれて実行時間が長くなってしまいます。
全ファイルをチェックするのは非効率的ですし、CIの待ち時間がもったいないなと感じています。

そこで、PRの差分ディレクトリだけに対してgolangci-lintを実行する方法を検討し、実際に導入してみた結果をまとめます。

問題:全ファイルチェックの課題

私が担当しているGoプロジェクトでは、以下のような問題に直面していました。

  • CI実行時間の長期化により、全ファイルのlintチェックに10分以上かかる
  • PRマージまでの待ち時間が毎回発生する
  • リソースの無駄遣いが発生し、変更のない既存コードも毎回チェックされる

これらの問題を解決するため、差分実行の仕組みを導入することにしました。

前提条件・環境

  • GitHub Actionsを使用したCI環境
  • golangci-lint-actionを使用してlintを実行
  • Goプロジェクトのディレクトリ構成には特に依存しない

調査・実装プロセス

1. 差分取得の検討

まず、PRの差分を取得する方法を調査しました。GitHub Actionsではgithub.shaを使って、以下のような方法で差分を取得できます。

git diff --name-only --diff-filter=ACMRT ${{ github.sha }}^ ${{ github.sha }}

このコマンドで、以下のような結果が得られます。

  • --name-only: ファイル名のみ出力
  • --diff-filter=ACMRT: 特定の変更タイプのファイルのみを対象とする
    削除されたファイル(D: Deleted)は対象外としています。これは、削除されたファイルに対してlintを実行する必要がないためです。

2. Goファイルの絞り込み

次に、差分の中からGoファイルだけを抽出する必要があります。

git diff --name-only --diff-filter=ACMRT ${{ github.sha }}^ ${{ github.sha }} | grep .go$

3. ディレクトリ単位でのlint実行

golangci-lintはファイル単位でも実行できるので、ファイルを抽出しても良かったのですが、特定のディレクトリだけlint対象外にしたいということが出来るようにしています。
そのため、ディレクトリ単位での実行をしています。
(grep -vを使えば簡単に特定ディレクトリを除外できます。)

xargs -I{} dirname {} | sort | uniq | xargs -I{} echo ./{}

4. 最終的な実装

これらを組み合わせて、以下のようなサンプルのGitHub Actionsワークフローを作成しました。

name: Lint Check

on:
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 2  

    - name: Setup Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.24'

    - name: Run Diff golangci-lint
      uses: golangci/golangci-lint-action@v8.0.0
      with:
        version: v2.1.0
        args: -v --timeout 15m00s `git diff --name-only --diff-filter=ACMRT ${{ github.sha }}^ ${{ github.sha }} | grep .go$ | xargs -I{} dirname {} | sort | uniq | xargs -I{} echo ./{}`
      timeout-minutes: 20

実行結果と効果

パフォーマンス改善

導入前後でのCI実行時間を比較しました。

  • 導入前の実行時間は平均15分(全ファイルチェック)
  • 導入後の実行時間は平均5分(差分があったディレクトリのみチェック)

実際の使用感

  • PR作成からマージまでの時間が短縮される
  • 長いCI待ち時間のストレスから解放される

まとめ

PRの差分ディレクトリだけでgolangci-lintを実行することで、以下のような効果を得られました。

  • 実行時間の短縮
  • 開発効率の向上
  • CIコストの削減

特に大規模なGoプロジェクトでは、この手法の効果は大きいです。
またlintだけではなく、テストも差分実行をしているので別の記事で差分テストの方法もまとめる予定です。

参考資料

Discussion