# CI Workflow

> PR作成後のCI監視、失敗時の分類と対応、自動マージ、環境クリーンアップまでの完全なワークフローを定義

- Skill: `majiayu000/ci-workflow` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/ci-workflow`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/ci-workflow/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/ci-workflow

---


# CI監視ワークフロー

> **責任範囲**: CI監視 → 失敗分析 → 自動修正 → 成功時マージ
> 
> | このスキル | pr-merge-workflow |
> |-----------|-------------------|
> | CIポーリング・ログ分析 | PR作成テンプレート |
> | 失敗時の自動修正 | マージ戦略選択 |
> | リトライ管理（3回） | ロールバック手順 |
> | 成功時の自動マージ呼び出し | クリーンアップ |

---

## 実行者の責任分担

| フェーズ | 実行者 | 理由 |
|---------|--------|------|
| 0-9 (実装→PR作成) | `container-worker` / `Sisyphus` | container-use環境内での作業 |
| **10 (CI監視→マージ)** | **`Sisyphus`** | GitHub API操作、環境外での監視 |
| **11 (環境クリーンアップ)** | **`Sisyphus`** | 環境管理はホスト側で実行 |

> **Note**: CI監視やPRマージは `bash` ツールでGitHub APIを呼び出す。

---

## メインフロー

```python
def post_pr_workflow(pr_number: int, env_id: str):
    """PR作成後: CI待機 → 成功:マージ&削除 / 失敗:修正(3回) / タイムアウト:報告"""
    ci_result = wait_for_ci(pr_number)
    
    if ci_result == SUCCESS:
        auto_merge_pr(pr_number, env_id) and cleanup_environment(env_id)
    elif ci_result == FAILURE:
        if handle_ci_failure(pr_number, env_id):
            # 修正成功 → マージ & 環境削除
            auto_merge_pr(pr_number, env_id) and cleanup_environment(env_id)
        else:
            # 3回失敗 → エスカレーション（環境保持）
            escalate_ci_failure(pr_number, env_id)
    elif ci_result == TIMEOUT:
        handle_ci_timeout(pr_number, env_id)  # 環境保持
```

---

## 1. CI完了待機

```python
def wait_for_ci(pr_number: int, timeout: int = 600) -> CIResult:
    """30秒間隔でgh pr checksをポーリング（最大10分）"""
    for _ in range(timeout // 30):
        checks = bash(f"gh pr checks {pr_number} --json state,name")
        if all_success(checks): return SUCCESS
        if any_failure(checks): return FAILURE
        wait(30)
    return TIMEOUT
```

---

## 2. CI失敗の分類と対応

| 失敗カテゴリ | 検出パターン | 対応方法 |
|------------|-------------|---------|
| **Lint/Clippy** | `warning:`, `clippy::` | 自動修正 (`--fix`) |
| **Test失敗** | `FAILED`, `test result: FAILED` | テストコード修正 |
| **ビルドエラー** | `error[E`, `cannot find` | コード修正 |
| **フォーマット** | `Diff in`, `would have been reformatted` | `cargo fmt` |
| **環境依存** | `platform exception` | 環境再開 |

```python
def analyze_failure(log: str) -> CIFailureAnalysis:
    """CIログを分析して失敗種別を特定"""
    if "clippy::" in log or "warning:" in log:
        return CIFailureAnalysis(type="lint", auto_fixable=True, 
            fix_command="cargo clippy --fix --allow-dirty --allow-staged")
    if "FAILED" in log:
        return CIFailureAnalysis(type="test", auto_fixable=False)
    if "error[E" in log:
        return CIFailureAnalysis(type="build", auto_fixable=False)
    if "would have been reformatted" in log:
        return CIFailureAnalysis(type="format", auto_fixable=True, fix_command="cargo fmt")
    return CIFailureAnalysis(type="unknown")
```

---

## 3. CI修正フロー

```python
MAX_CI_RETRIES = 3

def handle_ci_failure(pr_number: int, env_id: str) -> bool:
    """CI失敗 → ログ分析 → container環境で修正 → push → 再待機（最大3回）"""
    for attempt in range(MAX_CI_RETRIES):
        log = bash("gh run view --log-failed")
        fix_in_container(env_id, analyze_failure(log))
        bash("git add . && git commit -m 'fix: CI修正' && git push")
        if wait_for_ci(pr_number) == SUCCESS:
            return True
    return False  # リトライ超過 → escalate_ci_failure()

def fix_in_container(env_id: str, analysis: CIFailureAnalysis):
    """既存のcontainer環境で修正を実施"""
    # 1. 環境を再開
    container-use_environment_open(environment_id=env_id, ...)
    # 2. リモートの最新状態を取得
    container-use_environment_run_cmd(command="git pull origin HEAD")
    # 3. 修正を実施
    if analysis.auto_fixable:
        container-use_environment_run_cmd(command=analysis.fix_command)
    # 4. ローカルで検証
    container-use_environment_run_cmd(command="cargo clippy -- -D warnings && cargo test")
    # 5. 修正をpush
    container-use_environment_run_cmd(command="git add . && git commit -m 'fix: CI修正' && git push")
```

---

## 4. 自動マージ

```python
def auto_merge_pr(pr_number: int, issue_num: int) -> bool:
    """gh pr merge --merge --delete-branch"""
    result = bash(f"gh pr merge {pr_number} --merge --delete-branch")
    if result.exit_code == 0:
        # Issue ラベル更新: env:merged ({{skill:github-issue-state-management}} API)
        bash(f"bash .opencode/skill/github-issue-state-management/scripts/issue-state.sh merged {issue_num}")
        return True
    return handle_merge_failure(pr_number, error=result.stderr)
```

---

## 5. エスカレーション

```python
def escalate_ci_failure(pr_number: int, env_id: str):
    """PRをDraft化、失敗ログをコメント、ユーザーに報告"""
    bash(f"gh pr ready {pr_number} --undo")
    bash(f"gh pr comment {pr_number} --body '⚠️ CI修正3回失敗。env_id: {env_id}'")
    report_to_user(f"⚠️ PR #{pr_number} 手動確認が必要")
```

---

## 6. 環境クリーンアップ

```python
def cleanup_environment(env_id: str, pr_number: int) -> bool:
    """delete-environment スキルを実行（最大2回リトライ）"""
    script = ".opencode/skill/delete-environment/scripts/delete_env.sh"
    
    for _ in range(3):
        if bash(f"bash {script} {env_id}").exit_code == 0:
            report_to_user(f"✅ PR #{pr_number} マージ済み、環境 {env_id} 削除済み")
            return True
        wait(5)
    report_to_user(f"⚠️ 環境削除失敗。手動: bash {script} {env_id}")
    return False
```

> **Note**: 環境状態は GitHub Issue ラベルで管理。詳細は [github-issue-state-management](../github-issue-state-management/SKILL.md) を参照。

### クリーンアップタイミング

| 状況 | 環境の扱い |
|------|----------|
| PRマージ成功 | ✅ 即座に削除 |
| PRクローズ（マージなし） | ✅ 即座に削除 |
| CI修正中（リトライ中） | ❌ 削除しない |
| Draft PR（エスカレーション中） | ❌ 削除しない |
| PRレビュー修正待ち | ❌ 削除しない |

---

## 関連ドキュメント

| ドキュメント | 内容 |
|-------------|------|
| {{skill:pr-merge-workflow}} | PR作成〜マージ〜ロールバックの全体フロー |
| {{skill:github-issue-state-management}} | 環境状態管理（ラベル） |
| {{skill:delete-environment}} | 環境削除手順 |

---

## CLIスクリプト

**CI待機の自動化スクリプト：**

```bash
bash .opencode/skill/ci-workflow/scripts/ci-wait.sh <pr-number> [timeout-seconds]
```

| 引数 | 説明 | デフォルト |
|------|------|-----------|
| `pr-number` | PR番号 | 必須 |
| `timeout-seconds` | 最大待機時間（秒） | 600 |

**終了コード：**
| コード | 意味 |
|--------|------|
| 0 | 全CIチェック成功 |
| 1 | CIチェック失敗 |
| 2 | タイムアウト |
| 3 | 引数エラー |

**使用例：**
```bash
bash .opencode/skill/ci-workflow/scripts/ci-wait.sh 42 1800
```

