# 機能設計書 23-Blame表示

## 概要

本ドキュメントは、GitLabにおけるBlame表示機能の設計を定義する。ファイルの各行について、最終変更者とコミット情報を表示し、コードの変更履歴を行単位で追跡できる機能である。

### 本機能の処理概要

Blame表示機能は、Gitの`git blame`コマンドに相当する機能で、ファイルの各行がいつ・誰によって・どのコミットで変更されたかを表示する機能である。

**業務上の目的・背景**：ソフトウェア開発において、特定のコード行の変更履歴を追跡することは、バグの原因調査やコードの理解に不可欠である。本機能により、開発者は「この行を書いたのは誰か」「なぜこの変更が入ったのか」を即座に確認でき、問題解決の効率が大幅に向上する。特にレガシーコードのメンテナンスや、チーム間のコード引き継ぎ時に重要な役割を果たす。

**機能の利用シーン**：
- バグの原因となったコード変更を特定する
- 特定のロジックが追加された経緯を調査する
- コードの責任者（オーナー）を特定する
- コードレビュー時に変更の背景を理解する
- リファクタリング対象の選定時に変更頻度を確認する

**主要な処理内容**：
1. 指定されたファイルのBlame情報をGitalyから取得
2. 行単位でのコミット情報（SHA、作者、日時、メッセージ）の表示
3. ページネーションによる大量行の分割表示
4. `.git-blame-ignore-revs`ファイルによる除外設定のサポート
5. ストリーミングモードでの段階的表示

**関連システム・外部連携**：Gitalyサーバーとの連携によるBlame情報取得、CI/CDパイプラインとの連携（環境情報表示）

**権限による制御**：リポジトリへの読み取り権限（read_code）が必要。プライベートプロジェクトではプロジェクトメンバーまたは適切な権限を持つユーザーのみアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | Blame表示 | 主機能 | ファイルの行ごとの変更履歴表示 |
| 31 | ファイル表示 | 補助機能 | Blame表示への遷移 |

## 機能種別

データ参照・表示処理（SELECT）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ref | String | Yes | ブランチ名、タグ名、またはコミットSHA | 有効なGit参照 |
| path | String | Yes | ファイルパス | リポジトリ内に存在するファイル |
| page | Integer | No | ページ番号（ページネーション用） | 正の整数 |
| no_pagination | Boolean | No | ページネーション無効化フラグ | true/false |
| streaming | Boolean | No | ストリーミングモード | true/false |
| ignore_revs | Boolean | No | .git-blame-ignore-revs適用フラグ | true/false |

### 入力データソース

- URL パス: `/project_namespace/project_name/-/blame/:ref/:path`
- クエリパラメータによるオプション指定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| blame | Gitlab::Blame | Blame情報オブジェクト |
| blame.groups | Array<BlameGroup> | 連続する同一コミットの行グループ |
| group.commit | Commit | コミットオブジェクト |
| group.lines | Array<String> | 該当コミットに属する行内容 |
| group.span | Integer | グループの行数 |
| group.lineno | Integer | 開始行番号 |

### 出力先

- HTML: ブラウザへのレンダリング
- 部分レンダリング: Ajax リクエストによるページ取得

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信・認証確認
   └─ authorize_read_code!
2. 参照・パスの検証
   └─ assign_ref_vars でブランチ/タグ/コミット解決
3. Blobの読み込み
   └─ load_blob でファイル存在確認
4. バイナリチェック
   └─ require_non_binary_blob でバイナリファイル拒否
5. 環境情報の取得
   └─ load_environment で関連環境を取得
6. Blame情報の取得
   └─ load_blame でGitalyからBlame取得
7. レスポンス出力
   └─ HTML/部分テンプレートでレンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{プロジェクトが空?}
    B -->|Yes| C[404エラー]
    B -->|No| D{参照が有効?}
    D -->|No| C
    D -->|Yes| E{ファイルが存在?}
    E -->|No| F[ルートにリダイレクト]
    E -->|Yes| G{バイナリファイル?}
    G -->|Yes| H[Blob表示にリダイレクト]
    G -->|No| I[環境情報取得]
    I --> J[Blame情報取得]
    J --> K{ignore_revs エラー?}
    K -->|Yes| L[フラッシュエラーでリダイレクト]
    K -->|No| M{ストリーミング?}
    M -->|Yes| N[段階的表示]
    M -->|No| O[通常表示]
    N --> P[終了]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-23-01 | バイナリ拒否 | バイナリファイルのBlame表示は不可 | ファイルがバイナリの場合 |
| BR-23-02 | ページネーション | 大きなファイルはページ分割表示 | no_pagination=false（デフォルト） |
| BR-23-03 | ignore_revs対応 | .git-blame-ignore-revsで特定コミットを除外可能 | ignore_revs=true |
| BR-23-04 | ストリーミング | 大きなファイルは段階的に読み込み可能 | streaming=true |

### 計算ロジック

**Blameグルーピング**：
- 連続する同一コミットの行をグループ化して表示
- グループごとにコミット情報を1回表示し、行内容を列挙

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Blame取得 | - | - | Gitalyから直接取得（DBアクセスなし） |
| 環境取得 | environments | SELECT | 関連する環境情報を取得 |

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

#### environments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | name, external_url等 | ref または commit に基づく | 最新のデプロイ環境 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | プロジェクトが空の場合 | エラーページ表示 |
| 302 | Redirect | ファイルが存在しない場合 | ルートにリダイレクト |
| 302 | Redirect | バイナリファイルの場合 | Blob表示にリダイレクト |
| 302 | Redirect | .git-blame-ignore-revs形式エラー | フラッシュメッセージ付きリダイレクト |
| 302 | Redirect | .git-blame-ignore-revsがファイルでない | フラッシュメッセージ付きリダイレクト |

### リトライ仕様

特になし（読み取り専用操作）

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

読み取り専用のため、トランザクション管理は不要

## パフォーマンス要件

- 大きなファイルはページネーションで分割（BlamePagination）
- ストリーミングモードによる段階的読み込み
- Blameモード（BlameMode）による表示最適化

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

- authorize_read_code! による読み取り権限の確認
- ファイルパスのバリデーション（ディレクトリトラバーサル防止）

## 備考

- Blame表示は計算コストが高いため、大きなファイルでは応答が遅くなる可能性がある
- .git-blame-ignore-revsファイルでフォーマット変更コミット等を除外可能

---

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

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

### 推奨読解順序

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

Blame情報を格納するデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | blame.rb | `lib/gitlab/blame.rb` | Blame情報のコアクラス |
| 1-2 | blame_mode.rb | `lib/gitlab/git/blame_mode.rb` | Blameモード設定 |
| 1-3 | blame_pagination.rb | `lib/gitlab/git/blame_pagination.rb` | ページネーション処理 |

**読解のコツ**: Blame情報がどのようにグループ化され、ページ分割されるかを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | blame_controller.rb | `app/controllers/projects/blame_controller.rb` | コントローラーの主要アクション |

**主要処理フロー**:
1. **17-25行目**: show - Blame表示のメインアクション
2. **27-29行目**: streaming - ストリーミングモード
3. **32-36行目**: page - ページネーション用部分取得
4. **41-47行目**: load_blob - ファイル読み込み
5. **66-81行目**: load_blame - Blame情報取得

#### Step 3: Blame取得処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | blame.rb | `lib/gitlab/blame.rb` | Blame情報の取得・グループ化 |
| 3-2 | blame.rb | `lib/gitlab/git/blame.rb` | Gitalyとの連携 |

**主要処理フロー**:
- **70-73行目**: Gitlab::Blame.new - Blame情報の構築
- range パラメータによるページ範囲指定
- ignore_revs パラメータによる除外設定

#### Step 4: プレゼンターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | blame_presenter.rb | `app/presenters/blame_presenter.rb` | Blame表示用プレゼンター |

**主要処理フロー**:
- **75-80行目**: Gitlab::View::Presenter::Factory でプレゼンター生成

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

```
BlameController#show
    │
    ├─ ExtractsPath#assign_ref_vars
    │      └─ Repository#find_branch / find_tag
    │
    ├─ load_blob
    │      └─ Repository#blob_at
    │
    ├─ require_non_binary_blob
    │      └─ Blob#binary? チェック
    │
    ├─ load_environment
    │      └─ EnvironmentsByDeploymentsFinder
    │
    └─ load_blame
           ├─ Gitlab::Git::BlameMode
           ├─ Gitlab::Git::BlamePagination
           └─ Gitlab::Blame
                  └─ Gitlab::Git::Blame
                         └─ Gitaly::CommitService
```

### データフロー図

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

URL パラメータ    ───▶  BlameController         ───▶  HTML
(ref, path)             │
                        ▼
                   load_blob
                   (ファイル取得)
                        │
                        ▼
                   Gitlab::Blame
                        │
                        ▼
                   Gitaly Server ──────────────────▶  Blame情報
                   (Git blame計算)                    (コミット+行)
                        │
                        ▼
                   BlamePresenter ────────────────▶  整形されたBlame表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| blame_controller.rb | `app/controllers/projects/blame_controller.rb` | コントローラー | Blame表示のエントリーポイント |
| blame.rb | `lib/gitlab/blame.rb` | ライブラリ | Blame情報のコアクラス |
| blame.rb | `lib/gitlab/git/blame.rb` | ライブラリ | Gitaly連携 |
| blame_mode.rb | `lib/gitlab/git/blame_mode.rb` | ライブラリ | Blameモード設定 |
| blame_pagination.rb | `lib/gitlab/git/blame_pagination.rb` | ライブラリ | ページネーション |
| blame_presenter.rb | `app/presenters/blame_presenter.rb` | プレゼンター | 表示用プレゼンター |
| extracts_path.rb | `app/controllers/concerns/extracts_path.rb` | Concern | パス・参照の抽出 |
| show.html.haml | `app/views/projects/blame/show.html.haml` | ビュー | Blame表示テンプレート |
| _page.html.haml | `app/views/projects/blame/_page.html.haml` | ビュー | ページ部分テンプレート |
