Files
gh-wasabeef-claude-code-coo…/commands/pr-auto-update.md
2025-11-30 09:05:37 +08:00

13 KiB

PR Auto Update

概要

Pull Request の説明とラベルを自動的に更新するコマンドです。Git の変更内容を分析して、適切な説明文とラベルを生成・設定します。

使い方

/pr-auto-update [オプション] [PR 番号]

オプション

  • --pr <番号> : 対象の PR 番号を指定 (省略時は現在のブランチから自動検出)
  • --description-only : 説明文のみ更新 (ラベルは変更しない)
  • --labels-only : ラベルのみ更新 (説明文は変更しない)
  • --dry-run : 実際の更新は行わず、生成される内容のみ表示
  • --lang <言語> : 言語を指定 (ja, en)

基本例

# 現在のブランチの PR を自動更新
/pr-auto-update

# 特定の PR を更新
/pr-auto-update --pr 1234

# 説明文のみ更新
/pr-auto-update --description-only

# ドライランで確認
/pr-auto-update --dry-run

機能詳細

1. PR の自動検出

現在のブランチから対応する PR を自動検出:

# ブランチから PR を検索
gh pr list --head $(git branch --show-current) --json number,title,url

2. 変更内容の分析

以下の情報を収集・分析:

  • ファイル変更: 追加・削除・変更されたファイル
  • コード分析: import 文、関数定義、クラス定義の変更
  • テスト: テストファイルの有無と内容
  • ドキュメント: README、docs の更新
  • 設定: package.json、pubspec.yaml、設定ファイルの変更
  • CI/CD: GitHub Actions、workflow の変更

3. 説明文の自動生成

テンプレート処理の優先順位

  1. 既存の PR 説明: 既に記述されている内容を完全に踏襲
  2. プロジェクトテンプレート: .github/PULL_REQUEST_TEMPLATE.md から構造を取得
  3. デフォルトテンプレート: 上記が存在しない場合のフォールバック

既存内容の保持ルール

重要: 既存の内容は変更しない

  • 書かれているセクションは保持
  • 空のセクションのみ補完
  • 機能的なコメント (Copilot review rule など) は保持

プロジェクトテンプレートの使用

# .github/PULL_REQUEST_TEMPLATE.md の構造を解析
parse_template_structure() {
  local template_file="$1"

  if [ -f "$template_file" ]; then
    # セクション構造を抽出
    grep -E '^##|^###' "$template_file"

    # コメントプレースホルダーを特定
    grep -E '<!--.*-->' "$template_file"

    # 既存のテンプレート構造を完全に踏襲
    cat "$template_file"
  fi
}

4. ラベルの自動設定

ラベル取得の仕組み

優先順位:

  1. .github/labels.yml: プロジェクト固有のラベル定義から取得
  2. GitHub API: gh api repos/{OWNER}/{REPO}/labels --jq '.[].name' で既存ラベルを取得

自動判定ルール

ファイルパターンベース:

  • ドキュメント: *.md, README, docs/documentation|docs|doc を含むラベル
  • テスト: test, spectest|testing を含むラベル
  • CI/CD: .github/, *.yml, Dockerfileci|build|infra|ops を含むラベル
  • 依存関係: package.json, pubspec.yaml, requirements.txtdependencies|deps を含むラベル

変更内容ベース:

  • バグ修正: fix|bug|error|crash|修正bug|fix を含むラベル
  • 新機能: feat|feature|add|implement|新機能|実装feature|enhancement|feat を含むラベル
  • リファクタリング: refactor|clean|リファクタrefactor|cleanup|clean を含むラベル
  • パフォーマンス: performance|perf|optimize|パフォーマンスperformance|perf を含むラベル
  • セキュリティ: security|secure|セキュリティsecurity を含むラベル

制約

  • 最大 3 個まで: 自動選択されるラベル数の上限
  • 既存ラベルのみ: 新しいラベルの作成は禁止
  • 部分マッチ: ラベル名にキーワードが含まれているかで判定

実際の使用例

.github/labels.yml が存在する場合:

# ラベル定義から自動取得
grep "^- name:" .github/labels.yml | sed "s/^- name: '\?\([^']*\)'\?/\1/"

# 例: プロジェクト固有のラベル体系を使用

GitHub API から取得する場合:

# 既存ラベルの一覧取得
gh api repos/{OWNER}/{REPO}/labels --jq '.[].name'

# 例: bug, enhancement, documentation などの標準的なラベルを使用

5. 実行フロー

#!/bin/bash

# 1. PR の検出・取得
detect_pr() {
  if [ -n "$PR_NUMBER" ]; then
    echo $PR_NUMBER
  else
    gh pr list --head $(git branch --show-current) --json number --jq '.[0].number'
  fi
}

# 2. 変更内容の分析
analyze_changes() {
  local pr_number=$1

  # ファイル変更の取得
  gh pr diff $pr_number --name-only

  # 内容分析
  gh pr diff $pr_number | head -1000
}

# 3. 説明文の生成
generate_description() {
  local pr_number=$1
  local changes=$2

  # 現在の PR 説明を取得
  local current_body=$(gh pr view $pr_number --json body --jq -r .body)

  # 既存内容があればそのまま使用
  if [ -n "$current_body" ]; then
    echo "$current_body"
  else
    # テンプレートから新規生成
    local template_file=".github/PULL_REQUEST_TEMPLATE.md"
    if [ -f "$template_file" ]; then
      generate_from_template "$(cat "$template_file")" "$changes"
    else
      generate_from_template "" "$changes"
    fi
  fi
}

# テンプレートからの生成
generate_from_template() {
  local template="$1"
  local changes="$2"

  if [ -n "$template" ]; then
    # テンプレートをそのまま使用 (HTML コメント保持)
    echo "$template"
  else
    # デフォルトフォーマットで生成
    echo "## What does this change?"
    echo ""
    echo "$changes"
  fi
}

# 4. ラベルの決定
determine_labels() {
  local changes=$1
  local file_list=$2
  local pr_number=$3

  # 利用可能なラベルを取得
  local available_labels=()
  if [ -f ".github/labels.yml" ]; then
    # labels.yml からラベル名を抽出
    available_labels=($(grep "^- name:" .github/labels.yml | sed "s/^- name: '\?\([^']*\)'\?/\1/"))
  else
    # GitHub API からラベルを取得
    local repo_info=$(gh repo view --json owner,name)
    local owner=$(echo "$repo_info" | jq -r .owner.login)
    local repo=$(echo "$repo_info" | jq -r .name)
    available_labels=($(gh api "repos/$owner/$repo/labels" --jq '.[].name'))
  fi

  local suggested_labels=()

  # 汎用的なパターンマッチング
  analyze_change_patterns "$file_list" "$changes" available_labels suggested_labels

  # 最大 3 個に制限
  echo "${suggested_labels[@]:0:3}"
}

# 変更パターンからラベルを決定
analyze_change_patterns() {
  local file_list="$1"
  local changes="$2"
  local -n available_ref=$3
  local -n suggested_ref=$4

  # ファイルタイプによる判定
  if echo "$file_list" | grep -q "\.md$\|README\|docs/"; then
    add_matching_label "documentation\|docs\|doc" available_ref suggested_ref
  fi

  if echo "$file_list" | grep -q "test\|spec"; then
    add_matching_label "test\|testing" available_ref suggested_ref
  fi

  # 変更内容による判定
  if echo "$changes" | grep -iq "fix\|bug\|error\|crash\|修正"; then
    add_matching_label "bug\|fix" available_ref suggested_ref
  fi

  if echo "$changes" | grep -iq "feat\|feature\|add\|implement\|新機能\|実装"; then
    add_matching_label "feature\|enhancement\|feat" available_ref suggested_ref
  fi
}

# マッチするラベルを追加
add_matching_label() {
  local pattern="$1"
  local -n available_ref=$2
  local -n suggested_ref=$3

  # すでに 3 個ある場合はスキップ
  if [ ${#suggested_ref[@]} -ge 3 ]; then
    return
  fi

  # パターンにマッチする最初のラベルを追加
  for available_label in "${available_ref[@]}"; do
    if echo "$available_label" | grep -iq "$pattern"; then
      # 重複チェック
      local already_exists=false
      for existing in "${suggested_ref[@]}"; do
        if [ "$existing" = "$available_label" ]; then
          already_exists=true
          break
        fi
      done

      if [ "$already_exists" = false ]; then
        suggested_ref+=("$available_label")
        return
      fi
    fi
  done
}

# 旧関数の互換性のため残しておく
find_and_add_label() {
  add_matching_label "$@"
}

# 5. PR の更新
update_pr() {
  local pr_number=$1
  local description="$2"
  local labels="$3"

  if [ "$DRY_RUN" = "true" ]; then
    echo "=== DRY RUN ==="
    echo "Description:"
    echo "$description"
    echo "Labels: $labels"
  else
    # リポジトリ情報を取得
    local repo_info=$(gh repo view --json owner,name)
    local owner=$(echo "$repo_info" | jq -r .owner.login)
    local repo=$(echo "$repo_info" | jq -r .name)

    # GitHub API を使用して本文を更新 (HTML コメント保持)
    # JSON エスケープを適切に処理
    local escaped_body=$(echo "$description" | jq -R -s .)
    gh api \
      --method PATCH \
      "/repos/$owner/$repo/pulls/$pr_number" \
      --field body="$description"

    # ラベルは通常の gh コマンドで問題なし
    if [ -n "$labels" ]; then
      gh pr edit $pr_number --add-label "$labels"
    fi
  fi
}

設定ファイル (今後の拡張用)

~/.claude/pr-auto-update.config:

{
  "language": "ja",
  "max_labels": 3
}

よくあるパターン

Flutter プロジェクト

## What does this change?

{機能名}を実装しました。ユーザーの{課題}を解決します。

### 主な変更内容

- **UI 実装**: {画面名}を新規作成
- **状態管理**: 状態管理ライブラリを使用してステート管理を追加
- **API 統合**: GraphQL クエリ・ミューテーションを実装
- **テスト**: ウィジェットテスト・ユニットテストを追加

### 技術仕様

- **アーキテクチャ**: {使用パターン}
- **依存関係**: {新規追加したパッケージ}
- **パフォーマンス**: {最適化内容}

Node.js プロジェクト

## What does this change?

{API 名}エンドポイントを実装しました。{ユースケース}に対応します。

### 主な変更内容

- **API 実装**: {エンドポイント}を新規作成
- **バリデーション**: リクエスト検証ロジックを追加
- **データベース**: {テーブル名}への操作を実装
- **テスト**: 統合テスト・ユニットテストを追加

### セキュリティ

- **認証**: JWT トークン検証
- **認可**: ロールベースアクセス制御
- **入力検証**: SQL インジェクション対策

CI/CD 改善

## What does this change?

GitHub Actions ワークフローを改善しました。{効果}を実現します。

### 改善内容

- **パフォーマンス**: ビルド時間を{時間}短縮
- **信頼性**: エラーハンドリングを強化
- **セキュリティ**: シークレット管理を改善

### 技術詳細

- **並列化**: {ジョブ名}を並列実行
- **キャッシュ**: {キャッシュ対象}のキャッシュ戦略を最適化
- **モニタリング**: {メトリクス}の監視を追加

注意事項

  1. 既存内容の完全保持:

    • 既に記述されている内容は一文字も変更しない
    • 空のコメント部分とプレースホルダーのみ補完
    • ユーザーが意図的に書いた内容を尊重
  2. テンプレート優先順位:

    • 既存の PR 説明 > .github/PULL_REQUEST_TEMPLATE.md > デフォルト
    • プロジェクト固有のテンプレート構造を完全踏襲
  3. ラベル制約:

    • .github/labels.yml が存在すれば優先使用
    • 存在しない場合は GitHub API から既存ラベルを取得
    • 新しいラベルの作成は禁止
    • 最大 3 個まで自動選択
  4. 安全な更新:

    • --dry-run で事前確認を推奨
    • 機密情報を含む変更の場合は警告表示
    • バックアップとして元の説明を保存
  5. 一貫性の維持:

    • プロジェクトの既存 PR スタイルに合わせる
    • 言語 (日本語/英語) の統一
    • ラベリング規則の継承

トラブルシューティング

よくある問題

  1. PR が見つからない: ブランチ名と PR の関連付けを確認
  2. 権限エラー: GitHub CLI の認証状態を確認
  3. ラベルが設定できない: リポジトリの権限を確認
  4. HTML コメントがエスケープされる: GitHub CLI の仕様により <!-- -->&lt;!-- --&gt; に変換される

GitHub CLI の HTML コメントエスケープ問題

重要: GitHub CLI(gh pr edit) は HTML コメントを自動エスケープします。また、シェルのリダイレクト処理で EOF < /dev/null などの不正な文字列が混入する場合があります。

根本的解決策

  1. GitHub API の --field オプション使用: --field を使用して適切なエスケープ処理
  2. シェル処理の簡素化: 複雑なリダイレクトやパイプ処理を避ける
  3. テンプレート処理の単純化: HTML コメント除去処理を廃止し、完全保持
  4. JSON エスケープの適切な処理: 特殊文字を正しく処理

デバッグオプション

# 詳細ログ出力 (実装時に追加)
/pr-auto-update --verbose