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

## 概要

本ドキュメントは、NuGetパッケージに含まれるアセンブリのSourceLink情報の整合性を検証するPowerShellスクリプト `eng/common/post-build/sourcelink-validation.ps1` の設計仕様を定義する。

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

このバッチは、シンボルパッケージ（*.symbols.nupkg）に含まれるDLL/EXE/PDBファイルのSourceLink情報を検証する。SourceLinkは、PDBファイルにソースコードのリポジトリURL情報を埋め込む技術であり、本バッチはそれらのURLが実際にアクセス可能かを確認する。

**業務上の目的・背景**：SourceLinkにより、デバッグ時にソースコードを自動的にダウンロードしてステップ実行が可能になる。本バッチは、埋め込まれたソースURLが実際に有効であることを検証し、デバッグ体験の品質を保証する。無効なURLが含まれている場合、ユーザーはソースコードにアクセスできずデバッグが困難になる。

**バッチの実行タイミング**：CIパイプラインのポストビルドステージで、シンボルパッケージ生成後に実行される。

**主要な処理内容**：
1. sourcelink CLIツールのグローバルインストール
2. GitHubリポジトリのファイルツリー取得（キャッシュ用）
3. シンボルパッケージの展開と対象ファイルの抽出
4. sourcelink print-urlsコマンドによるURL抽出
5. 各URLへのHTTP HEADリクエストによるアクセス可能性検証
6. 並列処理による高速検証
7. 検証結果のサマリー報告

**前後の処理との関連**：symbols-validation.ps1やnuget-validation.ps1と並行して実行可能。パッケージ公開前の品質ゲートの一部。

**影響範囲**：パイプラインのビルドステータスに影響。SourceLinkの問題が検出された場合、ビルドが失敗する。

## バッチ種別

検証処理 / SourceLink整合性検証

## 実行スケジュール

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

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| シンボルパッケージの存在 | 検証対象の*.symbols.nupkgファイルが指定パスに存在すること |
| インターネット接続 | GitHubおよびsourcelink CLIのダウンロードのため |
| .NET SDK | dotnet toolコマンドが実行可能であること |
| 書き込み権限 | 展開ディレクトリへの書き込みが可能であること |

### 実行可否判定

InputPathが指定され、対象ディレクトリにシンボルパッケージが存在する場合に実行される。パッケージが存在しない場合は正常終了（ExitWithExitCode 0）。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| InputPath | string | Yes | - | シンボルパッケージが格納されているディレクトリパス |
| ExtractPath | string | Yes | - | パッケージ展開先ディレクトリパス |
| GHRepoName | string | No | - | GitHubリポジトリ名（例：dotnet/arcade） |
| GHCommit | string | No | - | GitHubコミットSHA（40文字の16進数） |
| SourcelinkCliVersion | string | Yes | - | 使用するsourcelink CLIのバージョン |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| *.symbols.nupkg | NuGetパッケージ | 検証対象のシンボルパッケージファイル群 |
| GitHub API | JSON | リポジトリのファイルツリー情報 |
| tools.ps1 | PowerShellスクリプト | 共通ユーティリティ関数 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| コンソール | テキスト | 検証結果メッセージ |
| Azure Pipelines | テレメトリエラー | SourceLinkカテゴリのエラー |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | 展開されたパッケージコンテンツ |
| 出力先 | ExtractPathで指定されたディレクトリ |
| 文字コード | - |
| 区切り文字 | - |

## 処理フロー

### 処理シーケンス

```
1. パラメータ受け取りと初期化
   └─ $ErrorActionPreference = 'Stop'、Set-StrictMode -Version 2.0
2. 入力検証
   └─ InputPathの存在確認（存在しなければ正常終了）
3. sourcelink CLIのインストール
   └─ InstallSourcelinkCli関数で指定バージョンをグローバルインストール
4. GHRepoNameとGHCommitの検証
   └─ 4.1 GHRepoNameのフォーマット検証（<org>/<repo>または<org>-<repo>）
   └─ 4.2 GHCommitのフォーマット検証（40文字16進数）
5. GitHubファイルツリーの取得（オプション・キャッシュ用）
   └─ GitHub API（git/trees/{commit}?recursive=1）でファイル一覧取得
   └─ コード拡張子（.cs, .vb, .fs等）のファイルをHashMapにキャッシュ
6. 展開ディレクトリの初期化
   └─ 既存ディレクトリがあれば削除
7. パッケージごとの検証（並列処理）
   └─ 7.1 パッケージをZIP展開
   └─ 7.2 対象拡張子（.dll, .exe, .pdb）のファイルを抽出
   └─ 7.3 .resources.dllは除外
   └─ 7.4 sourcelink print-urlsでURLを抽出
   └─ 7.5 HTTP(S)のURLを正規表現で抽出
   └─ 7.6 各URLにHTTP HEADリクエスト（GitHubリンクのみ）
   └─ 7.7 サブモジュールリンクはスキップ
   └─ 7.8 最大5回のリトライ（30秒間隔）
8. ジョブ結果の集約
   └─ 失敗件数をカウント
9. 最終結果報告
   └─ 9.1 全成功：正常終了
   └─ 9.2 失敗あり：エラー報告してExitWithExitCode 1
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{InputPath存在?}
    B -->|No| C[正常終了 ExitCode 0]
    B -->|Yes| D[sourcelink CLIインストール]
    D --> E[GHRepoName/GHCommit検証]
    E --> F{両方指定?}
    F -->|Yes| G[GitHub APIでファイルツリー取得]
    F -->|No| H[キャッシュなしで続行]
    G --> I[展開ディレクトリ初期化]
    H --> I
    I --> J[*.symbols.nupkgループ]
    J --> K[Start-Job 並列検証]
    K --> L{16ジョブ以上?}
    L -->|Yes| M[10秒待機]
    M --> L
    L -->|No| N[次のパッケージ]
    N --> J
    J -->|終了| O[全ジョブ待機]
    O --> P[結果集約]
    P --> Q{失敗あり?}
    Q -->|Yes| R[エラー報告]
    R --> S[ExitWithExitCode 1]
    Q -->|No| T[正常終了]
```

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

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

本バッチはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | フォーマットエラー | GHRepoNameまたはGHCommitのフォーマットが不正 | 正しいフォーマットで指定 |
| 1 | URL検証失敗 | SourceLinkのURLがアクセス不可 | ビルド設定とリポジトリ構成を確認 |
| 1 | パッケージ展開失敗 | ZIPファイルが破損 | パッケージを再作成 |

### リトライ仕様

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

### 障害時対応

1. エラーログで問題のファイルとURLを特定
2. SourceLinkのビルド設定を確認
3. GitHubリポジトリへのアクセス権限を確認

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | N/A（読み取り専用操作） |
| コミットタイミング | - |
| ロールバック条件 | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数十〜数百パッケージ |
| 目標処理時間 | パッケージ数とネットワーク速度に依存 |
| メモリ使用量上限 | 並列ジョブ16個分 + GitHubファイルキャッシュ |
| 並列度 | 最大16ジョブ（MaxParallelJobs） |

## 排他制御

Start-Jobによる並列処理を使用。各ジョブはパッケージIDに基づくディレクトリに展開するため、ファイル競合は発生しない。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 進捗ログ | パッケージ検証開始時 | "Validating {PackageName}..." |
| 成功ログ | パッケージ検証成功時 | "Passed." |
| エラーログ | URL検証失敗時 | "File {path} has broken links:" / "Failed to retrieve {url}" |
| エラーログ | パッケージ失敗時 | "{PackagePath} has broken SourceLink links." |
| エラーログ | 最終結果 | "{count} package(s) failed validation." |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| SourceLinkエラー | 1件以上 | Azure Pipelines（ビルド失敗） |

## 備考

- 並列処理により検証を高速化（最大16並列）
- sourcelink CLIツールを使用してPDBからURLを抽出
- GitHubリンクのみを検証（他のホストはスキップ）
- サブモジュールリンクは現在のsourcelinkの制限によりスキップ
- GHRepoNameとGHCommitを指定することで、GitHub APIを使用したファイルキャッシュが有効になり、HTTP リクエスト数を削減可能
- .resources.dllはSourceLink情報を持たないため除外
- 対象拡張子：.dll、.exe、.pdb（PortableおよびEmbedded PDB対応）
- dotnet/arcadeフレームワークの共通スクリプト群の一部
