# 機能設計書 19-フィンガープリント

## 概要

本ドキュメントは、Jenkinsにおけるフィンガープリント機能の設計について記述する。この機能は、ビルド成果物のMD5ハッシュを記録し、ファイルの追跡や依存関係の可視化を可能にするビルド後処理を提供する。

### 本機能の処理概要

フィンガープリント機能は、ビルド後処理（Recorder）として指定されたファイルのMD5ハッシュを計算・記録する。記録されたフィンガープリントはビルド間で共有され、同一ファイルを使用するビルドを追跡できる。

**業務上の目的・背景**：CI/CDパイプラインでは、ビルド成果物がどのビルドで生成され、どのビルドで使用されたかを追跡する必要がある。フィンガープリント機能により、JARファイルなどの成果物の由来を特定し、依存関係グラフを構築できる。

**機能の利用シーン**：
- 共有ライブラリの使用状況追跡
- ビルド成果物の由来特定
- 依存関係の可視化
- 特定ファイルを使用したビルドの一覧表示
- ビルド間のファイル受け渡し追跡

**主要な処理内容**：
1. Antスタイルグロブパターンによるファイルマッチング
2. FindRecordsでワークスペースからファイル一覧取得
3. FilePath.digest()でMD5ハッシュ計算
4. FingerprintMapへのフィンガープリント登録
5. FingerprintActionによるビルドへの関連付け
6. DependencyGraph連携による依存関係追跡

**関連システム・外部連携**：FingerprintMap、FingerprintStorage、DependencyGraph。

**権限による制御**：Job.CONFIGURE権限でビルドステップの設定変更が可能。Item.READ権限でフィンガープリント情報の参照が可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | ジョブ設定 | 主画面 | フィンガープリント設定の追加・編集 |
| 10 | ビルド詳細 | 結果表示画面 | フィンガープリント一覧の表示 |

## 機能種別

ビルド後処理 / ファイル追跡

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| targets | String | Yes | フィンガープリント対象ファイルパターン | Antグロブパターン |
| excludes | String | No | 除外するファイルパターン | - |
| defaultExcludes | boolean | No | Antデフォルト除外を適用 | デフォルトtrue |
| caseSensitive | boolean | No | 大文字小文字を区別 | デフォルトtrue |

### 入力データソース

- ジョブ設定画面からのユーザー入力
- ワークスペースファイルシステム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Fingerprint | Fingerprint | MD5ハッシュとメタデータ |
| FingerprintAction | Action | ビルドに関連付けられたフィンガープリント一覧 |

### 出力先

- FingerprintStorage（XMLファイルまたは外部ストレージ）
- ビルドアクション（FingerprintAction）

## 処理フロー

### 処理シーケンス

```
1. Fingerprinter.perform()呼び出し
2. targets展開（環境変数）
3. FindRecords.invoke()でファイル走査
   └─ FileSetによるAntパターンマッチング
   └─ FilePath.digest()でMD5計算
   └─ Recordオブジェクト作成
4. Record.addRecord()でFingerprintMap登録
   └─ getOrCreate()で既存or新規Fingerprint取得
5. fp.addFor()で使用ビルドを記録
6. FingerprintAction追加/更新
7. enableFingerprintsInDependencyGraph時
   └─ Jenkins.rebuildDependencyGraphAsync()
```

### フローチャート

```mermaid
flowchart TD
    A[perform開始] --> B{targets空?}
    B -->|Yes| C[スキップ]
    B -->|No| D[環境変数展開]
    D --> E[FindRecords.invoke]
    E --> F{各ファイル処理}
    F --> G[FilePath.digest]
    G --> H[Record作成]
    H --> I{produced判定}
    I -->|buildTimestamp比較| J[Record.addRecord]
    J --> K[FingerprintMap.getOrCreate]
    K --> L[fp.addFor]
    L --> M{次のファイル?}
    M -->|Yes| F
    M -->|No| N{FingerprintAction存在?}
    N -->|Yes| O[action.add]
    N -->|No| P[新規FingerprintAction]
    O --> Q{enableFingerprintsInDependencyGraph?}
    P --> Q
    Q -->|Yes| R[rebuildDependencyGraphAsync]
    Q -->|No| S[完了]
    R --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-19-01 | produced判定 | ファイルタイムスタンプがbuildTimestamp+2000ms以降なら生成者 | 常時 |
| BR-19-02 | デフォルト除外 | defaultExcludes=trueでAntデフォルト除外パターン適用 | デフォルト |
| BR-19-03 | 大文字小文字区別 | caseSensitive=trueで大文字小文字を区別 | デフォルト |
| BR-19-04 | 依存関係グラフ | enableFingerprintsInDependencyGraph=trueで依存関係追加 | システムプロパティ設定時 |
| BR-19-05 | 自己参照回避 | 同一プロジェクトへの依存は追加しない | buildDependencyGraph |

### 計算ロジック

- MD5ハッシュ: FilePath.digest()でMD5計算
- produced判定: buildTimestamp <= file.lastModified() + 2000

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

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

本機能はデータベースではなく、ファイルシステム（またはFingerprintStorage）を使用。

| 操作 | 対象 | 操作種別 | 概要 |
|-----|-----|---------|------|
| Fingerprint保存 | fingerprints/{hash}.xml | INSERT/UPDATE | フィンガープリントの永続化 |
| 設定保存 | jobs/{job}/config.xml | UPDATE | Fingerprinter設定の永続化 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IOException | ダイジェスト計算失敗 | エラーログ出力、Result.FAILURE設定 |
| - | InterruptedException | 処理中断 | 例外ラップ、処理停止 |
| - | AccessDeniedException | アクセス権限なし | 警告ログ、対象スキップ |

### リトライ仕様

リトライはユーザーによる手動再実行のみ。フィンガープリント記録失敗はビルド失敗にならない（エラーだが致命的ではない）。

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

- BuildStepMonitor.NONEで排他制御なし

## パフォーマンス要件

- MD5計算はリモートエージェントで実行（MasterToSlaveFileCallable）
- PackedMapによるメモリ効率化（String.intern()使用）
- WeakReferenceによるFingerprint参照キャッシュ

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

- MasterToSlaveFileCallableでセキュアなリモート呼び出し
- Item.READ/Item.DISCOVER権限チェックによる情報漏洩防止
- getDependencies()でのAccessDeniedException適切な処理

## 備考

- @Symbol("fingerprint")でPipeline DSLからはfingerprintとして参照可能
- SimpleBuildStepを実装しており、Pipeline互換
- DependencyDeclarerを実装し、依存関係グラフへの参加が可能
- enableFingerprintsInDependencyGraphはシステムプロパティで制御

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Fingerprinter.java | `core/src/main/java/hudson/tasks/Fingerprinter.java` | フィンガープリントRecorder |
| 1-2 | Fingerprint.java | `core/src/main/java/hudson/model/Fingerprint.java` | フィンガープリントデータモデル |
| 1-3 | FingerprintAction | `core/src/main/java/hudson/tasks/Fingerprinter.java` 内部クラス | ビルドアクション |

#### Step 2: perform()メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | perform() | `core/src/main/java/hudson/tasks/Fingerprinter.java` | メイン処理（179-209行目） |

**主要処理フロー**:
- **181行目**: 記録開始メッセージ出力
- **185-191行目**: targets展開とrecord()呼び出し
- **193-198行目**: FingerprintAction追加/更新
- **200-202行目**: enableFingerprintsInDependencyGraph時の依存グラフ再構築
- **203-206行目**: IOException時のエラー処理（Result.FAILURE）

#### Step 3: FindRecordsを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FindRecords | `core/src/main/java/hudson/tasks/Fingerprinter.java` 内部クラス | ファイル走査（278-323行目） |

**主要処理フロー**:
- **298-300行目**: FileSet作成とオプション設定
- **302-303行目**: DirectoryScanner.getIncludedFiles()
- **309行目**: produced判定（タイムスタンプ比較）
- **312行目**: FilePath.digest()でMD5計算

#### Step 4: Fingerprintデータモデルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BuildPtr | `core/src/main/java/hudson/model/Fingerprint.java` | ビルドへのポインタ（90-219行目） |
| 4-2 | Range/RangeSet | `core/src/main/java/hudson/model/Fingerprint.java` | ビルド番号範囲（225-814行目） |
| 4-3 | usages | `core/src/main/java/hudson/model/Fingerprint.java` | ジョブ名→ビルド番号範囲マップ（865行目） |

**主要処理フロー**:
- **874-884行目**: Fingerprintコンストラクタ（original, fileName, md5sum）
- **1017-1019行目**: addFor()でビルド使用記録追加
- **1057-1075行目**: isAlive()で有効判定
- **1085-1139行目**: trim()で古い参照削除

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

```
AbstractBuild.run()
    │
    └─ Fingerprinter.perform()
           │
           ├─ record()
           │      │
           │      └─ ws.act(FindRecords)
           │             │
           │             ├─ Util.createFileSet() → FileSet
           │             │      │
           │             │      └─ DirectoryScanner.getIncludedFiles()
           │             │
           │             └─ FilePath.digest() → MD5ハッシュ
           │
           ├─ Record.addRecord()
           │      │
           │      └─ FingerprintMap.getOrCreate()
           │             │
           │             └─ Fingerprint(BuildPtr, fileName, md5sum)
           │
           ├─ fp.addFor(build) → usages更新
           │
           ├─ FingerprintAction追加
           │
           └─ [enableFingerprintsInDependencyGraph]
                  │
                  └─ Jenkins.rebuildDependencyGraphAsync()
```

### データフロー図

```
┌─────────────────┐     ┌──────────────────┐     ┌────────────────────┐
│  ワークスペース   │────→│  FindRecords     │────→│  Record            │
│  (ファイル群)    │     │  (MasterToSlave) │     │  (produced,path,   │
└─────────────────┘     └──────────────────┘     │   fileName,md5sum) │
                                                  └────────────────────┘
                                                           │
                                                           ▼
┌─────────────────┐     ┌──────────────────┐     ┌────────────────────┐
│  FingerprintMap │←────│  Record.addRecord│←────│  FilePath.digest() │
│  (グローバル)    │     │                  │     │  (MD5計算)         │
└─────────────────┘     └──────────────────┘     └────────────────────┘
        │
        ▼
┌─────────────────┐     ┌──────────────────┐     ┌────────────────────┐
│  Fingerprint    │────→│  fp.addFor()     │────→│  usages更新        │
│  (original,     │     │                  │     │  (jobName→RangeSet)│
│   usages, ...)  │     └──────────────────┘     └────────────────────┘
└─────────────────┘
        │
        ▼
┌─────────────────┐
│FingerprintAction│
│ (ビルドに関連付け)│
└─────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Fingerprinter.java | `core/src/main/java/hudson/tasks/Fingerprinter.java` | ソース | フィンガープリントRecorder |
| Fingerprint.java | `core/src/main/java/hudson/model/Fingerprint.java` | ソース | フィンガープリントデータモデル |
| FingerprintMap.java | `core/src/main/java/hudson/model/FingerprintMap.java` | ソース | フィンガープリントマップ |
| FingerprintStorage.java | `core/src/main/java/jenkins/fingerprints/FingerprintStorage.java` | ソース | ストレージ抽象クラス |
| FileFingerprintStorage.java | `core/src/main/java/jenkins/fingerprints/FileFingerprintStorage.java` | ソース | ファイルベースストレージ |
| Recorder.java | `core/src/main/java/hudson/tasks/Recorder.java` | ソース | 結果変更Publisher基底クラス |
| DependencyDeclarer.java | `core/src/main/java/jenkins/model/DependencyDeclarer.java` | ソース | 依存関係宣言インターフェース |
