GitHub↔タスク連携 仕様書

PR・コミット・ブランチとタスクの自動リンク・クローズ連動

ステータス: 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. データモデル

カラム 制約 説明
id UUID PK  
task_id UUID NOT NULL, FK→tasks CASCADE  
link_type VARCHAR NOT NULL pull_request / commit / branch
github_repo VARCHAR NOT NULL owner/repo 形式
github_number INT NULLABLE PR 番号
github_sha VARCHAR(40) NULLABLE コミット SHA
title VARCHAR NOT NULL PR タイトル / コミットメッセージ先頭行
github_url VARCHAR NOT NULL GitHub 上の URL
state VARCHAR NULLABLE open / closed / merged(PR のみ)
created_at TIMESTAMPTZ NOT NULL DEFAULT now()  
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()  

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

パターン 動作
KEY-N(タイトル / メッセージ) fix: ログインバグ修正 ENG-42 タスク ENG-42 にリンク追加
複数 KEY-N feat: OAuth ENG-42 ENG-43 タスク ENG-42 と ENG-43 両方にリンク追加
異なるプロジェクト feat: OAuth ENG-42 BACK-7 各プロジェクトのタスクにそれぞれリンク
ブランチ名 feat/ENG-42-oauth タスク ENG-42 にブランチリンク追加
クローズキーワード + KEY-N Closes ENG-42 / Fixes ENG-42 / Resolves ENG-42 PR マージ時にタスク ENG-42 を自動クローズ

クローズキーワード: 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)の場合はスキップして二重遷移を防ぐ。

イベント一覧

GitHub イベント 処理内容
push コミットメッセージをパースし task_github_links を UPSERT
pull_request.opened PR タイトル + 本文をパースしリンク追加(UPSERT)
pull_request.edited リンクを再解析・UPDATE
pull_request.closed(merged=true) state → merged に UPDATE。クローズキーワードがあり、タスクが未完了なら完了ステータスへ遷移(Automation github_pr_merged トリガーを発火)
pull_request.closed(merged=false) state → closed に UPDATE
pull_request.reopened state → open に UPDATE
create(ref_type=branch) ブランチ名をパースしリンク追加(UPSERT)

マイグレーション追加(冪等性制約)

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

メソッド パス 説明
GET /tasks/{id}/github-links タスクに紐付いた PR / コミット一覧
POST /tasks/{id}/github-links 手動リンク追加
DELETE /tasks/{id}/github-links/{link_id} リンク削除

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 マージ時に       │
│   タスクが自動的に完了になります。           │
└──────────────────────────────────────────────┘
コンポーネント ファイル
TaskGitHubPanel components/tasks/TaskGitHubPanel.vue
GitHubLinkBadge components/tasks/GitHubLinkBadge.vue