# 通知設計書 31-ユーザー操作原因（UserIdCause）

## 概要

本ドキュメントは、Jenkins のビルド原因通知機能のうち、ユーザーの手動操作によってビルドがトリガーされた場合に記録・表示される `UserIdCause` の設計について記述する。

### 本通知の処理概要

ユーザー操作原因（UserIdCause）は、Jenkins のビルドがどのような理由で開始されたかを追跡するための `Cause` クラス階層の一部であり、ユーザーの手動操作によってビルドがトリガーされた場合に使用される。

**業務上の目的・背景**：CI/CD パイプラインにおいて、ビルドの実行理由を追跡することは監査、デバッグ、およびチーム内のコミュニケーションにおいて重要である。UserIdCause は、誰がいつビルドを手動で開始したかを記録し、ビルド履歴画面やビルドログに表示することで、ビルドのトレーサビリティを確保する。これにより、予期しないビルドの原因特定や、ビルド実行者への問い合わせが容易になる。

**通知の送信タイミング**：ユーザーが Jenkins の UI（「ビルド実行」ボタンなど）からビルドを手動でトリガーした時点で、現在ログインしているユーザーの情報が `UserIdCause` として記録される。この情報はビルドの `CauseAction` に関連付けられ、ビルドの実行開始時にコンソールログに出力される。

**通知の受信者**：この通知は特定の受信者に送信されるものではなく、ビルド履歴画面やビルドの詳細ページを閲覧するすべてのユーザーが確認できる形で表示される。ビルドのコンソールログにも出力される。

**通知内容の概要**：通知には、ビルドをトリガーしたユーザーの表示名（User Display Name）が含まれる。ユーザーが特定できない場合は「anonymous」と表示される。メッセージの形式は「Started by user {ユーザー名}」となる。

**期待されるアクション**：受信者（ビルド履歴閲覧者）は、ビルドが手動でトリガーされたことを認識し、必要に応じてビルド実行者に連絡を取ることができる。また、監査目的でビルドの実行者を追跡することが可能となる。

## 通知種別

- アプリ内通知（ビルド履歴画面、ビルド詳細ページ）
- コンソールログ出力

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ビルド開始時に即時記録） |
| 優先度 | 中 |
| リトライ | 無（永続化された情報のため） |

### 送信先決定ロジック

送信先は決定されない。ビルド原因情報はビルドオブジェクトに関連付けられ、ビルドの詳細ページやコンソールログを閲覧する全ユーザーに表示される。

## 通知テンプレート

### コンソールログ出力の場合

| 項目 | 内容 |
|-----|------|
| 形式 | テキスト |

### 本文テンプレート

```
Started by user {userName}
```

ユーザーが特定できない場合：
```
Started by user unknown or anonymous
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| userId | ビルドをトリガーしたユーザーのID | `User.current().getId()` | No |
| userName | ビルドをトリガーしたユーザーの表示名 | `User.getById(userId, false).getDisplayName()` | Yes |
| userUrl | ユーザーのプロファイルページURL | `User.getById(userId, false).getUrl()` | No |
| userAvatar | ユーザーのアバター画像 | `Functions.getAvatar(user, "48x48")` | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ユーザーによるビルド実行ボタンクリック | 常に記録 | Jenkins UI からの手動ビルド実行 |
| API | REST API 経由のビルドトリガー | ユーザー認証が行われている場合 | API 経由でビルドをトリガーした場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | ユーザーの手動操作によるビルドでは常に記録される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがビルド実行ボタンをクリック] --> B[UserIdCauseインスタンス生成]
    B --> C[User.current()でログインユーザー取得]
    C --> D{ユーザーが存在?}
    D -->|Yes| E[userIdにユーザーIDを設定]
    D -->|No| F[userIdをnullに設定]
    E --> G[CauseActionにUserIdCauseを追加]
    F --> G
    G --> H[ビルドキューに投入]
    H --> I[ビルド開始時にonAddedToコールバック]
    I --> J[コンソールログにprintメソッドで出力]
    J --> K[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

Jenkinsはファイルベースの永続化を使用しており、従来のRDBMSは使用しない。

| ストレージ | 用途 | 備考 |
|-----------|------|------|
| users/{userId}/config.xml | ユーザー情報の取得 | User.getById()で参照 |
| jobs/{jobName}/builds/{buildNumber}/build.xml | ビルド情報とCauseの永続化 | XStreamでシリアライズ |

### 参照項目詳細

#### User オブジェクト

| 参照項目 | 用途 | 取得条件 |
|-------------------|------|---------|
| id | ユーザーの一意識別子 | User.current()またはUser.getById() |
| displayName | UI表示用のユーザー名 | User.getDisplayName() |
| url | ユーザープロファイルへのURL | User.getUrl() |

### 更新テーブル一覧

| ストレージ | 操作 | 概要 |
|-----------|------|------|
| jobs/{jobName}/builds/{buildNumber}/build.xml | INSERT | ビルド情報にCauseを含めて永続化 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ユーザー不明 | User.current()がnullを返す場合 | userIdをnullに設定し、表示名を「anonymous」とする |
| ユーザー取得失敗 | User.getById()がnullを返す場合 | 表示名を「anonymous」とする |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限なし | ビルドごとに1回記録されるため制限不要 |

### 配信時間帯

制限なし（ビルド実行時に即時記録）

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

- ユーザーIDは内部識別子として使用され、外部には表示名のみが公開される
- ビルド履歴へのアクセスはJenkinsの認可設定に従う
- XSS対策として、Jenkins 2.315以降では`getShortDescription()`の戻り値はテキストとして解釈される

## 備考

- `UserIdCause`は Jenkins 1.427 で導入され、それ以前の`UserCause`（非推奨）を置き換えた
- ユーザーIDを明示的に指定するコンストラクタ`UserIdCause(String userId)`は Jenkins 2.96 で追加された

---

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

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

### 推奨読解順序

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

まず、ビルド原因を表現するデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Cause.java | `core/src/main/java/hudson/model/Cause.java` | Causeクラス階層の基底クラス。getShortDescription()とprint()メソッドの役割を理解する |
| 1-2 | Cause.java (UserIdCause) | `core/src/main/java/hudson/model/Cause.java` 417-500行 | UserIdCauseの実装。userId、getUserName()、getShortDescription()の実装を確認 |

**読解のコツ**: `@Exported`アノテーションは REST API で公開されるプロパティを示す。`@CheckForNull`は null を返す可能性があることを示す。

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

処理の起点となるUserIdCauseのコンストラクタを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Cause.java | `core/src/main/java/hudson/model/Cause.java` 425-428行 | デフォルトコンストラクタ。User.current()で現在のユーザーを取得 |
| 2-2 | Cause.java | `core/src/main/java/hudson/model/Cause.java` 435-437行 | userIdを明示的に指定するコンストラクタ |

**主要処理フロー**:
1. **425行**: `UserIdCause()`コンストラクタが呼ばれる
2. **426行**: `User.current()`で現在ログインしているユーザーを取得
3. **427行**: ユーザーが存在すれば`user.getId()`、なければnullをuserIdに設定

#### Step 3: 表示ロジックを理解する

ビルド履歴画面やコンソールログへの出力方法を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Cause.java | `core/src/main/java/hudson/model/Cause.java` 474-477行 | getShortDescription()の実装 |
| 3-2 | Cause.java | `core/src/main/java/hudson/model/Cause.java` 480-489行 | print()メソッドでコンソールログへ出力 |

**主要処理フロー**:
- **474行**: `getShortDescription()`が呼ばれる
- **476行**: `Messages.Cause_UserIdCause_ShortDescription(getUserName())`でメッセージを生成
- **481行**: `print()`メソッドでユーザーIDからUserオブジェクトを取得
- **483-484行**: ユーザーが存在すれば`ModelHyperlinkNote.encodeTo(user)`でリンク付きで出力

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

```
ユーザーがビルド実行ボタンをクリック
    │
    ├─ new UserIdCause()
    │      └─ User.current()
    │             └─ user.getId()
    │
    ├─ CauseAction.addCause(cause)
    │
    └─ Build.run()
           └─ cause.onAddedTo(build)
           └─ cause.print(listener)
                  ├─ getUserId()
                  ├─ User.getById(userId, false)
                  └─ listener.getLogger().println()
```

### データフロー図

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

User.current() ───▶ UserIdCause() ───▶ userId (String)
                          │
                          ▼
                    CauseAction
                          │
                          ▼
                    Build.run()
                          │
                          ▼
                    print(listener)
                          │
                          ▼
                    [コンソールログ]
                    [ビルド詳細ページ]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Cause.java | `core/src/main/java/hudson/model/Cause.java` | ソース | Cause基底クラスとUserIdCauseの定義 |
| CauseAction.java | `core/src/main/java/hudson/model/CauseAction.java` | ソース | ビルドにCauseを関連付けるAction |
| User.java | `core/src/main/java/hudson/model/User.java` | ソース | Jenkinsユーザーモデル |
| Messages.properties | `core/src/main/resources/hudson/model/Messages.properties` | リソース | メッセージ定義 |
| description.jelly | `core/src/main/resources/hudson/model/Cause/UserIdCause/description.jelly` | テンプレート | UI表示用Jellyテンプレート |
