GitHub↔タスク連携 仕様書
ステータス: Draft / 作成日: 2026-05-27 PR #9b — 依存: コア(PR #1), 自動化(PR #8), GitHub App 基盤(PR #9a)
1. 概要
PR #9a で構築した GitHub App 基盤の上に、タスクとの自動リンク機能を追加する。
コミットメッセージや PR タイトルに KEY-N(プロジェクトキー + 連番、例: ENG-42)を書くだけで自動リンクされ、Closes ENG-42 でタスクが自動クローズされる。
なぜ
KEY-Nか: GitHub 自身が#Nを Issue 番号として使用するため、#42ではどちらを指すか曖昧になる。ENG-42のようなプロジェクトキー付き形式は GitHub Issues と衝突せず、Linear・Jira ユーザーにも馴染み深い。
2. データモデル
task_github_links
3. マイグレーション
CREATE TABLE task_github_links (
id UUID PRIMARY KEY,
task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
link_type VARCHAR NOT NULL,
github_repo VARCHAR NOT NULL,
github_number INT,
github_sha VARCHAR(40),
title VARCHAR NOT NULL,
github_url VARCHAR NOT NULL,
state VARCHAR,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_github_links_task ON task_github_links(task_id);
4. タスクへの自動リンク
パターン一覧
PR タイトル・PR 本文・コミットメッセージ・ブランチ名から KEY-N を正規表現でパースする。
正規表現: \b([A-Z][A-Z0-9]{1,9})-(\d+)\b
クローズキーワード: Closes / Close / Fixes / Fix / Resolves / Resolve(大小文字不問)
PR タイトルおよび PR 本文の両方が対象。GitHub 自身の Closes #N(Issue クローズ)と構文が異なるため衝突しない。
KEY-N の解決
KEY-N はまず KEY でテナント内のプロジェクトを特定し、その seq_id=N のタスクを探す。
KEY が不明またはタスクが見つからない場合はリンク追加をスキップ(エラーにしない)。
1つのコミット / PR が複数プロジェクトのキーを含む場合、それぞれのプロジェクトのタスクへリンクする。
5. 受信する GitHub Webhook イベント
PR #9a の webhook エンドポイント(POST /v1/github/webhook)に本 PR でハンドラーを追加する。
冪等性設計
GitHub は障害時に同一イベントを複数回送信することがある。X-GitHub-Delivery ヘッダー(配信固有 UUID)を使って二重処理を防ぐ。
受信時:
delivery_id = X-GitHub-Delivery ヘッダー値
Redis SET NX gh_delivery:{delivery_id} "1" EX 86400
→ SET 成功(初回): 通常処理へ
→ SET 失敗(重複): 即 200 OK を返して処理をスキップ
task_github_links の INSERT は常に UPSERT(ON CONFLICT (task_id, link_type, github_repo, github_number, github_sha) DO UPDATE)で実行し、ネットワーク再送でのリンク重複を防ぐ。
pull_request.closed(merged=true)時のタスク遷移は、タスクが既に done 系ステータス(is_done_state = true)の場合はスキップして二重遷移を防ぐ。
イベント一覧
マイグレーション追加(冪等性制約)
ALTER TABLE task_github_links
ADD CONSTRAINT uq_github_link
UNIQUE (task_id, link_type, github_repo, github_number, github_sha);
6. GitHub 側へのフィードバック
PR 作成時に、リンクされたタスクへの URL をコメントとして PR に自動追加する(権限 pull_requests: write が必要)。
---
🔗 Linked Task: [ENG-42 OAuth 対応を実装する](https://app.example.com/projects/.../tasks/42)
7. API
POST /tasks/{id}/github-links リクエスト(手動リンク):
{
"link_type": "pull_request",
"github_repo": "myorg/myapp",
"github_number": 87,
"title": "feat: OAuth 対応",
"github_url": "https://github.com/myorg/myapp/pull/87",
"state": "open"
}
8. フロントエンド(Phase B)
タスク詳細「GitHub」タブ
┌─────────────────────────────────────────────┐
│ GitHub [+ 手動リンク] │
├─────────────────────────────────────────────┤
│ Pull Requests │
│ ✅ #87 feat: OAuth 対応 ENG-42 [Merged] │
│ 🔄 #91 fix: エラーハンドリング [Open] │
│ │
│ Commits │
│ a3f92c1 fix: トークン期限切れを修正 │
│ e7b81d4 feat: GitHub App 初期実装 │
│ │
│ Branches │
│ feat/ENG-42-oauth │
└─────────────────────────────────────────────┘
設定画面(PR #9a の設定画面に使い方を追加)
┌──────────────────────────────────────────────┐
│ GitHub 連携 │
├──────────────────────────────────────────────┤
│ 接続リポジトリ: myorg/myapp [解除] │
│ │
│ 自動リンク: 有効 │
│ ブランチ自動リンク: 有効 │
│ │
│ 使い方: │
│ コミットや PR タイトルに ENG-42 を含めると │
│ タスク ENG-42 に自動でリンクされます。 │
│ Closes ENG-42 と書くと PR マージ時に │
│ タスクが自動的に完了になります。 │
└──────────────────────────────────────────────┘