開発効率化

GitHub Code Quality REST API入門——FindingsをFirestoreへ同期する

GitHub Code Quality Findings REST APIのPublic Previewを踏まえ、Next.js + Firestoreで品質指摘を集計し、PR品質ゲートへつなげる実践手順を解説します。

2026年6月29日
GitHub Code QualityGitHub ActionsFirestoreNext.jsTypeScript
GitHub Code Quality REST API入門——FindingsをFirestoreへ同期する

はじめに

Next.jsのPRレビューで、こんな状態になっていませんか?

  • PR上ではCode Qualityの指摘を見るが、長期傾向を追えていない
  • src/libapp/apicomponents のどこに品質負債が多いか説明しにくい
  • PR品質ゲートを強めたいが、既存負債まで一気に止めるのは怖い
  • AIエージェントに修正を任せる前に、対象を優先順位付けしたい

2026年6月23日、GitHubは Code Quality Findings REST API をPublic Previewとして公開しました。リポジトリ単位のFinding一覧と、単一Findingの詳細をREST APIで取得できるようになったため、GitHub UIの外で品質指摘を集計できます。

本記事では、架空の業務管理SaaS「KensaBoard」を題材に、Next.js App Router + Firestore + GitHub Actions + TypeScriptでCode Quality findingsを同期し、PR品質ゲートへつなげる手順を解説します。

参考にした一次情報は次の通りです。

何が変わったのか

Code Qualityは、GitHub TeamまたはGitHub Enterprise Cloudのorganization-owned repository向けの品質分析機能です。公式ドキュメントでは、2026年7月20日にGAとなり、Public Preview中はGitHub Actions minutesを消費し、GA後は追加料金が発生すると説明されています。

今回のREST API追加で、次のような運用が組みやすくなりました。

観点内容KensaBoardでの使い方
一覧取得GET /repos/{owner}/{repo}/code-quality/findings未解決Findingを日次同期
詳細取得GET /repos/{owner}/{repo}/code-quality/findings/{finding_number}修正IssueやAI依頼の材料にする
フィルタstate=open / state=dismissed新規負債と対応済みを分ける
ページングper_pageafter / before100件ずつ安全に取得する
権限Code qualityのread権限GitHub Appかfine-grained tokenで管理

事前準備

まず対象リポジトリでCode Qualityを有効化します。GitHub Docsでは、リポジトリの Settings > Code quality から有効化でき、organization単位の有効化手順も案内されています。

API認証では、classic PATならprivate/public repositoryに repo scope、public repositoryだけなら public_repo scopeが必要です。fine-grained tokenやGitHub App installation tokenでは、repository permissionとして Code quality: read を付与します。

実務では、ブラウザからGitHub APIを直接叩かない構成にします。KensaBoardでは、管理者限定のNext.js Route HandlerだけがGitHub APIトークンを持ち、GitHub Actionsのスケジュール実行からそのRoute Handlerを呼びます。

ハンズオン1: Firestoreの保存形式を決める

GitHub APIのレスポンスを丸ごと保存すると、画面や集計がAPI仕様に引きずられます。まずは使う項目だけを正規化します。

// src/types/codeQuality.ts
export type CodeQualityFinding = {
  repository: string;
  number: number;
  state: "open" | "dismissed";
  ruleId: string;
  ruleTitle: string;
  severity: string;
  category: string;
  path: string;
  startLine: number;
  message: string;
  createdAt: string;
  syncedAt: string;
};

Firestoreには codeQualityFindings コレクションを作り、ドキュメントIDは owner_repo_number のように決定的にします。同じFindingを毎日同期しても重複せず、最新状態だけを上書きできます。

フィールド用途
repository複数リポジトリを横断集計する
ruleId多発しているルールを見つける
severityPRブロック対象を決める
pathapp/apisrc/lib など責務別に見る

ハンズオン2: Next.jsでFindingsを同期する

次に、Code Quality findingsを取得するRoute Handlerを作ります。GitHub DocsのREST API例に合わせ、Accept: application/vnd.github+jsonX-GitHub-Api-Version: 2026-03-10 を付けます。

// src/app/api/admin/code-quality/sync/route.ts
import { FieldValue } from "firebase-admin/firestore";
import { adminDb } from "@/lib/firebase/admin";

type GitHubFinding = {
  number: number;
  state: "open" | "dismissed";
  rule: { id: string; title: string; severity: string; category: string };
  location: { path: string; start_line: number };
  message: { text: string };
  created_at: string;
};

type SyncRequest = {
  owner: string;
  repo: string;
};

export async function POST(request: Request) {
  const body = (await request.json()) as SyncRequest;
  const token = process.env.GITHUB_CODE_QUALITY_TOKEN;

  if (!token) {
    return Response.json({ error: "token is not configured" }, { status: 500 });
  }

  const url = new URL(
    `https://api.github.com/repos/${body.owner}/${body.repo}/code-quality/findings`,
  );
  url.searchParams.set("state", "open");
  url.searchParams.set("per_page", "100");

  const response = await fetch(url, {
    headers: {
      Accept: "application/vnd.github+json",
      Authorization: `Bearer ${token}`,
      "X-GitHub-Api-Version": "2026-03-10",
    },
  });

  if (!response.ok) {
    return Response.json({ error: `GitHub API ${response.status}` }, { status: 502 });
  }

  const findings = (await response.json()) as GitHubFinding[];
  const batch = adminDb.batch();

  for (const finding of findings) {
    const docId = `${body.owner}_${body.repo}_${finding.number}`;
    batch.set(
      adminDb.collection("codeQualityFindings").doc(docId),
      {
        repository: `${body.owner}/${body.repo}`,
        number: finding.number,
        state: finding.state,
        ruleId: finding.rule.id,
        ruleTitle: finding.rule.title,
        severity: finding.rule.severity,
        category: finding.rule.category,
        path: finding.location.path,
        startLine: finding.location.start_line,
        message: finding.message.text,
        createdAt: finding.created_at,
        syncedAt: FieldValue.serverTimestamp(),
      },
      { merge: true },
    );
  }

  await batch.commit();
  return Response.json({ synced: findings.length });
}

100件を超えるリポジトリでは、afterカーソルを使ってページングします。また、実運用では管理者認可、対象リポジトリのallowlist、同期失敗ログを必ず入れます。

ハンズオン3: GitHub Actionsで毎朝同期する

同期APIは、GitHub Actionsのスケジュール実行から呼びます。GitHub API用トークンはNext.js側に置き、Actionsには同期API用の短い権限だけを渡します。

name: sync-code-quality

on:
  schedule:
    - cron: "15 22 * * *"
  workflow_dispatch:

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - name: Sync findings
        env:
          SYNC_ENDPOINT: ${{ secrets.CODE_QUALITY_SYNC_ENDPOINT }}
          SYNC_TOKEN: ${{ secrets.CODE_QUALITY_SYNC_TOKEN }}
        run: |
          curl -fsS -X POST "$SYNC_ENDPOINT" \
            -H "Authorization: Bearer $SYNC_TOKEN" \
            -H "Content-Type: application/json" \
            -d '{"owner":"morison-example","repo":"kensaboard"}'

20〜30リポジトリを扱う場合は、3〜4件ずつバッチに分けます。Code Quality未有効化、権限不足、API一時失敗を個別に記録できるため、全体ジョブの再実行が楽になります。

ハンズオン4: coverageとPRしきい値へつなげる

Code QualityはcoverageアップロードやrulesetのPRしきい値とも組み合わせられます。公式ドキュメントでは、Cobertura XML形式のcoverageを actions/upload-code-coverage@v1 でアップロードする手順が案内されています。

permissions:
  contents: read
  code-quality: write

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-node@v4
    with:
      node-version: 22
      cache: yarn
  - run: yarn install --frozen-lockfile
  - run: yarn test:coverage
  - uses: actions/upload-code-coverage@v1
    with:
      file: coverage/cobertura-coverage.xml
      language: JavaScript
      label: code-coverage/nextjs

いきなり全PRを止めるのではなく、30日分のFindingsをFirestoreに貯めてから段階的に強めます。

フェーズ運用
1Firestore集計だけで多いルールとディレクトリを見る
2Errors だけPRブロックする
3新規FindingをGitHub Issues化する
4一部リポジトリで Warnings and higher を試す

まとめ

Code Quality Findings REST APIにより、GitHub上の品質指摘をNext.jsアプリやFirestoreの運用データとして扱いやすくなりました。

実務では、少数リポジトリでCode Qualityを有効化し、open findingsをFirestoreに同期します。そのうえでcoverageアップロードを追加し、30日ほど傾向を見てからPRしきい値を強めるのが安全です。

2026年7月20日のGA以降は追加料金が発生するため、どのリポジトリで何を品質ゲートにするかを決める必要があります。APIで傾向を可視化しておけば、品質ルールを感覚ではなくデータで調整できます。