# 帳票設計書 5-GitHubActionsReporter

## 概要

本ドキュメントは、Jestテストフレームワークにおける GitHub Actions 環境向けレポーター「GitHubActionsReporter」の設計仕様を定義する。GitHubActionsReporterは、テスト失敗時に GitHub Actions のアノテーション形式（::error, ::warning）でエラー情報を出力し、GitHub のプルリクエスト画面でインラインエラー表示を可能にするレポーターである。

### 本帳票の処理概要

GitHubActionsReporterは、GitHub Actions 環境でのテスト実行時に使用されるレポーターであり、テスト失敗時にGitHub Actionsのワークフローコマンド形式でアノテーションを出力する。これにより、GitHub のプルリクエスト画面のFiles changedタブで、失敗したテストのエラーメッセージがソースコードの該当行にインライン表示される。また、リトライが発生した場合は警告として出力する。

**業務上の目的・背景**：CI/CDパイプラインにおいて、テスト失敗の原因を素早く特定することは開発効率に直結する。GitHubActionsReporterは、テスト失敗情報をGitHub Actionsのネイティブ形式で出力することで、ビルドログを解析することなく、プルリクエスト画面から直接エラー箇所を確認できるようにする。これにより、コードレビューとテスト結果確認のワークフローが統合され、開発者の生産性が向上する。

**帳票の利用シーン**：GitHub Actionsワークフロー内でJestテストを実行する場合に使用される。プルリクエストのCIチェック、main/masterブランチへのマージ前テスト、定期実行テストなどで活用される。

**主要な出力内容**：
1. テスト失敗時のエラーアノテーション（::error形式）
2. リトライ発生時の警告アノテーション（::warning形式）
3. テスト結果のグループ化された詳細表示（::group::形式）
4. PASS/FAILステータスと実行時間
5. 各テストケースの成功/失敗/スキップ状態

**帳票の出力タイミング**：各テストファイルの完了時に結果が出力され、アノテーションは失敗テストごとに即座に出力される。

**帳票の利用者**：ソフトウェア開発者、DevOpsエンジニア、コードレビュアー

## 帳票種別

CI/CD連携レポート / GitHub Actions アノテーション

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| GHA-01 | GitHub Actions ログ | N/A | ワークフロー実行 |
| GHA-02 | プルリクエスト Files changed | N/A | アノテーション表示 |
| GHA-03 | プルリクエスト Checks | N/A | チェック結果表示 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（コンソール出力） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（標準出力/標準エラー出力） |
| 出力方法 | GitHub Actions ワークフローコマンド形式 |
| 文字コード | UTF-8 |

### GitHub Actions ワークフローコマンド

| コマンド | 用途 | 形式 |
|---------|------|------|
| ::error | エラーアノテーション | `::error file={file},line={line},title={title}::{message}` |
| ::warning | 警告アノテーション | `::warning file={file},line={line},title={title}::{message}` |
| ::group:: | グループ開始 | `::group::{title}` |
| ::endgroup:: | グループ終了 | `::endgroup::` |

## 帳票レイアウト

### レイアウト概要

GitHubActionsReporterの出力は、アノテーションとグループ化された詳細結果で構成される。

```
┌─────────────────────────────────────┐
│   ::error アノテーション             │
│   ::warning アノテーション（リトライ） │
├─────────────────────────────────────┤
│   ::group::PASS ファイルパス (時間)   │
│     テストケース結果（階層構造）      │
│   ::endgroup::                      │
├─────────────────────────────────────┤
│   FAIL ファイルパス (時間)           │
│     テストケース結果（階層構造）      │
├─────────────────────────────────────┤
│   ::group::Errors thrown in ファイル │
│     エラーメッセージ                 │
│   ::endgroup::                      │
└─────────────────────────────────────┘
```

### アノテーション部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | type | アノテーションタイプ | status判定 | error/warning |
| 2 | file | エラー発生ファイル | スタックトレース解析 | 相対パス |
| 3 | line | エラー発生行番号 | スタックトレース解析 | 数値 |
| 4 | title | テストケース名 | ancestorTitles + title | パス形式 |
| 5 | message | エラーメッセージ | failureMessage | エスケープ済みテキスト |

### テスト結果部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 結果ラベル | PASS/FAIL状態 | passed判定 | 緑(PASS)/赤(FAIL)の反転テキスト |
| 2 | ファイルパス | テストファイルパス | testFilePath | 相対パス |
| 3 | 実行時間 | テスト実行時間 | performanceInfo.runtime | ミリ秒表示 |
| 4 | 状態アイコン | テスト状態 | status | Unicode文字 |
| 5 | テスト名 | テストケース名 | title | テキスト |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| GitHub Actions環境 | GITHUB_ACTIONS環境変数が設定されている | 推奨 |
| テスト失敗 | failureMessagesが存在 | アノテーション出力条件 |
| リトライ発生 | retryReasonsが存在 | 警告出力条件 |

### オプション設定

| オプション | 説明 | デフォルト |
|-----------|------|----------|
| silent | 詳細結果の出力を抑制 | true |

### 改ページ条件

N/A（コンソール出力のためスクロール表示）

## データベース参照仕様

### 参照テーブル一覧

N/A（テスト実行結果を使用）

### データ構造参照

#### AssertionResult

| 参照項目 | 帳票項目との対応 | 用途 |
|---------|----------------|------|
| ancestorTitles | テストケースパス | タイトル生成 |
| title | テストケース名 | タイトル生成 |
| status | 状態判定 | アイコン選択 |
| failureMessages | エラーメッセージ | アノテーション内容 |
| retryReasons | リトライ情報 | 警告アノテーション |
| duration | 実行時間 | 時間表示 |

#### PerformanceInfo

| 参照項目 | 帳票項目との対応 | 用途 |
|---------|----------------|------|
| runtime | 実行時間 | ファイル実行時間表示 |
| slow | 遅延判定 | 時間の色分け |
| start | 開始時刻 | 計算用 |
| end | 終了時刻 | 計算用 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| isLastTestSuite | passedTestSuites + failedTestSuites === totalTestSuites | なし | 最終テストスイート判定 |

### メッセージエスケープ処理

| 文字 | エスケープ後 |
|-----|-------------|
| % | %25 |
| \r | %0D |
| \n | %0A |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[onTestResult] --> B[generateAnnotations]
    B --> C{failureMessages/retryReasons?}
    C -->|Yes| D[#createAnnotation]
    C -->|No| E[スキップ]
    D --> F{silent === false?}
    E --> F
    F -->|Yes| G[printFullResult]
    F -->|No| H[スキップ]
    G --> I[getResultTree]
    I --> J[printResultTree]
    J --> K[recursivePrintResultTree]
    H --> L{isLastTestSuite?}
    K --> L
    L -->|Yes| M[printFailedTestLogs]
    L -->|No| N[終了]
    M --> N
```

### アノテーション生成フロー

```mermaid
flowchart TD
    A[generateAnnotations] --> B[testResultsをループ]
    B --> C{retryReasons?}
    C -->|Yes| D[#createAnnotation - warning]
    C -->|No| E[スキップ]
    D --> F{failureMessages?}
    E --> F
    F -->|Yes| G[#createAnnotation - error]
    F -->|No| H[次のテスト]
    G --> H
    H --> B
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| テスト失敗 | failureMessages存在 | ::error形式でアノテーション | ファイル名・行番号付きで出力 |
| リトライ | retryReasons存在 | ::warning形式でアノテーション | "RETRY N:"タイトル付き |
| 計算異常 | passed + failed > total | "Sum({computed}) of passed ({passed}) and failed ({failed}) test suites is greater than the total number of test suites ({total}). Please report the bug at..." | Errorをスロー |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数千テストケースまで対応 |
| 目標出力時間 | リアルタイム |
| 同時出力数上限 | 1（シングルスレッド出力） |

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

- エラーメッセージにはスタックトレースが含まれるため、機密情報の露出に注意
- ファイルパスがアノテーションに含まれるため、リポジトリ構造が公開される
- パブリックリポジトリでのCI実行時は、環境変数等の機密情報がエラーメッセージに含まれていないか確認

## 備考

- silentオプションのデフォルトはtrueで、詳細なテスト結果表示は抑制される
- ::group::でグループ化されたログは、GitHub Actions UIで折りたたみ可能
- PASSしたテストスイートはグループ化、FAILしたテストスイートはグループ化せずに表示
- スタックトレースからファイル・行番号を抽出するため、ソースマップが正しく設定されている必要がある

---

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

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

### 推奨読解順序

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

まず、GitHubActionsReporterで使用される内部データ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | 内部型定義（29-65行目）を確認 |

**読解のコツ**: AnnotationOptions, PerformanceInfo, ResultTree, ResultTreeNode, ResultTreeLeafの型を理解することで、データの流れが把握しやすくなる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | コンストラクタ（72-84行目） |

**主要処理フロー**:
1. **72-84行目**: コンストラクタ - globalConfigとoptions（silent）の設定
2. **79-83行目**: silentオプションのデフォルト値（true）設定

#### Step 3: テスト結果処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | onTestResult（86-98行目） |

**主要処理フロー**:
- **86-98行目**: `onTestResult` - メインの処理ロジック
- **91行目**: `generateAnnotations` - アノテーション生成
- **92-94行目**: silent === falseの場合のみ詳細結果を出力
- **95-97行目**: 最後のテストスイートの場合、失敗ログを出力

#### Step 4: アノテーション生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | generateAnnotations, #createAnnotation（100-158行目） |

**主要処理フロー**:
- **100-126行目**: `generateAnnotations` - テスト結果からアノテーションを生成
- **104-107行目**: titleSeparator（ › ）でテスト名を連結
- **109-116行目**: retryReasonsがある場合、warningアノテーションを生成
- **118-124行目**: failureMessagesをerrorアノテーションとして出力
- **128-144行目**: `#getMessageDetails` - エラーメッセージとスタックトレースの解析
- **146-158行目**: `#createAnnotation` - GitHub Actions形式のアノテーション出力

#### Step 5: メッセージエスケープ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | #createAnnotation内のエスケープ処理（147-153行目） |

**主要処理フロー**:
- **147-153行目**: GitHub Actionsの仕様に従ったエスケープ処理
- **149行目**: `%` → `%25`
- **150行目**: `\r` → `%0D`
- **151行目**: `\n` → `%0A`
- **147行目**: `stripAnsi` - ANSIエスケープシーケンスの除去

#### Step 6: 結果ツリー構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | getResultTree, getResultChildren（212-315行目） |

**主要処理フロー**:
- **212-257行目**: `getResultTree` - テスト結果からツリー構造を構築
- **217-222行目**: ルートノードの初期化
- **224-247行目**: ancestorTitlesがないテストをルートに追加、あるテストはブランチを作成
- **259-315行目**: `getResultChildren` - 再帰的に子ノードを構築

#### Step 7: 結果表示を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 7-1 | GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | printResultTree, recursivePrintResultTree（317-410行目） |

**主要処理フロー**:
- **317-349行目**: `printResultTree` - ルートレベルの結果表示
- **330-340行目**: PASSの場合は::group::でグループ化
- **341-348行目**: FAILの場合はグループ化せずに表示
- **351-410行目**: `recursivePrintResultTree` - 再帰的な結果表示

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

```
GitHubActionsReporter
    │
    ├─ BaseReporter (継承)
    │
    ├─ onTestResult
    │      │
    │      ├─ generateAnnotations
    │      │      ├─ #getMessageDetails
    │      │      │      ├─ separateMessageFromStack
    │      │      │      ├─ getStackTraceLines
    │      │      │      ├─ getTopFrame
    │      │      │      └─ formatPath
    │      │      │
    │      │      └─ #createAnnotation
    │      │             └─ stripAnsi
    │      │
    │      ├─ printFullResult (silent === false時)
    │      │      ├─ getResultTree
    │      │      │      └─ getResultChildren (再帰)
    │      │      │
    │      │      └─ printResultTree
    │      │             └─ recursivePrintResultTree (再帰)
    │      │
    │      └─ printFailedTestLogs (isLastTestSuite時)
    │
    ├─ isLastTestSuite
    │
    ├─ startGroup
    │
    └─ endGroup
```

### データフロー図

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

TestResult ──────────────▶ onTestResult
       │                       │
       │                       ├─▶ generateAnnotations
       │                       │         │
       ▼                       │         ├─▶ #getMessageDetails ──▶ file, line, message
AssertionResult.               │         │
failureMessages                │         └─▶ #createAnnotation ───▶ ::error/::warning
       │                       │
       │                       ├─▶ printFullResult
       │                       │         │
       ▼                       │         ├─▶ getResultTree ────────▶ ResultTree
TestResult.                    │         │
testResults                    │         └─▶ printResultTree ─────▶ ::group:: + 結果
       │                       │
       │                       └─▶ printFailedTestLogs ──────────▶ ::group:: + エラー詳細
       │
       └────────────────────▶ isLastTestSuite ────────────────────▶ 最終スイート判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| GitHubActionsReporter.ts | `packages/jest-reporters/src/GitHubActionsReporter.ts` | ソース | GitHub Actionsレポーター実装 |
| BaseReporter.ts | `packages/jest-reporters/src/BaseReporter.ts` | ソース | 基底クラス |
| types.ts | `packages/jest-reporters/src/types.ts` | ソース | 型定義 |
| index.ts | `packages/jest-reporters/src/index.ts` | ソース | エクスポート定義 |
| jest-message-util | `packages/jest-message-util` | ソース | スタックトレース解析ユーティリティ |
