メインコンテンツへスキップ
見出し画像

GitHub Actions × Claude APIで、pushのたびにコミット要約をSlackへ送る

    チームで開発していると、「今日なにがmainに入ったのか」を追うのが地味に手間です。コミットログを毎回読むのは大変なので、GitHub ActionsとClaude APIで、pushのたびにコミットの要約をSlackへ投稿する仕組みを作りました。


    この記事では、同じことを再現できる最小構成のサンプルを紹介します。紹介するコードは記事用に書き起こしたもので、自分の環境のコードそのものではありません。外部のライブラリは使わず、ワークフロー1つとスクリプト1つで動く形にしています。

    この記事が関係する人・関係しない人

    関係する人

    • GitHub Actions を使っていて、main に入った変更をチームの Slack に流したい人

    • CI から Claude API を呼ぶ最小構成(Secrets の置き方、pushイベントの読み方)を知りたい人

    関係しない人

    • GitHub Actions を使っていない人(この記事のサンプルは GitHub Actions のワークフロー前提です)

    • ファイル単位の変更まで要約したい人は、このサンプルだけでは足りません。Actions に渡される push イベントには、各コミットの追加・削除・変更ファイルの一覧が含まれないため、GitHub の API で別に取得する必要があります

    自分が当てはまるかの確認方法

    • Secrets を登録できるかは、リポジトリの Settings → サイドバーの「Security」にある Secrets and variables → Actions を開いて確認できます

    • Slack 側は、Slack App の設定画面で Incoming Webhooks を有効にし、Add New Webhook to Workspace から投稿先のチャンネルを選べるかを確認します

    仕組み


    流れは次のとおりです。


    1. mainブランチにpushすると、GitHub Actionsのワークフローが動く

    2. スクリプトが、pushイベントの情報からコミットの一覧を取り出す

    3. Claude APIに一覧を渡して、短く要約してもらう

    4. 要約を、SlackのIncoming Webhookで指定のチャンネルに投稿する


    APIキーとWebhookのURLは、どちらもGitHubのSecretsに入れて、コードには書きません。

    画像


    準備


    1. SlackでIncoming WebhookのURLを作る


    Slack Appの設定画面で、Incoming Webhooksを有効にし、投稿先のチャンネルを選んでWebhook URLを発行します。Incoming Webhookは、発行されたURLにJSONをPOSTするだけでメッセージを投稿できる仕組みです。このURLを知っている人は誰でも投稿できてしまうので、APIキーと同じように秘密情報として扱います。

    Your webhook URL contains a secret. Don't share it online, including via public version control repositories.

    訳: webhook の URL には秘密情報が含まれています。公開されたバージョン管理のリポジトリを含め、オンラインで共有しないでください。(Sending messages using incoming webhooks)

    2. GitHubのSecretsに2つ登録する


    リポジトリの設定から、Actions用のSecretsに次の2つを登録します。


    • ANTHROPIC_API_KEY: ClaudeのAPIキー

    • SLACK_WEBHOOK_URL: 1で発行したWebhook URL

    画像


    ワークフロー


    .github/workflows/commit-summary.yml に置きます。


    name: Commit summary to Slack
    
    on:
      push:
        branches: [main]
    
    jobs:
      summarize:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: 22
          - name: Summarize commits and post to Slack
            env:
              ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
              SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
            run: node .github/scripts/summarize.mjs


    対象を main に絞っているのは、作業ブランチへのpushのたびにAPIを呼ばないようにするためです。


    スクリプト


    .github/scripts/summarize.mjs に置きます。Node.jsの標準機能(fs と fetch)だけで書いているので、npm install は要りません。


    // .github/scripts/summarize.mjs
    import fs from "node:fs";
    
    // pushイベントの情報から、コミットの一覧を取り出す
    const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8"));
    const lines = (event.commits ?? []).map(
      (c) => `- ${c.message.split("\n")[0]} (${c.author.name})`
    );
    
    if (lines.length === 0) {
      console.log("要約するコミットがありません");
      process.exit(0);
    }
    
    // 1. Claude APIでコミット一覧を要約する
    const res = await fetch("https://api.anthropic.com/v1/messages", {
      method: "POST",
      headers: {
        "x-api-key": process.env.ANTHROPIC_API_KEY,
        "anthropic-version": "2023-06-01",
        "content-type": "application/json",
      },
      body: JSON.stringify({
        model: "claude-haiku-5-5", // 使うモデルIDに置き換える
        max_tokens: 500,
        messages: [
          {
            role: "user",
            content: `次のコミット一覧を、チーム向けに日本語で3行以内に要約してください。\n\n${lines.join("\n")}`,
          },
        ],
      }),
    });
    if (!res.ok) throw new Error(`Claude API error: ${res.status} ${await res.text()}`);
    const data = await res.json();
    const summary = data.content
      .filter((b) => b.type === "text")
      .map((b) => b.text)
      .join("\n");
    
    // 2. SlackのIncoming Webhookに投稿する
    const slack = await fetch(process.env.SLACK_WEBHOOK_URL, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        text: `*${event.repository.full_name}* に ${lines.length} 件のコミットがpushされました\n${summary}\n${event.compare}`,
      }),
    });
    if (!slack.ok) throw new Error(`Slack error: ${slack.status} ${await slack.text()}`);


    実装のポイント


    コミット一覧はイベント情報から取る


    GitHub Actionsでは、ワークフローを起動したイベントの中身が、GITHUB_EVENT_PATH が指すJSONファイルに入っています。pushイベントには、pushされたコミットの配列(commits)が含まれるので、git log を自分で叩かなくても一覧が作れます。


    注意点が2つあります。GitHubのドキュメントによると、commits に入るのは最大2048件です。また、Actionsに渡されるpushイベントの情報には、各コミットで追加・削除・変更されたファイルの一覧が含まれません。ファイル単位の変更まで要約したい場合は、GitHubのAPIでコミットの詳細を取りに行く必要があります。

    The array includes a maximum of 2048 commits.

    訳: この配列(commits)には、最大2048件のコミットが含まれます。(Webhook events and payloads)

    The webhook payload available to GitHub Actions does not include the added, removed, and modified attributes in the commit object.

    訳: GitHub Actions で使える webhook のペイロードには、コミットオブジェクトの added、removed、modified の属性が含まれません。(Events that trigger workflows)

    送るのはコミットメッセージだけにする


    このサンプルでClaude APIに送るのは、コミットメッセージの1行目と作者名だけです。コードの差分まで送ると要約の質は上がりますが、外部のAPIにソースコードを渡すことになります。業務のリポジトリで使う場合は、社内のルールを先に確認してください。


    要約は軽いモデルで足りる


    コミット一覧の要約は、長い推論が要らない作業です。pushのたびに呼ぶので、速くて安いモデルを選ぶのが向いていると考えています。モデルIDは更新されるので、Claudeの公式ドキュメントで最新のものを確認して置き換えてください。


    失敗したら、ワークフローを失敗させる


    APIやSlackがエラーを返したときは、例外を投げてワークフローを失敗させています。黙って何も投稿されないより、Actionsの画面で失敗に気づけるほうが運用しやすいからです。


    動作確認


    1. Secretsの2つを登録したことを確認する

    2. ワークフローとスクリプトをmainにpushする

    3. GitHubのActionsタブで、ワークフローが成功しているかを見る

    4. Slackのチャンネルに要約が届いているかを見る


    まとめ


    • pushイベントの情報(GITHUB_EVENT_PATH)からコミット一覧を取り、Claude APIで要約して、SlackのIncoming Webhookに投稿する

    • APIキーとWebhook URLはGitHubのSecretsに入れる

    • Claude APIに送る範囲は必要最小限にし、モデルは軽いもので足りる

    関連記事

    出典:

    仕様は更新されるので、最新の内容は各公式ページで確認してください。

    開発ツールの仕様変更・提供終了の情報を毎朝お届けしています。見逃したくない方は、フォローしてください。

     
     

    HARu

     
     
    バックエンドエンジニア。Claude・GitHub・ローカルLLMなど開発ツールの新機能や仕様変更を、公式ドキュメントをもとに日本語で整理しています。「自分に関係あるか」「何を直せばいいか」がすぐ分かる記事を毎朝更新。記事はClaudeと一緒に作っています。

    あなたへのおすすめ