# バッチ設計書 70-sourcelink-validation.ps1

## 概要

本ドキュメントは、リリース前にNuGetパッケージ内のデバッグシンボルのSourceLink設定を検証するためのPowerShellスクリプト `eng/common/post-build/sourcelink-validation.ps1` の設計仕様を記載する。

### 本バッチの処理概要

このバッチは、Symbols.NuGetパッケージに含まれるDLL/EXE/PDBファイルのSourceLink情報を検証し、ソースコードへのリンクが正しく機能するかを確認する。sourcelink CLIツールを使用してSourceLinkメタデータを抽出し、各リンクがGitHubリポジトリ上で有効かを検証する。

**業務上の目的・背景**：SourceLinkは、デバッガーがシンボルからソースコードを自動的にダウンロードできるようにする技術である。.NETランタイムをリリースする際、SourceLink設定が正しく機能することは、開発者がステップ実行デバッグで.NETのソースコードに直接ナビゲートできるために不可欠である。

**バッチの実行タイミング**：CI/CDパイプラインのポストビルドフェーズで実行される。パッケージ公開前の検証ステップとして構成される。

**主要な処理内容**：
1. sourcelink CLIツールのインストール
2. Symbols.NuGetパッケージの展開
3. DLL/EXE/PDBファイルからSourceLink情報の抽出
4. GitHub APIを使用したソースファイルの存在確認
5. 検証結果のレポート

**前後の処理との関連**：本スクリプトはtools.ps1を読み込む。パッケージビルド完了後、公開前に実行される。

**影響範囲**：検証のみであり、パッケージには影響しない。検証結果に基づいてリリース可否が判断される。

## バッチ種別

検証 / SourceLink検証 / ポストビルド

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（リリースビルド時） |
| 実行時刻 | - |
| 実行曜日 | - |
| 実行日 | - |
| トリガー | CI/CDパイプライン |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| PowerShell | PowerShell 5.1以降が利用可能であること |
| ネットワーク接続 | GitHub APIへのアクセスが可能であること |
| dotnet CLI | dotnet toolインストールが可能であること |
| Symbols.NuGetパッケージ | 検証対象の.symbols.nupkgファイルが存在すること |

### 実行可否判定

- InputPathが存在しない場合は正常終了（検証対象なし）
- GHRepoNameとGHCommitが両方指定されている場合はキャッシュ機能が有効

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| InputPath | string | Yes | - | Symbols.NuGetパッケージ格納ディレクトリ |
| ExtractPath | string | Yes | - | パッケージ展開先ディレクトリ |
| GHRepoName | string | No | - | GitHubリポジトリ名（org/repo形式） |
| GHCommit | string | No | - | GitHubコミットSHA（40文字16進数） |
| SourcelinkCliVersion | string | Yes | - | sourcelink CLIツールのバージョン |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| *.symbols.nupkg | ZIP/NuGet | 検証対象シンボルパッケージ |
| GitHub API | REST API | ソースファイル存在確認 |
| tools.ps1 | PowerShellスクリプト | 共通関数 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 標準出力 | テキスト | 検証進捗と結果 |
| 終了コード | int | 0:全リンク有効、1:リンク切れあり |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| 展開ディレクトリ | $ExtractPath\{PackageId}\ |
| 一時ファイル | GUID付きファイル名で展開 |

## 処理フロー

### 処理シーケンス

```
1. sourcelink CLIインストール
   └─ dotnet tool install --global
2. リポジトリファイルキャッシュ構築（オプション）
   └─ GHRepoName/GHCommit指定時、GitHub APIでファイルリストを取得
3. パッケージループ開始
   └─ *.symbols.nupkgファイルを順次処理
4. パッケージ展開
   └─ ZipFile.OpenReadで開いてファイルを抽出
5. ファイル検証（並列）
   └─ .dll/.exe/.pdbファイルを処理
6. SourceLink情報抽出
   └─ sourcelink print-urlsコマンド実行
7. リンク検証
   └─ 各URLに対してHTTP HEADリクエスト
8. 結果判定
   └─ リンク切れファイル数をカウント
9. 結果集計
   └─ 失敗パッケージ数を報告
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{InputPath存在?}
    B -->|No| C[正常終了]
    B -->|Yes| D[sourcelink CLIインストール]
    D --> E{GHRepoName/GHCommit指定?}
    E -->|Yes| F[GitHub APIでファイルリスト取得]
    E -->|No| G[パッケージループ開始]
    F --> G
    G --> H{*.symbols.nupkgあり?}
    H -->|No| I[結果集計]
    H -->|Yes| J[Start-Job並列実行]
    J --> K[ZipFile.OpenRead]
    K --> L[ファイル抽出]
    L --> M{.dll/.exe/.pdb?}
    M -->|No| N[次のファイル]
    M -->|Yes| O{.resources.dll?}
    O -->|Yes| N
    O -->|No| P[sourcelink print-urls]
    P --> Q[URLパターンマッチ]
    Q --> R{GitHubリンク?}
    R -->|No| S[スキップ]
    R -->|Yes| T[Invoke-WebRequest HEAD]
    S --> N
    T --> U{ステータス200?}
    U -->|Yes| N
    U -->|No| V[リトライ/失敗カウント]
    V --> N
    N --> W{ファイル完了?}
    W -->|No| M
    W -->|Yes| X[Job完了]
    X --> G
    I --> Y{失敗あり?}
    Y -->|Yes| Z[エラー終了]
    Y -->|No| AA[正常終了]
```

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

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

本スクリプトはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | GHRepoName形式エラー | org/repo形式でない | 正しい形式で指定 |
| 1 | GHCommit形式エラー | 40文字16進数でない | 正しいコミットSHAを指定 |
| 1 | リンク切れ | SourceLinkのURLが無効 | SourceLink設定を確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 5回（MaxRetries） |
| リトライ間隔 | 30秒（RetryWaitTimeInSeconds） |
| リトライ対象エラー | HTTP リクエスト失敗 |

### 障害時対応

1. エラーメッセージを確認し、該当パッケージ・ファイルを特定
2. SourceLink設定（csprojのSourceLinkプロパティ）を確認
3. ビルド時のGitリポジトリ状態を確認

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | - |
| コミットタイミング | - |
| ロールバック条件 | - |

本スクリプトはトランザクション管理を行わない。

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数十〜数百パッケージ |
| 目標処理時間 | パッケージ数とネットワーク速度依存 |
| メモリ使用量上限 | パッケージ展開サイズ依存 |
| 並列ジョブ数 | 16（MaxParallelJobs） |

## 排他制御

並列ジョブごとに異なる展開ディレクトリを使用するため、排他制御は不要。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 情報ログ | 検証開始時 | "Validating $PackageName..." |
| 情報ログ | 検証成功時 | "Passed." |
| 警告ログ | リトライ時 | "Download failed, $attemptsLeft attempts remaining..." |
| エラーログ | リンク切れ時 | "File $RealPath has broken links:" / "Failed to retrieve $Link" |
| エラーログ | パッケージ失敗時 | "$PackagePath has broken SourceLink links." |
| エラーログ | 検証失敗時 | "$ValidationFailures package(s) failed validation." |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 終了コード | 0以外 | CI/CDパイプライン（Write-PipelineTelemetryError） |
| 失敗パッケージ数 | 1以上 | CI/CDパイプラインログ（カテゴリ：SourceLink） |

## 備考

- 検証対象拡張子：.dll、.exe、.pdb
- .resources.dllはスキップされる（リソースDLLにはSourceLinkなし）
- GHRepoNameはorg/repo形式またはorg-repo形式（後者は自動変換）
- GHCommitは40文字の16進数文字列
- submodulesを含むリンクはスキップされる（SourceLinkの既知の問題）
- GitHub以外のリンク（非github/githubusercontent）はスキップされる
- キャッシュ機能：GHRepoName/GHCommit指定時、リポジトリのファイルリストをHashMapにキャッシュして高速化
- SecondsBetweenLoadChecks（10秒）間隔でジョブ数を監視
- sourcelink print-urlsコマンドでSourceLinkメタデータを抽出
- Invoke-WebRequest -Method HEADでリンク有効性を確認（コンテンツダウンロード不要）
- タイムアウト：5秒（-TimeoutSec 5）
