CI 連携

bca をビルドパイプラインに組み込むためのレシピ集です。bca check コマンドは、現代の CI に必要なあらゆる出力形式(Checkstyle、SARIF、GitLab Code Climate JSON、clang/GCC 警告行、MSVC 警告行)を既に備えており、加えて人間向けの bca report markdown があります。このページは、ユーザーの 目的 から、適切なサブコマンド・フラグ・プラットフォーム連携の組み合わせへの統合マップです。

出力の選び方

以下のマトリクスは、よくある目的ごとに、対応する CI サーフェスへ出力を供給する bca の呼び出し方を対応付けたものです。実行可能な例はリンク先の各セクションにあります。

目的コマンド + フラグ
しきい値リグレッションに対するハードゲートbca check (自動検出された bca.toml のしきい値を使用)
既存コードベースでしきい値をラチェットするbca check --baseline .bca-baseline.toml (‡)
インライン PR アノテーション(GitHub)bca check … --report-format clang-warning --no-fail + GCC problem matcher
Code Scanning アラート(GitHub)bca check … --report-format sarif --no-fail + github/codeql-action/upload-sarif
マージリクエストウィジェット(GitLab Code Quality)bca check … --report-format code-climate --no-fail
Jenkins / SonarQube への取り込みbca check … --report-format checkstyle
人間可読な PR/MR コメントまたはダウンロード可能な成果物bca report -O markdown --top 20 --strip-prefix "$PWD/"
ダッシュボード向けの機械可読アーティファクトbca metrics --format json --output-dir ./out

(‡)既存の違反があるコードベースにしきい値を導入する際に推奨される導入パスです。ブートストラップ・リフレッシュ・リタイアのワークフローについてはベースラインのレシピを参照してください。

bca check の出力形式、終了コード(0 はクリーン、2 は違反、1 はツールエラー)、しきい値設定の完全なリファレンスは Check コマンドのページ にあります。Markdown レポートの形式については、Report コマンドのページ品質レポートのレシピを参照してください。

GitHub Actions

実際の動作例

big-code-analysis は、すべてのプッシュと PR で、以下のレシピを自身のソースに対して実行しています。ワークフローのソースである .github/workflows/pages.yml は、しきい値ゲート、ベースラインのラチェット、両方のレポート形式、そして GitHub Code Scanning への SARIF アップロードを、ワークスペース自身に対してエンドツーエンドで実行します。(SARIF アップロードは同一リポジトリのプッシュと PR でのみ実行されます。アップロードには書き込みスコープのトークンが必要なため、フォークからの PR ではスキップされます。これは clippy の SARIF ジョブとまったく同じ扱いです。)出力は本書と並んで GitHub Pages 上に置かれています:

以下のスニペットはそのまま自身のワークフローにコピーできます。記載されている bca のバージョンは、執筆時点で最新の公開リリースです。

リポジトリ内のワークフローは、ピン留めされたリリースをダウンロードするのではなく、現在のチェックアウトから bca をビルドしてインストールします。これは、.bca-baseline.toml が常にそれをゲートするのと同じ bca によって書かれるリポジトリにおいて、後述の GitHub Release からの bca のインストールで説明する CLI アーティファクトのスキーマ不整合という失敗モードを避けるためです。安定リリース系列を追跡する下流の採用者は、ピン留めされた tarball のパターンを使い続けるべきです。「チェックアウトからビルド」に切り替えるのは、あなたもバイナリと同時に CLI アーティファクトのスキーマを変更している場合だけにしてください。

しきい値ゲート、SARIF、clang-warning マッチャー

既存の 3 つのレシピ、すなわちハードなしきい値ゲート、Code Scanning への SARIF アップロード、インライン PR アノテーション用の clang-warning + GCC problem matcher は、Check コマンドのページにあります。ここで再実装せず、リンク先を利用してください。

最も高速で再現性の高いインストール方法は、このリポジトリの GitHub Releases にあるビルド済み tarball です。curl | sha256sum | tar の 1 手順だけで済み、Rust ツールチェーンを必要とせず、実行のたびにバイト単位で同一のバイナリが得られます。バージョンをキーにした actions/cache と組み合わせると、正常パスの再実行ではダウンロード自体をスキップできます:

CLI アーティファクトのスキーマ互換性。 ここでピン留めする BCA_VERSION は、リポジトリがコミットするすべての CLI アーティファクト — 最も重要なのは(独自の version フィールドを持つ).bca-baseline.tomlbca.toml マニフェスト — のスキーマバージョンをサポートしている必要があります。より新しい bca(より新しいスキーマバージョンを持つもの)が書いたベースラインファイルは、古い bca では読み込めず、ゲートは baseline version N is not supported by this bca というエラーで失敗します。main を追跡している場合や、より新しい bca でローカルにベースラインを再生成した場合は、新しいスキーマに対応したリリースへピン留めし直すか、ベースラインを書いたのと同じコミットを指す bcacargo install --git ビルドに切り替えてください(後述の cargo install の代替手段を参照)。互換性の契約は STABILITY.md に記録されています。

env:
  BCA_VERSION: "2.0.0"
  BCA_TARGET:  "x86_64-unknown-linux-gnu"
  # リリースの SHA256SUMS ファイルにある big-code-analysis-${BCA_VERSION}-${BCA_TARGET}.tar.gz の sha256。
  # BCA_VERSION と合わせて更新してください。
  BCA_SHA256:  "a205fff13108d0f8c679a062e352ba8468109c4adfdd8c9e3567cf5fcc99c3d5"

steps:
  # キャッシュキーには必ず BCA_SHA256(と BCA_TARGET)を含めてください。
  # キーに sha256 が含まれていないと、バージョンを上げずに公開チェックサムを
  # ローテーションした場合、キャッシュヒット時に古いバイナリが返され、
  # インストールステップの `sha256sum --check`(キャッシュミス時のみ実行)を
  # 黙ってバイパスしてしまいます。同じワークフローを複数の `runs-on` で
  # 実行する場合は、BCA_TARGET を含めることが重要です。
  - name: Cache bca binary
    id: bca-cache
    uses: actions/cache@v5
    with:
      path: ~/.local/bin/bca
      key: bca-${{ runner.os }}-${{ env.BCA_TARGET }}-${{ env.BCA_VERSION }}-${{ env.BCA_SHA256 }}

  - name: Install bca from GitHub Releases
    if: steps.bca-cache.outputs.cache-hit != 'true'
    run: |
      set -euo pipefail
      stage="big-code-analysis-${BCA_VERSION}-${BCA_TARGET}"
      tarball="${stage}.tar.gz"
      url="https://github.com/dekobon/big-code-analysis/releases/download/v${BCA_VERSION}/${tarball}"
      mkdir -p "$HOME/.local/bin"
      curl -fsSL --proto '=https' --tlsv1.2 -o "/tmp/${tarball}" "$url"
      echo "${BCA_SHA256}  /tmp/${tarball}" | sha256sum --check --strict -
      tar -xzf "/tmp/${tarball}" -C /tmp
      install -m 0755 "/tmp/${stage}/bca" "$HOME/.local/bin/bca"
      rm -rf "/tmp/${tarball}" "/tmp/${stage}"

  - name: Prepend ~/.local/bin to PATH
    run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"

利用可能な BCA_TARGET の値(runs-on に一致するものを選択してください): x86_64-unknown-linux-gnux86_64-unknown-linux-muslaarch64-unknown-linux-gnuaarch64-unknown-linux-muslaarch64-apple-darwinx86_64-pc-windows-msvcaarch64-pc-windows-msvc。Windows のアセットは .tar.gz ではなく .zip を使用します。bca-web バイナリは同じアーカイブ内で bca と一緒に配布されます。

代替手段: ビルド済みバイナリ対応アクション経由の cargo install

ランナーから github.com に到達できないが crates.io には到達できる場合(エアギャップ環境、カスタムミラー)、次の 2 つのアクションは、ビルド済みバイナリが公開されていないときに透過的に cargo install へフォールバックします — その代償はコールドパスでのコンパイル時間です。どちらも GitHub Releases のアセットと同じ crates.io リリースにピン留めするため、CLI アーティファクトのスキーマ互換性の警告はここでもそのまま当てはまります。

最新の crates.io リリースより先の bca が特に必要な場合(例えば、コミットされた .bca-baseline.toml のスキーマが、公開されているどの bca も理解できないほど新しい場合)は、tool: big-code-analysis-cli@<version>--version の形式を、ベースラインが生成された正確なコミットを対象とする cargo install --git https://github.com/dekobon/big-code-analysis --rev <SHA> --locked big-code-analysis-cli に置き換えてください。これはリポジトリ内の pages.yml ワークフローが(--path によりローカルチェックアウトに対して)行っていることですが、bca 自身のリポジトリのための意図的な回避策であり、下流の採用者に推奨されるデフォルトではありません。

# 選択肢 1: taiki-e/install-action
- name: Install bca
  uses: taiki-e/install-action@v2
  with:
    tool: big-code-analysis-cli@2.0.0
# 選択肢 2: cargo-binstall
- name: Install cargo-binstall
  uses: cargo-bins/cargo-binstall@main
- name: Install bca
  run: cargo binstall --no-confirm big-code-analysis-cli --version 2.0.0

いずれかのアクションがコンパイルにフォールバックした場合は、2 回目の実行が速くなるように cargo レジストリとインストール済みバイナリをキャッシュしてください:

- name: Cache cargo registry and bca binary
  uses: actions/cache@v5
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
      ~/.cargo/bin/bca
    # crates.io のリリースは不変なものとして公開されるため、ここでは
    # `<version>` のキーで十分です — ローテーションすべき sha256 はありません。
    # (上記の GitHub Releases インストールパスは事情が異なります。再公開された
    # リリースアセットはバージョンを共有するため、そのキャッシュキーには sha256 が必要です。)
    key: bca-${{ runner.os }}-2.0.0

レポートが実行間で再現可能であり続けるよう、特定のバージョン(crates.io に公開されている big-code-analysis-cli のリリースに一致するもの)にピン留めしてください。バージョンを固定しないインストールでは、メトリクス集計の変更が月曜日に「謎の CI フレーク」として現れます。

Markdown レポートを PR コメントとして投稿する

bca report markdown は PR/MR コメント専用に設計されています。安定したヘッダー構造、ホットスポットごとに 1 行のテーブル、そして --strip-prefix を渡せば短いパスが得られます。marocchino/sticky-pull-request-comment と組み合わせると、プッシュのたびに新しいコメントが積み重なるのではなく、単一のコメントが更新されます:

name: bca-pr-report
on:
  pull_request:
    branches: [main]
jobs:
  report:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - name: Install bca
        uses: taiki-e/install-action@v2
        with:
          tool: big-code-analysis-cli@2.0.0
      - name: Generate report
        run: |
          bca \
            report -O markdown \
            --paths "$PWD" \
            --top 20 \
            --strip-prefix "$PWD/" \
            --output report.md
      - name: Post or update PR comment
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          path: report.md
          header: bca-quality-report

同じ Markdown ファイルは、PR コメントに加えてワークフロー実行ページからもダウンロードできるようにしたい場合、ビルドアーティファクトとしてのアップロード(actions/upload-artifact@v7)にも適しています。

ベースライン / ラチェットパターン

bca check --baseline はネイティブのラチェットです。今日時点の違反をコミット済みの TOML ファイルに記録し、リグレッションと新規違反に対してのみ失敗させ、ファイルを時間をかけて縮小していきます。一度ブートストラップしてコミットし、CI をそのファイルに向けます:

# 開発者マシンで一度だけ実行します。両方のファイルをコミットしてください。
bca check --paths src/ \
    --write-baseline .bca-baseline.toml
git add bca.toml .bca-baseline.toml

このスニペットは src/ のみからブートストラップします — 単一クレートのライブラリに適した形です。複数クレートのワークスペースについては実際の動作例を参照してください。その .github/workflows/pages.yml は、ベンダリングされた文法、生成されたツリー、テストをカバーするチェックイン済みの除外セットである --exclude-from .bcaignore を使って、リポジトリ全体をスキャンします。

除外リストはワークフロー・レシピ・ブートストラップで共有してください。 除外セットをリポジトリルートの単一ファイル(.gitignore / .dockerignore に倣い、慣例として .bcaignore)に置き、すべての bca 呼び出しを --exclude-from .bcaignore でそのファイルに向けます。--exclude-from のパターンはインラインの --exclude <GLOB> フラグと和集合され、1 つの除外セットになります — --exclude は一回限りのアドホックな除外用に残してください。ファイル内の空行と # で始まるコメント行はスキップされます。パターンは --exclude 引数と同じ ./ プレフィックスの規約(ウォーカーが出力する形式)に従います。.bcaignore の編集は --write-baseline による更新とセットで行ってください — ベースラインのキーは、ウォーカーがどのファイルを訪れるかに敏感です。

- name: Threshold check with baseline
  run: |
    bca check --paths src/ \
        --baseline .bca-baseline.toml

リグレッションした関数(current value > baseline value)は引き続き失敗します。ベースラインにない新規の違反も引き続き失敗します。改善された関数は黙って通過し、次の --write-baseline による更新までベースラインに残ります。

Each surviving violation row is prefixed with a tag so a developer can tell at a glance whether they are looking at a brand-new offender or a known one that has worsened:

  • [new] — この関数 / メトリクスに対するベースラインエントリがありません。
  • [regr +N%] — 現在値が記録されたベースラインを N パーセント超過しています。特殊形式として、ベースライン値がゼロだった場合は [regr from 0]、リグレッションがベースラインの 100 倍を超える場合は [regr +>9999%]、現在値が NaN の場合は [regr NaN] となります。

The violation rows go to stdout; everything below goes to stderr. See Which stream for the full split.

After the per-violation rows, stderr carries a per-file rollup footer with the format <path>: <count> violations (worst: <metric> = <value> vs limit <limit> at L<start>), sorted by violation count descending. This is intended to be the first thing a reader looks at: which file has the most problems, and which metric is the loudest in that file. Pass --no-summary to suppress the footer for tooling that reads the merged streams.

対処しやすい失敗出力

以下の 4 つのサブセクションは、bca check の失敗出力を「違反行の羅列」から CI を意識した表現のスタックへと変えます。この PR のどのファイルがしきい値に触れたか(--since / --changed-only)、インラインのファイル diff アノテーション(--github-annotations)、レンダリングされたステップサマリーのダイジェスト($GITHUB_STEP_SUMMARY)、そしてコピー&ペーストしても安全な修復ブロックです。それぞれ独立しているので、CI サーフェスごとに自由に組み合わせられます。組み合わせた実例はこのグループの最後にあります。

差分対応モード(--since / --changed-only

PR やプッシュで開発者が最初に抱く疑問はたいてい、ツリー全体の違反リストではなく、この変更に含まれる自分のファイルのうちどれが しきい値に触れたのか、です。2 つのフラグがそれに答えます:

  • --since <ref> はファイル別フッターを、「Files in this range:」セクション(<ref>HEAD の間で変更されたファイルにある違反)と、それに続く「Other offenders:」(それ以外すべて)に分割します。違反ごとの行は変更されないため、grep を前提とした既存のツールはそのまま動作し続けます。
  • --changed-only は、変更されたファイル群の外にあるファイルの違反を完全に除外します。簡潔さが求められる PR ゲートに使用してください。
- uses: actions/checkout@v4
  with:
    # `--since origin/<base>` はマージベースを解決します。デフォルトの
    # `fetch-depth: 1` チェックアウトではその ref に到達できません。`0` を
    # 指定すると全履歴を取得するため、差分ベースが解決できます。
    fetch-depth: 0
- name: 差分対応フッター付きのしきい値チェック
  run: |
    bca check --paths . --exclude-from .bcaignore \
        --baseline .bca-baseline.toml \
        --since "origin/${{ github.base_ref }}"

--since を省略すると、bca は次の優先順位で環境から差分ベースを自動検出します。

  1. BCA_DIFF_BASE — 明示的にオーバーライドするための手段です。ローカルシェルや GHA 以外の CI ランナーから自動検出を模倣するために使用します。
  2. GITHUB_BASE_REF — GitHub Actions が pull_request イベントで設定します。origin/<value> に展開されます。対応する git fetch はランナー側の責任です。
  3. GITHUB_EVENT_BEFORE — GitHub Actions が push イベントで、プッシュ前の HEAD の SHA に設定します。すべてゼロの SHA(強制プッシュや新規ブランチ)はシグナルなしとして扱われます。

自動検出の失敗(git がない、ref が解決できない、git チェックアウトではない)は、--changed-only なしでは致命的ではありません。bca は警告を表示し、従来どおりのツリー全体のフッターにフォールバックします。--changed-only を指定した場合、同じ失敗は致命的になります。設定を誤った CI がすべての違反を抑制して黙って合格扱いになることを防ぐためです。

"Files in this range:" バナーには、解決されたベースとそれを導いたシグナルが表示されるため、CI ログの読者はゲートが期待どおりの ref を捕捉したことを確認できます。

Files in this range (diff base: origin/main via GITHUB_BASE_REF):
./src/a.rs: 1 violation (worst: cyclomatic = 11 vs limit 2 at L1)

Other offenders:
./src/b.rs: 1 violation (worst: cyclomatic = 11 vs limit 2 at L1)

これは bca diff-baseline とは異なります。bca diff-baseline はディスク上の 2 つのパス間でベースラインファイルを比較し、追加・削除・悪化・改善されたエントリを報告します。--since は 2 つの git ref 間でソースファイルを比較します。

GitHub Actions のインラインアノテーション(--github-annotations

GHA の UI は ::error file=…,line=…,title=…::msg ワークフローコマンドをファイル差分ビュー上のインラインアノテーションとして表示します。生のジョブログをスクロールするよりはるかに見つけやすい方法です。bca check は、3 状態の --github-annotations <auto|always|never> に従って違反ごとに 1 件ずつ出力します。auto(デフォルト)は $GITHUB_ACTIONS == "true"(すべての GHA ワークフローステップで設定されます)のときに有効化し、always は常に有効にし、never はステップ内でも抑制します(ワークフローが bca check を 2 回実行し、片方の実行だけからアノテーションを得たい場合に便利です)。引数なしの --github-annotationsalways を意味します。

アノテーションは既存の違反ごとの人間向けストリームに重ねて出力され、両方が出力されます。GitHub のステップあたり 10 エラーという UI クォータを使い切らないよう、アノテーションはメトリクスごとに 10 件までに制限され、超過分は 1 行の ::error::N more <metric> violations not shown にまとめられるため、件数は常に確認できます。

- name: インラインアノテーション付きのしきい値チェック
  run: |
    bca check --paths . --exclude-from .bcaignore \
        --baseline .bca-baseline.toml
  # `--github-annotations` フラグは不要です — GHA では自動的に有効になります。

上記の --since と組み合わせると、アノテーションが違反者リスト全体ではなく PR 内のファイルを指すようになります。

ステップサマリーの Markdown ダイジェスト($GITHUB_STEP_SUMMARY

GitHub Actions は $GITHUB_STEP_SUMMARY を公開しています。これは Markdown ファイルへのパスで、内容を書き込むとジョブ UI にそのステップのサマリービューとして表示されます。bca check は、この環境変数が設定されているとき、または --summary-file <path> が明示的に渡されたときに、ファイル別ロールアップ表、メトリクス別の件数内訳、value / limit 比による上位 10 件の違反者を含むダイジェストを追記します。--summary-file never は、$GITHUB_STEP_SUMMARY が設定されていてもダイジェストを抑制します。

ダイジェストは HTML コメントマーカー(<!-- bca-step-summary-begin --> / <!-- bca-step-summary-end -->)で囲まれているため、リトライされたステップは前のブロックを(積み重ねるのではなく)置き換えます。3 回リトライしても、最新のダイジェストがちょうど 1 つに収束します。マーカーの外側の内容(同じステップ内で先に他のツールが書き込んだサマリーなど)は保持されます。

- name: ステップサマリーダイジェスト付きのしきい値チェック
  run: |
    bca check --paths . --exclude-from .bcaignore \
        --baseline .bca-baseline.toml
  # フラグは不要です — GHA では `$GITHUB_STEP_SUMMARY` が自動的に設定されます。

ローカルユーザーは --summary-file <path> でダイジェストを任意の Markdown ファイルに書き出せます。入力が空(クリーンな実行)でも "✓ No threshold violations." ブロックが書き込まれるため、ステップサマリーからゲートが実行されたことを明確に確認できます。

修復フッター(常時有効)

ゲートが違反を検出すると、bca check は stderr に(さらに上記のステップサマリーダイジェスト内にも)末尾の --- next steps --- ブロックを出力します。

--- next steps ---
* Detailed reports: bca-reports artifact at https://github.com/<owner>/<repo>/actions/runs/<run-id>
* To refresh baseline: bca check --paths . --exclude-from .bcaignore --write-baseline .bca-baseline.toml
* Adoption guide: https://dekobon.github.io/big-code-analysis/recipes/baselines.html

このベースライン更新用の呼び出しは、ゲートで解決された --paths--exclude--exclude-from--config--baseline をそのまま反映するため、失敗した CI ログを初めて読む人でもそのままコピー&ペーストできます。アーティファクト URL は $GITHUB_REPOSITORY$GITHUB_RUN_ID の両方が存在するとき(GHA では常に真)に導出されます。ローカル実行では指し示すべきアップロードが存在しないため、代わりに bca report を実行して詳細ビューをローカルで確認することを提案します。

Suppress the block with --no-remediation for tooling that reads the merged streams; a plain bca check | ... pipeline never sees it.

集中的なリファクタリングの後に更新します。

bca check --paths src/ \
    --write-baseline .bca-baseline.toml
git diff .bca-baseline.toml   # ファイルは縮小していくはずです

変更のないツリーに対して --write-baseline を 2 回実行するとバイト単位で同一の出力が生成されるため、偽の差分は違反者が実際に変化したときにのみ現れます。採用フローの全体、PR レビューのヒューリスティクス、抑制の合成規則についてはベースラインのレシピを参照してください。

すべてを組み合わせる

上記の 4 つのフラグは組み合わせて使えます。PR ゲートのワークフローで推奨される呼び出しは次のとおりです。

- uses: actions/checkout@v4
  with:
    # `--since origin/<base>` はマージベースを解決します。デフォルトの
    # `fetch-depth: 1` ではその ref に到達できません。`0` を指定すると
    # 全履歴を取得するため、差分が解決できます。
    fetch-depth: 0

- name: しきい値ゲート(差分対応 + GHA UX)
  run: |
    bca check --paths . --exclude-from .bcaignore \
        --baseline .bca-baseline.toml \
        --since "origin/${{ github.base_ref }}"
  # `--github-annotations` や `--summary-file` フラグは不要です。
  # どちらも `$GITHUB_ACTIONS == "true"` と `$GITHUB_STEP_SUMMARY` から
  # 自動的に有効になります。末尾の修復ブロックも自動的に
  # 出力されます。

失敗した PR で得られるもの:

  1. Per-violation rows on stdout — same shape as the legacy gate, so existing grep tooling keeps working.
  2. ファイル別ロールアップフッターFiles in this range:(PR で変更されたファイル)が Other offenders: の前に列挙されるため、開発者は自分の変更分を最初に確認できます。
  3. インライン GHA アノテーション — ファイル差分ビュー上に表示され、メトリクスごとに 10 件で打ち切られ、超過分はまとめて表示されます。
  4. ステップサマリーパネル — レンダリングされた Markdown ダイジェスト(ファイル別ロールアップ、メトリクス別内訳、比率による上位 10 件の違反者)を表示します。
  5. 末尾の修復ブロック — アーティファクト名を示し、そのまま使える --write-baseline 更新コマンドを表示し、ベースラインのレシピへリンクします。

調整ノブ:

フラグ効果デフォルト
--since <ref>フッターを分割。省略時は環境から自動検出オフ。BCA_DIFF_BASE / GITHUB_BASE_REF / GITHUB_EVENT_BEFORE により自動検出
--changed-only差分外の違反を完全に除外オフ
--github-annotations <auto\|always\|never>::error file=…::msg ワークフローコマンドを出力(引数なしのフラグ = alwaysauto$GITHUB_ACTIONS == "true" のとき有効化。never で無効化
--summary-file <path\|auto\|never>Markdown ダイジェストを追記。never で無効化auto$GITHUB_STEP_SUMMARY を検出
--no-remediation末尾の --- next steps --- ブロックを抑止失敗時にブロックを出力

GHA の外で bca check を実行するローカルユーザーにとって、デフォルトの挙動に変化はありません。環境からのシグナルなしに自動有効化される機能は 4 つのうち 1 つもありません。GHA での体験をローカルでプレビューするには次のようにします。

GITHUB_ACTIONS=true GITHUB_STEP_SUMMARY=/tmp/bca-summary.md \
  BCA_DIFF_BASE=main \
  bca check --paths . --exclude-from .bcaignore \
      --baseline .bca-baseline.toml
cat /tmp/bca-summary.md

GHA 以外の CI(GitLab、Buildkite、Jenkins)では、ランナーが公開する環境変数を設定する(またはフラグを明示的に渡す)ことで、同じ出力経路が動作します。

マージベースに対する違反者数の差分(暫定策)

(ポリシー上の理由などで)ベースラインファイルをコミットできないチーム向けのより粗い近似として、2 つの Checkstyle ドキュメント(マージベース上のものと PR ヘッド上のもの)の <error> 要素を数え、件数が増えたら失敗させる方法があります。

- name: マージベースに対する違反者の差分を計算
  run: |
    set -euo pipefail
    BASE="$(git merge-base origin/main HEAD)"
    git worktree add /tmp/base "$BASE"

    bca check --paths /tmp/base \
        --report-format checkstyle \
        --output /tmp/base.xml \
        --no-fail
    BASE_COUNT=$(grep -c "<error" /tmp/base.xml || true)

    bca check --paths "$PWD" \
        --report-format checkstyle \
        --output /tmp/head.xml \
        --no-fail
    HEAD_COUNT=$(grep -c "<error" /tmp/head.xml || true)

    echo "Offenders: base=$BASE_COUNT head=$HEAD_COUNT"
    if [ "$HEAD_COUNT" -gt "$BASE_COUNT" ]; then
      echo "::error::Offender count grew from $BASE_COUNT to $HEAD_COUNT"
      exit 1
    fi

これは違反の件数を数えるだけで、その同一性は追跡しません。違反している関数の名前を変えてもリグレッションとして検出されず、ある違反者を改善しつつ別の違反者を悪化させると差し引きゼロになります。上記のネイティブなベースラインフローの方が厳密に高精度であり、推奨されるアプローチです。

セルフスキャンしきい値ゲート(CI ゲートのローカルミラー)

CI のしきい値ゲートはプッシュ後にしか作動しないため、リファクタリングが気付かないうちにメトリクスを限界値の先へ押し出していた場合には手遅れです。big-code-analysis リポジトリの Makefile は、CI ゲート(.github/workflows/pages.ymlThreshold gate ステップ)をローカルでミラーする 4 つのターゲットを公開し、さらに各限界値の 95% に第 2 の段階を追加して、ハードゲートが作動する 1〜2 コミット前に接近を検出できるようにしています。

make self-scan                            # ハードゲート。bca.toml のしきい値の 100%
make self-scan-headroom                   # ソフトゲート。デフォルト 95%(BCA_HEADROOM)
make self-scan-write-baseline             # ハードしきい値でベースラインを更新
make self-scan-write-baseline-headroom    # ソフトしきい値でベースラインを更新

パス選択、.bcaignore の除外セット、関数ごとのしきい値、循環的複雑度の ? ポリシー、ベースラインファイルは、すべてリポジトリルートの bca.toml マニフェストにあり、bca はこれを自動的に発見します。ハード段階は CI が実行するものとまったく同じです。展開すると、引数なしのチェック(パス / しきい値 / ベースラインのフラグなし — マニフェストが供給します)になります。

cargo run --quiet --release -p big-code-analysis-cli -- check

両段階は同じ bca.toml のしきい値と同じ .bca-baseline.toml を使用します。ソフト段階は、各しきい値に BCA_HEADROOM を掛けた上でハード段階のレシピを実行するだけです。どちらもクリーンなら 0、しきい値違反があれば 2、ツールエラーなら 1 で終了します。ソフト段階は助言的なものではなく本物のゲートなので、make self-scan-headroom|| true で包まないでください。2 つのゲートターゲット(self-scanself-scan-headroom)は make pre-commitmake ci.pre-commit-config.yaml に組み込まれています。これらのチェーンはハード段階をソフト段階より先に実行するため、真のリグレッションは常に限界値接近の警告より先に報告されます。2 つの write-baseline ターゲットは副作用を伴うため、意図的に組み込まれていません。

BCA_HEADROOM=0.90 make self-scan-headroom は帯域を広げ、BCA_HEADROOM=0.99 は最後の 1% まで狭めます。ソフト段階が作動したときは、make self-scan-write-baseline-headroom(すべての違反者をスケール後のしきい値で記録します — ハード段階の違反者の厳密な上位集合です)でベースラインに違反者を取り込みます。

このパターン(CI をミラーするハード段階 + 早期警告帯としてのソフト段階、どちらも同じベースラインでラチェット)はプロジェクトに依存しません。ローカルしきい値ゲートのレシピには、基礎となる原則、そのまま使える Makefile / just / package.json のスケルトン、しきい値をスケールするヘルパースクリプトが記載されており、同じワークフローを自分のリポジトリでも採用できます。汎用レシピは上記の Makefile と同じ BCA_* 環境変数名を使うため、BCA_HEADROOM=0.90 のようなオーバーライドは両方でまったく同じように機能します。

GitLab CI

完全な .gitlab-ci.yml の例

以下のジョブは bca をインストールし、しきい値チェックを実行して Code Climate JSON(MR の Code Quality ウィジェット用)、Checkstyle XML、Markdown レポートを生成し、それらをアーティファクトとしてアップロードします。

GitHub Actions セクションの CLI アーティファクトのスキーマ互換性に関する注意がここでも当てはまります。BCA_VERSION のピンは、リポジトリにコミットするすべての CLI アーティファクトのスキーマバージョンをカバーしなければなりません。

stages:
  - quality

variables:
  BCA_VERSION: "2.0.0"  # 公開済みの big-code-analysis-cli リリースにピン留め
  BCA_TARGET:  "x86_64-unknown-linux-gnu"
  # リリースの SHA256SUMS ファイルに記載された
  # big-code-analysis-${BCA_VERSION}-${BCA_TARGET}.tar.gz の sha256。BCA_VERSION と一緒に更新します。
  BCA_SHA256:  "a205fff13108d0f8c679a062e352ba8468109c4adfdd8c9e3567cf5fcc99c3d5"

bca-quality:
  stage: quality
  image: debian:stable-slim
  cache:
    # GitHub Actions のスニペットと同じキー形式です。BCA_VERSION を
    # 上げるとキャッシュは自動的に無効化されます。
    key: "bca-$BCA_VERSION"
    paths:
      - .cache/bca/
  before_script:
    - apt-get update -qq && apt-get install -y --no-install-recommends ca-certificates curl tar
    - |
      set -euo pipefail
      install -d "$CI_PROJECT_DIR/.cache/bca" "$HOME/.local/bin"
      if [ ! -x "$CI_PROJECT_DIR/.cache/bca/bca" ]; then
        stage="big-code-analysis-${BCA_VERSION}-${BCA_TARGET}"
        tarball="${stage}.tar.gz"
        url="https://github.com/dekobon/big-code-analysis/releases/download/v${BCA_VERSION}/${tarball}"
        curl -fsSL --proto '=https' --tlsv1.2 -o "/tmp/${tarball}" "$url"
        echo "${BCA_SHA256}  /tmp/${tarball}" | sha256sum --check --strict -
        tar -xzf "/tmp/${tarball}" -C /tmp
        install -m 0755 "/tmp/${stage}/bca" "$CI_PROJECT_DIR/.cache/bca/bca"
        rm -rf "/tmp/${tarball}" "/tmp/${stage}"
      fi
      install -m 0755 "$CI_PROJECT_DIR/.cache/bca/bca" "$HOME/.local/bin/bca"
      export PATH="$HOME/.local/bin:$PATH"
  script:
    - bca
        check
        --paths "$PWD"
        --report-format code-climate
        --output gl-code-quality-report.json
        --no-fail
    - bca
        check
        --paths "$PWD"
        --report-format checkstyle
        --output bca-checkstyle.xml
        --no-fail
    - bca
        report -O markdown
        --paths "$PWD"
        --top 20
        --strip-prefix "$PWD/"
        --output bca-report.md
    # しきい値ゲートは別に実行するため、上記のアーティファクトは失敗時にも
    # 公開されます。終了コード 2 = 少なくとも 1 件のしきい値超過。
    - bca check --paths "$PWD"
  artifacts:
    when: always
    reports:
      codequality: gl-code-quality-report.json
    paths:
      - gl-code-quality-report.json
      - bca-checkstyle.xml
      - bca-report.md

この例に関する補足です。

  • 最初の 2 回の bca check … --no-fail 呼び出しはアーティファクト用に違反者を収集します。最後の bca check--no-fail なし)が合否を決めるゲートです。3 回の実行はすべて同じしきい値設定を使うため、アーティファクトは常にゲートの判定と一致します。
  • artifacts:when: always により、パイプラインが赤のときでも — まさに最も必要になる場面ですが — すべてのアーティファクトをダウンロードできます。
  • artifacts:reports:codequality は Code Climate JSON を GitLab の MR Code Quality ウィジェットに直接接続します。フィールドごとの意味は下記の Code Quality ウィジェットのセクションを参照してください。

GitLab Code Quality ウィジェット

GitLab の第一級の Code Quality 体験(MR 差分上のインライン指摘、MR 概要ページのサマリー)は Code Climate JSON を読み取ります。bca check--report-format code-climate によりこれをネイティブに出力するため、統合は 1 行で済みます。

code_quality:
  stage: quality
  script:
    - bca check --paths "$CI_PROJECT_DIR"
          --report-format code-climate
          --output gl-code-quality-report.json
          --no-fail
  artifacts:
    when: always
    reports:
      codequality: gl-code-quality-report.json
    paths:
      - gl-code-quality-report.json

重大度の帯は、各メトリクスが設定されたしきい値をどれだけ超えているか(value / limit 比。値が低いほど悪い保守容易性指数系では反転)から導出されます: ≤ 1.5×minor≤ 2×major≤ 4×critical> 4×blocker。ウィジェットは fingerprint で検出結果を重複排除します。bcapath \0 function \0 metric を(行番号も値も含めずに)ハッシュ化するため、変更による行ずれを生き延びた違反は、パイプライン実行をまたいで同じウィジェットエントリに集約されます。

生成されたレポートをローカルで検証するには次のようにします。

jq 'all(.[]; has("description") and has("check_name")
     and has("fingerprint") and has("severity")
     and has("location"))' gl-code-quality-report.json
# → true
jq '[.[] | .severity] | unique' gl-code-quality-report.json
# → ["info","minor","major","critical","blocker"] の部分集合

Markdown レポートを MR 限定コメントとして投稿

Markdown レポートを MR ノートとして添付する(GitHub の PR コメントレシピの GitLab 版)には、プロジェクトアクセストークンと Notes API を使用します。

bca-mr-comment:
  stage: quality
  image: alpine:3
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  needs: ["bca-quality"]
  before_script:
    - apk add --no-cache curl jq
  script:
    - |
      BODY=$(jq -Rs '.' < bca-report.md)
      curl --fail --silent --show-error \
        --request POST \
        --header "PRIVATE-TOKEN: $CI_BCA_BOT_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"body\": $BODY}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"

CI_BCA_BOT_TOKENapi スコープを持つプロジェクトアクセストークンです。このジョブは bca-quality に依存するため、実行前に Markdown アーティファクトが揃っています。

Jenkins / SonarQube

Jenkins(Warnings Next Generation プラグイン経由)と SonarQube(Generic Issue インポーター経由)は、どちらも Checkstyle 4.3 XML を直接読み取ります。同じ呼び出しが両方に使えます。

bca check --paths src/ \
    --report-format checkstyle \
    --output report.checkstyle.xml

report.checkstyle.xml を、既存の Jenkins の Record Issues / SonarQube の External Issues ステップに接続してください。Checkstyle ライターは違反者がいないときも空の(整形式の)ドキュメントを出力するため、どちらのツールもクリーンな実行を特別扱いする必要はありません。ライターのスキーマの詳細は check コマンドのページを参照してください。

汎用的な CI ガイダンス

以下はプロバイダーを問わず当てはまります。

  • bca は特定のバージョンにピン留めしてください。 cargo install --versioncargo binstall --version はどちらも big-code-analysis-cli の公開クレートバージョンを受け付けます。バージョンを固定しないインストールでは、メトリクス計上の変更が月曜日に「不可解な CI の揺らぎ」として現れます。CLI アーティファクトのスキーマ(ベースライン、しきい値)がリポジトリにコミットしているファイルと一致するバージョンにピン留めしてください — インストールセクションのスキーマ互換性に関する注意を参照してください。
  • --jobs のデフォルトは有効 CPU 数です。 このフラグは available_parallelism() に従います — Linux では cgroup / cpuset / クォータを考慮し、macOS / Windows では OS の CPU 数を使います — ので、CI ランナーであらゆるレシピに --jobs "$(nproc)" を通す必要はもうありません。--jobs 1 はデフォルトではなく、デバッグ用のノブとして残っています。
  • bca report markdown には常に --strip-prefix "$PWD/" を渡してください。 そうすればパス列は、ワークスペースパスが異なるランナー間でも同一になります。これがないと、2 つのレポートの差分は /home/runner/work/.../builds/group/project/... のノイズに支配されます。
  • bca.toml はリポジトリルートに置いてくださいCargo.toml / pyproject.toml / package.json と同じ場所です。bca はこれを自動的に発見するため、引数なしの bca check がコミット済みのしきい値、パス、ベースラインを読み込みます。これをソースコードとして扱い、しきい値の緩和はコードレビューで審査してください。
  • 終了コードの契約。 bca check は、クリーンなら 0、しきい値違反があれば 2、ツールエラー(不正な設定、未知のメトリクス、読み取れないパス)なら 1 で終了します。1 をツールエラー専用に予約することで、CI は「関数が複雑になりすぎた」と「アナライザーがクラッシュした」を区別できます。--exit-codes=tiered を渡す(または bca.toml[check] exit_codes = "tiered" を設定する)と、違反の場合を重大度で分割できます: 2 は新規違反者のみ、3 はリグレッションのみ、4 は両方、5 はハード限界も同時に超えた --tier=soft 違反です。tiered の終了コードはオプトインで、デフォルトは 0/1/2 のままです。すべての失敗状態は非ゼロのままなので、exit != 0 → fail 型のラッパーはそのまま機能します — 明示的に $? -eq 2 を検査するツールだけが 2-5 に広げる必要があります。
  • ソース内の抑制マーカーを尊重し、監査には --no-suppress を使ってください。 デフォルトの bca checkbca: suppress / bca: suppress-file マーカーを尊重します。--no-suppress を渡すとそれらを無視するため、監査者は生の違反者リストを確認できます。