# 機能設計書 30-マージリクエストマージ

## 概要

本ドキュメントは、GitLabにおけるマージリクエストマージ機能の設計を定義する。承認されたマージリクエストをターゲットブランチにマージし、コード変更を統合する機能である。

### 本機能の処理概要

マージリクエストマージ機能は、ソースブランチの変更をターゲットブランチにGitマージし、MRを完了状態にする機能である。

**業務上の目的・背景**：コードレビューが完了し、CI/CDパイプラインが成功したマージリクエストを本番ブランチに統合する。これにより、レビュー済みのコードのみがメインブランチにマージされ、コード品質が維持される。マージ後は関連するIssueの自動クローズ、ソースブランチの削除、通知送信などの後処理が実行される。

**機能の利用シーン**：
- コードレビュー完了後のマージ実行
- CI/CDパイプライン成功後の自動マージ
- スカッシュマージによるコミット履歴の整理
- マージ後のソースブランチ自動削除
- 関連Issueの自動クローズ

**主要な処理内容**：
1. マージ可能性の検証（権限、コンフリクト、パイプライン）
2. 排他ロック取得による競合防止
3. Gitマージ実行（通常/スカッシュ）
4. MRの状態をmergedに更新
5. 後処理（Issue自動クローズ、ブランチ削除、通知）

**関連システム・外部連携**：Gitalyサーバー、Sidekiqワーカー、CI/CDパイプライン

**権限による制御**：can_be_merged_by? による権限確認。マージ権限、承認要件の充足が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | MR詳細 | 主機能 | マージボタンによる実行 |
| 61 | MR一覧 | 参照 | マージ後の状態反映 |

## 機能種別

処理実行（Git操作）+ 状態遷移 + 非同期後処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sha | String | Yes | マージ対象のdiff_head_sha | 最新SHA一致 |
| merge_commit_message | String | No | マージコミットメッセージ | - |
| squash_commit_message | String | No | スカッシュコミットメッセージ | - |
| should_remove_source_branch | Boolean | No | ソースブランチ削除フラグ | true/false |
| squash | Boolean | No | スカッシュマージフラグ | true/false |
| merge_strategy | Class | No | マージ戦略クラス | デフォルト: FromSourceBranch |

### 入力データソース

- URL パス: `/project_namespace/project_name/-/merge_requests/:iid/merge`
- マージボタンクリック
- クイックアクション /merge
- 自動マージトリガー

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| merge_request.state | String | merged |
| merge_request.merged_commit_sha | String | マージ後のコミットSHA |
| merge_request.merge_commit_sha | String | マージコミットSHA |
| merge_request.squash_commit_sha | String | スカッシュコミットSHA（該当時） |

### 出力先

- HTML: MR詳細ページ（マージ完了状態）
- JSON: API レスポンス
- Webhook: merge_request merge イベント

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ 排他ロック取得（exclusive_lease）
2. バリデーション
   ├─ authorization_check! - 権限確認
   ├─ error_check! - EEエラーチェック
   ├─ validate_strategy! - マージ戦略検証
   └─ updated_check! - SHA一致確認
3. ロック状態に遷移
   └─ in_locked_state
4. Gitマージ実行
   └─ merge_strategy.execute_git_merge!
5. MR更新
   └─ merged_commit_sha, merge_commit_sha 設定
6. 後処理（PostMergeService）
   ├─ mark_as_merged
   ├─ イベント作成
   ├─ TODO解決
   ├─ 関連Issue自動クローズ
   ├─ 通知送信
   └─ Webhook実行
7. ソースブランチ削除（オプション）
   └─ DeleteSourceBranchWorker（非同期）
8. ロック解放
   └─ exclusive_lease.cancel
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{排他ロック取得?}
    B -->|No| C[処理スキップ]
    B -->|Yes| D{マージ権限?}
    D -->|No| E[権限エラー]
    D -->|Yes| F{SHA一致?}
    F -->|No| G[更新エラー]
    F -->|Yes| H[in_locked_state]
    H --> I[Gitマージ実行]
    I --> J{成功?}
    J -->|No| K[マージエラー]
    J -->|Yes| L[MR更新]
    L --> M[PostMergeService]
    M --> N{ブランチ削除?}
    N -->|Yes| O[DeleteSourceBranchWorker]
    N -->|No| P[成功レスポンス]
    O --> P
    K --> Q[エラー記録]
    Q --> R[排他ロック解放]
    E --> R
    G --> R
    C --> S[終了]
    P --> R
    R --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | マージ権限 | can_be_merged_by? で権限確認 | 常時 |
| BR-30-02 | SHA一致 | params[:sha] == diff_head_sha | 常時 |
| BR-30-03 | 排他制御 | merge_exclusive_lease による重複防止 | 常時 |
| BR-30-04 | locked状態 | マージ中はlocked状態 | マージ実行中 |
| BR-30-05 | ソースブランチ削除 | can_remove_source_branch? で削除可能性確認 | should_remove_source_branch時 |
| BR-30-06 | Issue自動クローズ | ターゲットがデフォルトブランチの場合のみ | マージ後処理 |

### 計算ロジック

**delete_source_branch?判定**：
```ruby
params.fetch('should_remove_source_branch', merge_request.force_remove_source_branch?) &&
  merge_request.can_remove_source_branch?(branch_deletion_user)
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 更新 | merge_requests | UPDATE | state_id, merged_commit_sha等 |
| 作成 | events | INSERT | マージイベント |
| 作成 | system_note_metadata | INSERT | 状態変更ノート |
| 更新 | merge_request_metrics | UPDATE | merged_at等 |
| 更新 | todos | UPDATE | TODO解決 |
| 更新 | issues | UPDATE | 関連Issue自動クローズ |

### テーブル別操作詳細

#### merge_requests

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | state_id | 3 (merged) | mark_as_merged |
| UPDATE | merged_commit_sha | Gitマージ結果 | - |
| UPDATE | merge_commit_sha | マージコミットSHA | - |
| UPDATE | squash_commit_sha | スカッシュコミットSHA | スカッシュ時 |
| UPDATE | merge_error | エラーメッセージ | エラー時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------
| - | MergeError | マージ権限なし | 権限エラーメッセージ |
| - | MergeError | SHA不一致 | 更新エラーメッセージ |
| - | StrategyError | マージ戦略検証失敗 | 戦略エラーメッセージ |
| - | PreReceiveError | pre-receiveフック失敗 | フックエラーメッセージ |
| - | GenericError | その他エラー | 汎用エラーメッセージ |

### リトライ仕様

排他ロック取得失敗時は処理をスキップ（別プロセスで処理中）

## トランザクション仕様

- Gitマージはトランザクション外（Gitaly操作）
- MR状態更新とイベント作成はトランザクション内
- Issue自動クローズは非同期ワーカーで実行

## パフォーマンス要件

- 排他ロックによる同時マージ防止
- ソースブランチ削除は非同期（DeleteSourceBranchWorker）
- Issue自動クローズは非同期（CloseIssueWorker）、バッチ処理

## セキュリティ考慮事項

- can_be_merged_by? による厳格な権限確認
- 排他ロックによる競合状態防止
- SHA検証による意図しないマージ防止
- pre-receiveフックによるサーバーサイド検証

## 備考

- マージ後は関連するauto_mergeを中止
- Review Appのジョブをキャンセル
- 環境のクリーンアップ実行
- Pages デプロイメントの非アクティブ化
- 非最新のdiffレコードを削除

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

マージリクエストの状態遷移とマージ関連属性を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | merge_request.rb | `app/models/merge_request.rb` | state_machine、merge_status、can_be_merged_by? |

**読解のコツ**: state_machine の merged 状態への遷移、merge_exclusive_lease、in_locked_state を理解する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | merge アクション |

**主要処理フロー**:
1. merge アクション - MergeWorker経由またはMergeOrchestrationService呼び出し

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | merge_service.rb | `app/services/merge_requests/merge_service.rb` | マージサービス本体 |
| 3-2 | merge_base_service.rb | `app/services/merge_requests/merge_base_service.rb` | マージ基底サービス |
| 3-3 | post_merge_service.rb | `app/services/merge_requests/post_merge_service.rb` | マージ後処理 |

**主要処理フロー（merge_service.rb）**:
- **17-42行目**: execute - マージ処理のメインロジック
- **46-51行目**: validate! - 全バリデーション実行
- **53-57行目**: authorization_check! - 権限チェック
- **63-68行目**: updated_check! - SHA一致確認
- **70-91行目**: commit - Gitマージ実行
- **102-117行目**: after_merge - 後処理呼び出し
- **126-129行目**: delete_source_branch? - ブランチ削除判定
- **168-172行目**: source_matches? - SHA比較
- **174-178行目**: exclusive_lease - 排他ロック

**主要処理フロー（post_merge_service.rb）**:
- **15-50行目**: execute - 後処理のメインロジック
- **20-29行目**: mark_as_merged - MR状態更新
- **31-40行目**: イベント・通知・TODO処理
- **64-79行目**: close_issues - 関連Issue自動クローズ

### プログラム呼び出し階層図

```
MergeRequestsController#merge
    │
    └─ MergeService#execute
           │
           ├─ exclusive_lease.try_obtain（排他ロック取得）
           │
           ├─ validate!
           │      ├─ authorization_check!
           │      │      └─ can_be_merged_by?
           │      ├─ error_check!（EE拡張）
           │      ├─ validate_strategy!
           │      └─ updated_check!
           │             └─ source_matches?（SHA比較）
           │
           ├─ in_locked_state
           │      └─ commit
           │             ├─ merge_strategy.execute_git_merge!
           │             │      └─ Gitaly操作
           │             └─ merge_request.update!
           │
           ├─ after_merge
           │      ├─ PostMergeService#execute
           │      │      ├─ mark_as_merged
           │      │      ├─ create_event
           │      │      ├─ todo_service.merge_merge_request
           │      │      ├─ create_note
           │      │      ├─ close_issues
           │      │      │      └─ CloseIssueWorker（非同期）
           │      │      ├─ notification_service.merge_mr
           │      │      ├─ cleanup_environments
           │      │      └─ execute_hooks('merge')
           │      │
           │      └─ DeleteSourceBranchWorker（非同期・オプション）
           │
           └─ exclusive_lease.cancel（排他ロック解放）
```

### データフロー図

```
[入力]                    [処理]                         [出力]

マージボタン        ───▶  MergeRequestsController   ───▶  マージ完了レスポンス
(sha, options)           │
                         ▼
                    MergeService
                         │
                    ┌────┴────┐
                    ▼         ▼
              validate!   exclusive_lease
                    │
                    ▼
              in_locked_state
                    │
                    ▼
              Gitマージ実行 ──────────────────────────▶  Gitaly
                    │
                    ▼
              PostMergeService
                    │
        ┌────┬─────┼─────┬────┐
        ▼    ▼     ▼     ▼    ▼
     mark_as  event  TODO  Issue  通知
     merged         解決  close
        │
        ▼
   DB UPDATE ──────────────────────────────────────▶  merge_requests
                                                      events
                                                      issues
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| merge_requests_controller.rb | `app/controllers/projects/merge_requests_controller.rb` | コントローラー | MRのエントリーポイント |
| merge_service.rb | `app/services/merge_requests/merge_service.rb` | サービス | マージ実行サービス |
| merge_base_service.rb | `app/services/merge_requests/merge_base_service.rb` | サービス | マージ基底サービス |
| post_merge_service.rb | `app/services/merge_requests/post_merge_service.rb` | サービス | マージ後処理 |
| merge_orchestration_service.rb | `app/services/merge_requests/merge_orchestration_service.rb` | サービス | マージオーケストレーション |
| from_source_branch.rb | `app/services/merge_requests/merge_strategies/from_source_branch.rb` | 戦略 | 通常マージ戦略 |
| merge_request.rb | `app/models/merge_request.rb` | モデル | MRモデル |
| merge_worker.rb | `app/workers/merge_worker.rb` | ワーカー | 非同期マージ |
| delete_source_branch_worker.rb | `app/workers/merge_requests/delete_source_branch_worker.rb` | ワーカー | ブランチ削除 |
| close_issue_worker.rb | `app/workers/merge_requests/close_issue_worker.rb` | ワーカー | Issue自動クローズ |
