# 機能設計書 81-is_update_available

## 概要

本ドキュメントは、Oh My Zshの自動更新機能における更新可否判定を行う`is_update_available`関数の機能設計について記述する。

### 本機能の処理概要

ローカルのOh My ZshリポジトリとGitHubリモートリポジトリのHEADコミットを比較し、更新が利用可能かどうかを判定する機能である。

**業務上の目的・背景**：Oh My Zshは継続的に更新されるオープンソースプロジェクトであり、ユーザーが常に最新バージョンを利用できるようにする必要がある。しかし、ネットワーク通信を伴う更新確認を無条件に行うとパフォーマンスに影響するため、実際に更新が存在する場合のみ更新処理を実行するための判定機能が必要となる。この関数により、不要な更新処理を回避し、ユーザー体験を向上させる。

**機能の利用シーン**：zshシェルの起動時に自動更新チェックが有効な場合、定期的（デフォルト13日間隔）に更新確認が行われる。このとき、実際にリモートリポジトリとの差分があるかどうかを判定するために本関数が呼び出される。

**主要な処理内容**：
1. ローカルリポジトリの設定からブランチ名とリモート名を取得
2. リモートURLからGitHubリポジトリ情報を抽出
3. ローカルHEADのコミットSHAを取得
4. GitHub APIを使用してリモートHEADのコミットSHAを取得
5. ローカルとリモートのSHAを比較して更新の有無を判定
6. 必要に応じてmerge-baseを使用して詳細な比較を実施

**関連システム・外部連携**：GitHub API（https://api.github.com）を使用してリモートリポジトリの最新コミット情報を取得する。curl、wget、fetchのいずれかのHTTPクライアントを使用する。

**権限による制御**：特になし。ただし、$ZSHディレクトリへの書き込み権限がない場合は自動更新自体がスキップされる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | check_for_upgrade.sh | 主画面 | ローカルとリモートのHEADを比較して更新があるか判定 |

## 機能種別

判定処理 / 外部API連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | 引数は受け取らない | - |

### 入力データソース

- `$ZSH`環境変数：Oh My Zshのインストールディレクトリ
- `.git/config`：リポジトリのgit設定（oh-my-zsh.branch、oh-my-zsh.remote）
- GitHub API：リモートリポジトリの最新コミット情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | 終了ステータス | 0: 更新あり、1: 更新なし |

### 出力先

シェルの終了ステータスとして返却

## 処理フロー

### 処理シーケンス

```
1. ローカル設定の取得
   └─ git configからブランチ名（デフォルト: master）とリモート名（デフォルト: origin）を取得
2. リモートURLの解析
   └─ HTTPSまたはSSH形式のGitHub URLからリポジトリパスを抽出
3. 公式リポジトリチェック
   └─ ohmyzsh/ohmyzsh以外のリポジトリは更新ありとみなす
4. ローカルHEADの取得
   └─ git rev-parseでローカルブランチのコミットSHAを取得
5. リモートHEADの取得
   └─ GitHub APIを呼び出してリモートブランチの最新コミットSHAを取得
6. SHA比較
   └─ ローカルとリモートのSHAが異なる場合、merge-baseで詳細比較
7. 結果判定
   └─ リモートが先行している場合は更新ありと判定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ブランチ名・リモート名取得]
    B --> C[リモートURLを解析]
    C --> D{GitHubリポジトリか?}
    D -->|No| E[更新ありと判定 return 0]
    D -->|Yes| F{公式リポジトリか?}
    F -->|No| E
    F -->|Yes| G[ローカルHEAD取得]
    G --> H{取得成功?}
    H -->|No| E
    H -->|Yes| I[GitHub APIでリモートHEAD取得]
    I --> J{取得成功?}
    J -->|No| K[更新なしと判定 return 1]
    J -->|Yes| L{ローカル = リモート?}
    L -->|Yes| K
    L -->|No| M[merge-base計算]
    M --> N{base = リモート?}
    N -->|Yes| K
    N -->|No| E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-81-001 | 非GitHub判定 | GitHub以外のリモートは更新ありとみなす | remote.origin.urlがgithub.comを含まない場合 |
| BR-81-002 | 非公式リポジトリ判定 | ohmyzsh/ohmyzsh以外は更新ありとみなす | リポジトリパスがohmyzsh/ohmyzshでない場合 |
| BR-81-003 | 通信失敗時 | リモートHEAD取得失敗時は更新なしとみなす | curl/wget/fetchがエラーを返した場合 |
| BR-81-004 | コマンド不在時 | HTTP取得コマンドがない場合は更新ありとみなす | curl/wget/fetchのいずれも存在しない場合 |

### 計算ロジック

更新判定ロジック：
- `local_head != remote_head` かつ `merge-base(local, remote) != remote_head` の場合、更新あり

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ローカルHEAD取得失敗 | gitリポジトリでない場合 | 更新ありと判定して処理継続 |
| - | リモートHEAD取得失敗 | ネットワーク接続不可/API制限 | 更新なしと判定してスキップ |
| - | merge-base失敗 | リモートコミットが未ダウンロード | 更新ありと判定して処理継続 |

### リトライ仕様

リトライは行わない。GitHub APIへの接続にはタイムアウト（2秒）を設定しており、失敗時は更新なしとみなす。

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

トランザクション管理の対象外（読み取り専用の判定処理）

## パフォーマンス要件

- GitHub API呼び出しタイムアウト: 2秒
- 期待レスポンス時間: 2秒以内

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

- GitHub APIへのアクセスは公開情報の取得のみ
- 認証は不要（パブリックリポジトリへのアクセス）
- コミットSHAは信頼できる情報源からのみ取得

## 備考

- curl、wget、fetchの優先順位でHTTPクライアントを選択
- Accept headerに`application/vnd.github.v3.sha`を指定してSHAのみを取得（軽量なレスポンス）

---

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

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

### 推奨読解順序

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

本関数で使用される主要な変数とその役割を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | check_for_upgrade.sh | `tools/check_for_upgrade.sh` | 42-94行目のis_update_available関数内で定義される変数を確認 |

**読解のコツ**: zshの`${...:-default}`構文は、変数が未定義または空の場合にデフォルト値を使用する。`${var#pattern}`はパターンマッチ削除。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | check_for_upgrade.sh | `tools/check_for_upgrade.sh` | 42行目: 関数定義の開始点 |

**主要処理フロー**:
1. **44行目**: ブランチ名の取得（デフォルト: master）
2. **47-48行目**: リモート名とURLの取得
3. **51-58行目**: GitHubリポジトリパスの抽出（HTTPS/SSH形式に対応）
4. **61行目**: 公式リポジトリのチェック
5. **65-66行目**: ローカルHEADコミットSHAの取得
6. **71-81行目**: HTTP取得コマンドの選択とGitHub API呼び出し
7. **84行目**: ローカルとリモートのSHA比較
8. **88-93行目**: merge-baseによる詳細比較

#### Step 3: 外部API連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | check_for_upgrade.sh | `tools/check_for_upgrade.sh` | 71-81行目: GitHub APIの呼び出しロジック |

**主要処理フロー**:
- **72-73行目**: curlを使用したAPI呼び出し（タイムアウト2秒）
- **74-75行目**: curlがない場合はwgetを使用
- **76-77行目**: wgetもない場合はfetchを使用
- **78-80行目**: いずれのコマンドもない場合は更新ありと判定

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

```
check_for_upgrade.sh
    │
    ├─ handle_update()
    │      ├─ is_update_available()  ← 本機能
    │      │      ├─ git config --local oh-my-zsh.branch
    │      │      ├─ git config --local oh-my-zsh.remote
    │      │      ├─ git rev-parse $branch
    │      │      ├─ curl/wget/fetch (GitHub API)
    │      │      └─ git merge-base
    │      │
    │      └─ update_ohmyzsh()
    │
    └─ current_epoch()
```

### データフロー図

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

$ZSH ─────────────┐
                  │
git config ───────┼─▶ is_update_available() ───────▶ 終了ステータス
                  │         │                         (0: 更新あり
GitHub API ───────┘         │                          1: 更新なし)
                            │
                            ├─▶ branch (e.g., "master")
                            ├─▶ remote (e.g., "origin")
                            ├─▶ local_head (SHA)
                            └─▶ remote_head (SHA)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| check_for_upgrade.sh | `tools/check_for_upgrade.sh` | ソース | 更新チェック・更新処理の統合スクリプト |
| upgrade.sh | `tools/upgrade.sh` | ソース | 実際の更新処理を実行 |
| .zsh-update | `$ZSH_CACHE_DIR/.zsh-update` | キャッシュ | 最終更新チェック日時を保存 |
