# バッチ設計書 6-publish-release

## 概要

本ドキュメントは、Next.jsパッケージをnpmレジストリに公開する `publish-release` バッチの設計書である。Gitタグからバージョンを検出し、各パッケージを適切なdistタグで公開する。

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

`publish-release` は、Next.jsモノレポ内の公開パッケージをnpmレジストリに公開するバッチ処理である。Gitタグからリリースタイプ（canary/rc/beta/stable）を自動検出し、適切なdistタグ（canary/rc/beta/latest/backport）でnpm publishを実行する。

**業務上の目的・背景**：`start-release` でバージョンバンプとGitタグが作成された後、実際にnpmレジストリにパッケージを公開する必要がある。複数のパッケージを並列で公開し、セマフォによる並列数制御でnpmレジストリへの過負荷を防止する。公開後にはGitHub Releaseのdraft解除も行う。

**バッチの実行タイミング**：`start-release` の後に実行。CI/CD環境で自動的にトリガーされる。

**主要な処理内容**：
1. `check-is-release.js` によるGitタグからのバージョン検出
2. リリースタイプ（canary/rc/beta/stable）の判定
3. backportリリースの検出（現在バージョンがnpm latestより古い場合）
4. 各パッケージの並列npm publish（セマフォ制御: 最大2並列）
5. 公開失敗時のリトライ（最大3回、15秒間隔）
6. GitHub Release の draft 解除（canaryリリース時）

**前後の処理との関連**：`start-release` によるバージョンバンプとGitタグ作成が前提。`publish-native` が別途ネイティブバイナリを公開する。

**影響範囲**：npmレジストリ上の全公開パッケージ、GitHub Releases。

## バッチ種別

リリース処理（パッケージ公開）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | リリース実行ごと |
| 実行時刻 | start-releaseの後 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | CI/CD（Gitタグプッシュイベント） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| NPM_TOKEN | npmレジストリ認証トークンが環境変数に設定 |
| Gitタグ | リリースバージョンに対応するGitタグが存在 |
| RELEASE_BOT_GITHUB_TOKEN | GitHub Release draft解除用（canary時） |
| ビルド済み | パッケージがビルド済みであること |

### 実行可否判定

- `check-is-release.js` でGitタグからバージョンを検出できること
- `NPM_TOKEN` が設定されていること
- タグ検出に失敗した場合は "Nothing to publish, exiting..." で正常終了

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| NPM_TOKEN | 環境変数 | Yes | なし | npm認証トークン |
| RELEASE_BOT_GITHUB_TOKEN | 環境変数 | No（canary時はYes） | なし | GitHub APIトークン |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| Gitタグ | Git | リリースバージョン情報 |
| lerna.json | JSON | 現在のバージョン番号 |
| packages/*/package.json | JSON | 各パッケージ情報（private判定） |
| npm registry dist-tags | HTTP API | 最新公開バージョン情報 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| npmレジストリ | npm package | 各パッケージの公開バージョン |
| GitHub Releases | GitHub API | draft解除されたリリース |

### 出力ファイル仕様

本バッチはファイル出力を行わない。npmレジストリとGitHub APIへの出力のみ。

| 項目 | 内容 |
|-----|------|
| ファイル名 | 該当なし |
| 出力先 | npmレジストリ / GitHub Releases |
| 文字コード | 該当なし |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. Gitタグからバージョン検出
   └─ check-is-release.js を実行
2. リリースタイプ判定
   └─ canary / rc / beta / stable を判定
3. distタグ決定
   └─ canary → "canary", rc → "rc", beta → "beta", stable → "latest"
   └─ backport検出時: stable でも "backport" タグを使用
4. NPM_TOKEN 検証
   └─ 未設定時は終了
5. パッケージ一覧取得
   └─ packages/ ディレクトリを読み込み
6. 並列npm publish
   └─ Sema(2) で最大2並列に制御
   └─ private パッケージはスキップ
   └─ --access public --ignore-scripts --tag {distTag}
7. 公開失敗時のリトライ
   └─ 最大3回、15秒間隔
   └─ "already published" エラーは無視
8. GitHub Release draft解除（canary時）
   └─ GitHub API で release を検索（最大6回リトライ）
   └─ PATCH で draft: false に更新
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始: publish-release] --> B[Gitタグからバージョン検出]
    B --> C{タグ検出成功?}
    C -->|失敗| D[何も公開せず終了]
    C -->|成功| E[リリースタイプ・distタグ判定]
    E --> F{NPM_TOKEN存在?}
    F -->|なし| G[終了]
    F -->|あり| H[パッケージ一覧取得]
    H --> I[各パッケージを並列npm publish]
    I --> J{全パッケージ公開成功?}
    J -->|失敗あり| K[エラー出力・exit 1]
    J -->|成功| L{canaryリリース?}
    L -->|Yes| M[GitHub Release draft解除]
    L -->|No| N[バッチ終了]
    M --> N
    K --> O[バッチ終了: 異常]
```

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

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 該当なし | - | - | データベース操作なし |

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NO_TAG | タグエラー | Gitタグが見つからない | start-releaseが正常完了したか確認 |
| NPM_PUBLISH_FAILED | 公開エラー | npm publishが3回リトライ後も失敗 | npmレジストリの状態を確認 |
| ALREADY_PUBLISHED | 重複公開 | 同一バージョンが公開済み | エラーとして無視（正常扱い） |
| UNDRAFT_FAILED | GitHub APIエラー | Release draft解除失敗 | 手動でGitHub Releaseを更新 |
| DIST_TAG_FETCH_FAILED | API通信エラー | npm dist-tags取得失敗 | ネットワーク接続を確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | npm publish: 最大3回、GitHub Release検索: 最大6回 |
| リトライ間隔 | npm publish: 15秒、GitHub Release: 10秒 |
| リトライ対象エラー | npm publish 失敗（already published除く） |

### 障害時対応

npm publish失敗時は、手動で `npm publish --tag {tag}` を実行する。GitHub Release draft解除失敗時は、GitHub UIから手動で更新する。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | パッケージ単位（個別にpublish） |
| コミットタイミング | 各パッケージのpublish成功時 |
| ロールバック条件 | 一部失敗時も他パッケージの公開は取り消さない |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 約10-15パッケージ |
| 目標処理時間 | 数分（並列2、リトライなし時） |
| メモリ使用量上限 | 通常のNode.jsプロセスメモリ |

## 排他制御

セマフォ（Sema(2)）により、同時npm publish数を最大2に制限している。リリースプロセス全体としては排他的に実行する必要がある。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | 公開開始時 | "Publishing as \"{tag}\" dist tag..." |
| 進捗ログ | 各パッケージ | npm publishの標準出力 |
| スキップログ | privateパッケージ | "Skipping private package {name}" |
| 終了ログ | draft解除時 | "un-drafted canary release successfully" |
| エラーログ | エラー発生時 | "Failed to publish {pkg}", リトライ情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 公開失敗パッケージ数 | 1件以上 | process.exit(1) でCI通知 |
| 処理時間 | 15分 | CI/CD通知 |

## 備考

- エントリポイント: `scripts/publish-release.js`
- `check-is-release.js` を内部で呼び出してリリースバージョンを検出
- backportリリースの検出: 現在バージョンが npm `latest` タグより古い場合、distタグを "backport" に変更
- `--ignore-scripts` フラグにより、パッケージの postinstall 等のスクリプトは実行されない
- Promise.allSettled を使用し、一部パッケージの失敗が他パッケージの公開を阻害しない設計
