# 機能設計書 23-SCMトリガー

## 概要

本ドキュメントは、JenkinsのSCMトリガー（SCMTrigger）機能の設計仕様を定義する。SCMトリガーは、ソースコード管理システムの変更を定期的にポーリングし、変更が検出された場合に自動的にビルドを開始するトリガー機構を提供する。

### 本機能の処理概要

SCMトリガーは、設定されたcronスケジュールに従ってSCMリポジトリをポーリングし、前回のビルド以降に変更があった場合にビルドをトリガーする機能である。

**業務上の目的・背景**：継続的インテグレーションの基本的な要件として、ソースコードの変更を検知して自動的にビルドを実行することがある。SCMトリガーは、Webhookが利用できない環境やレガシーなSCMシステムとの連携において、ポーリング方式でこの要件を満たすための機能を提供する。

**機能の利用シーン**：
- Webhookが設定できないプライベートSCMサーバーとの連携
- 社内ファイアウォール内のSVN/CVSリポジトリの監視
- Gitリポジトリの定期的な変更チェック
- 複数リポジトリの統合的な変更監視

**主要な処理内容**：
1. cronスケジュールに基づく定期的なポーリング実行
2. SCMシステムからの変更ログ取得
3. 前回ビルド以降の変更有無の判定
4. 変更検出時のビルドトリガー
5. ポーリングログの記録と表示
6. 同期ポーリングモードによる依存関係順でのポーリング

**関連システム・外部連携**：各種SCMプラグイン（Git、Subversion、CVS等）、Triggerシステム、PollingSchedulerとの連携。

**権限による制御**：ジョブの設定権限を持つユーザーがSCMトリガーの設定を変更可能。ポーリングログの閲覧にはジョブへのアクセス権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | ジョブ設定 | 主画面 | SCMトリガーの設定・編集 |
| 44 | SCMポーリングログ | 補助画面 | ポーリング結果の確認 |

## 機能種別

トリガー / ポーリング機構

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| spec | String | Yes | cronスケジュール指定 | 有効なcron構文 |
| ignorePostCommitHooks | boolean | No | post-commitフック無視フラグ | true/false |

### 入力データソース

ジョブ設定画面からの設定値。cronスケジュールはHash関数を使用してジョブごとに分散される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PollingResult | PollingResult | ポーリング結果（BUILD_NOW/NO_CHANGES/SIGNIFICANT_CHANGES） |
| PollingLog | SCMTriggerAction | ポーリングログのアクションオブジェクト |

### 出力先

- ビルドキューへのジョブ追加
- ポーリングログファイル（$JENKINS_HOME/jobs/[job]/polling.log）

## 処理フロー

### 処理シーケンス

```
1. Cron.doRun() が毎分実行
   └─ Trigger.checkTriggers(Calendar) を呼び出し
2. SCMTrigger.run() 実行
   └─ PollingScheduler.schedule() によるタスクスケジュール
3. Runner.run() 実行
   └─ SCM.poll() によるポーリング実行
4. ポーリング結果の判定
   ├─ BUILD_NOW: ビルドをスケジュール
   ├─ SIGNIFICANT_CHANGES: ビルドをスケジュール（追加情報付き）
   └─ NO_CHANGES: 何もしない
5. PollingLogActionの更新
   └─ ポーリングログファイルへの記録
```

### フローチャート

```mermaid
flowchart TD
    A[cronスケジュール一致] --> B[SCMTrigger.run]
    B --> C[PollingScheduler.schedule]
    C --> D[Runner.run]
    D --> E[SCM.poll実行]
    E --> F{ポーリング結果}
    F -->|BUILD_NOW| G[ビルドをスケジュール]
    F -->|SIGNIFICANT_CHANGES| H[追加情報付きでビルドをスケジュール]
    F -->|NO_CHANGES| I[スキップ]
    G --> J[PollingLogAction更新]
    H --> J
    I --> J
    J --> K[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | ポーリング間隔制限 | SCMへの負荷軽減のため、Hシンタックスによる分散を推奨 | cronスケジュール設定時 |
| BR-002 | post-commitフック無視 | ignorePostCommitHooksがtrueの場合、post-commitによるトリガーを無視 | ポーリング設定時 |
| BR-003 | 同期ポーリング | synchronousPollingがtrueの場合、依存関係順でポーリングを実行 | グローバル設定時 |
| BR-004 | 最大同時ポーリング数 | maximumThreadsで同時ポーリング数を制限 | ポーリング実行時 |

### 計算ロジック

```java
// H（ハッシュ）シンタックスによるジョブごとの分散
// 例: "H/15 * * * *" はジョブ名のハッシュ値に基づいて0-14分の間で分散
Hash hash = Hash.from(job.getFullName());
CronTabList tabs = CronTabList.create(spec, hash);
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ポーリングログ記録 | polling.log | INSERT/UPDATE | ポーリング結果のログ記録 |
| 設定保存 | config.xml | INSERT/UPDATE | SCMトリガー設定の永続化 |

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

#### polling.log（ポーリングログファイル）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | ログエントリ | ポーリング日時、結果、変更内容 | RotatingFileWriterによるローテーション |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IOException | SCMアクセス時のI/Oエラー | ログ記録してスキップ |
| - | InterruptedException | ポーリング中断 | 例外伝播 |
| - | AbortException | SCMが設定されていない | ログに警告を出力 |
| - | IllegalArgumentException | 無効なcronスケジュール | 設定時にエラー表示 |

### リトライ仕様

ポーリング失敗時のリトライは自動的には行わない。次回のcronスケジュールで再度ポーリングが実行される。

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

トランザクション管理はない。ポーリングとビルドトリガーは非同期で実行される。

## パフォーマンス要件

- ポーリングが30秒以上かかる場合、SlowTriggerAdminMonitorで警告
- maximumThreads（デフォルト10）で同時ポーリング数を制限
- PollingSchedulerによるスレッドプール管理

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

- SCMアクセスには適切な認証情報が必要
- ポーリングログにはSCMの詳細情報が含まれる可能性があるため、ジョブアクセス権限で保護

## 備考

- Webhookが利用可能な場合は、ポーリングよりもWebhook方式を推奨（SCM負荷軽減）
- H（ハッシュ）シンタックスはJenkins 1.445で導入

---

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

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

### 推奨読解順序

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

SCMTriggerのフィールド構造とネストクラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SCMTrigger.java | `core/src/main/java/hudson/triggers/SCMTrigger.java` | クラスフィールド（spec, ignorePostCommitHooks） |
| 1-2 | Trigger.java | `core/src/main/java/hudson/triggers/Trigger.java` | 親クラスの抽象定義、CronTabList |

**読解のコツ**: SCMTriggerはTriggerを継承し、Runnerという内部クラスでポーリング処理を実行する。PollingResultがポーリング結果を表す列挙型。

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

cronスケジュールからの起動フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Trigger.java | `core/src/main/java/hudson/triggers/Trigger.java` | Cron.doRun()、checkTriggers()メソッド |
| 2-2 | SCMTrigger.java | `core/src/main/java/hudson/triggers/SCMTrigger.java` | run()メソッド |

**主要処理フロー**:
1. **Trigger.java 238-250行目**: Cron.doRun() - 毎分実行されるエントリーポイント
2. **Trigger.java 256-329行目**: checkTriggers() - 各トリガーのチェック
3. **SCMTrigger.java 188-201行目**: run() - ポーリングスケジュール

#### Step 3: ポーリング実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SCMTrigger.java | `core/src/main/java/hudson/triggers/SCMTrigger.java` | Runner内部クラス |

**主要処理フロー**:
- **294-298行目**: Runner.run() - ポーリングの実行
- **300-330行目**: ポーリング結果の処理とビルドスケジュール
- **332-350行目**: PollingLogActionへのログ記録

#### Step 4: Descriptorを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SCMTrigger.java | `core/src/main/java/hudson/triggers/SCMTrigger.java` | DescriptorImpl |

**主要処理フロー**:
- **365-380行目**: DescriptorImpl - maximumThreads、synchronousPolling設定
- **382-395行目**: PollingScheduler/getExecutorメソッド

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

```
Cron.doRun() [毎分実行]
    │
    └─ Trigger.checkTriggers(Calendar)
           │
           ├─ SCMTrigger.tabs.check(Calendar)
           │      └─ cronスケジュール判定
           │
           └─ SCMTrigger.run()
                  │
                  └─ PollingScheduler.schedule(Runner)
                         │
                         └─ Runner.run()
                                │
                                ├─ SCM.poll(project, launcher, workspace, listener, baseline)
                                │      └─ ポーリング結果取得
                                │
                                ├─ project.scheduleBuild(SCMTriggerCause)
                                │      └─ ビルドキューへ追加
                                │
                                └─ PollingLogAction.log.write()
                                       └─ ポーリングログ記録
```

### データフロー図

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

cronスケジュール     SCMTrigger
(spec)          ├─ CronTabList.check() ───▶   ポーリング実行判定
                │
ジョブ設定      ├─ Runner.run()
(ignorePostCommitHooks)├─ SCM.poll() ───────────▶   PollingResult
                │
SCMリポジトリ   ├─ scheduleBuild() ─────────▶   ビルドキュー追加
(変更情報)      │
                └─ PollingLogAction ─────────▶   polling.log
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SCMTrigger.java | `core/src/main/java/hudson/triggers/SCMTrigger.java` | ソース | SCMトリガーの実装クラス |
| Trigger.java | `core/src/main/java/hudson/triggers/Trigger.java` | ソース | トリガーの抽象基底クラス |
| TriggerDescriptor.java | `core/src/main/java/hudson/triggers/TriggerDescriptor.java` | ソース | トリガーDescriptor基底クラス |
| SCM.java | `core/src/main/java/hudson/scm/SCM.java` | ソース | SCM抽象クラス（poll()メソッド） |
| PollingResult.java | `core/src/main/java/hudson/scm/PollingResult.java` | ソース | ポーリング結果の列挙型 |
| CronTabList.java | `core/src/main/java/hudson/scheduler/CronTabList.java` | ソース | cronスケジュール解析 |
| Hash.java | `core/src/main/java/hudson/scheduler/Hash.java` | ソース | H構文のハッシュ計算 |
| SlowTriggerAdminMonitor.java | `core/src/main/java/hudson/triggers/SlowTriggerAdminMonitor.java` | ソース | 遅いトリガーの監視 |
