mcpField
D
deployment-checker

deployment-checker

github.com/fellowship-devクラウド・DevOps3123 回インストール2 週間前に更新
リポジトリ

deployment-checker について

deployment-checker は、Bash スクリプトでヘルスエンドポイントをポーリングし、デプロイ SHA の一致またはタイムアウトを確認するデプロイパイプライン用スキルです。マージ済み PR のデプロイを検証し、結果ラベルを付けます。

主な機能

  1. 01Bash によるヘルスエンドポイントのポーリング
  2. 02デプロイ SHA の任意チェック
  3. 03タイムアウトの設定
  4. 04PR へのラベルとコメントの追加

活用シーン

  1. 01PR マージ後のデプロイ確認
  2. 02タイムアウト時の失敗ラベル付け
  3. 03post-merge からのデプロイ検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/fellowship-dev/dogfooded-skills --skill deployment-checker

インストール後、Claude Code で/deployment-checkerを入力して読み込まれたか確認します。

詳細

deployment-checker

自律型デプロイパイプラインのステージ 2 です。安価な bash スクリプトでチームのヘルスエンドポイントをポーリングし、デプロイされた SHA がマージ済み PR の SHA と一致するまで、またはタイムアウトするまで待機します。構造化された結果を返して終了し、deployed または deploy-failed ラベルを適用します。

設計目標: ポーリング中のトークン消費をゼロにします。Claude エージェントは、ポーリングの設定と結果の処理時にのみ実行されます。ポーリングはすべて bash スクリプトで行います。

使用するタイミング

  • PR のマージ後に /post-merge からディスパッチされます
  • 手動:/deployment-checker PR_NUMBER org/repo

呼び出し

/deployment-checker 42 fellowship-dev/pylot

引数

PR_NUMBER=$1    # PR number
REPO=$2         # org/repo

ランブック

ステップ 0:重複排除ゲート
PR=$1
REPO=$2

ALREADY_DONE=$(gh pr view $PR --repo $REPO --json labels \
  --jq '[.labels[].name] | (contains(["deployed"]) or contains(["deploy-failed"]))')
if [ "$ALREADY_DONE" = "true" ]; then
  echo "[deployment-checker] outcome=\"already complete — deployed or deploy-failed label present\" status=success"
  exit 0
fi
ステップ 1:ジョブからコンテキストを読み取る

ジョブのコンテキスト(/post-merge によって設定)からパラメーターを抽出します。

# These are passed via job context or derived from PR
PR_URL=$(gh pr view $PR --repo $REPO --json url --jq '.url')
PR_TITLE=$(gh pr view $PR --repo $REPO --json title --jq '.title')

# From job context (set by post-merge):
#   EXPECTED_SHA   — merge commit sha to wait for
#   HEALTH_URL     — endpoint to poll
#   TIMEOUT_MINUTES — max wait (default: 5)
#   CHECKER_SCRIPT  — path to team bash polling script
#   POLL_INTERVAL   — seconds between polls (default: 30)

EXPECTED_SHA="${EXPECTED_SHA:-}"
HEALTH_URL="${HEALTH_URL:-}"
TIMEOUT_MINUTES="${TIMEOUT_MINUTES:-5}"
CHECKER_SCRIPT="${CHECKER_SCRIPT:-}"
POLL_INTERVAL="${POLL_INTERVAL:-30}"

if [ -z "$HEALTH_URL" ] || [ -z "$CHECKER_SCRIPT" ]; then
  echo "[deployment-checker] ERROR: HEALTH_URL and CHECKER_SCRIPT must be set in job context" >&2
  exit 1
fi
ステップ 2:bash ポーリングスクリプトを実行する

チーム固有の bash スクリプトが実際のポーリングを処理します。これにより、待機中に Claude が処理に加わることはありません。

PYLOT_DIR="${PYLOT_DIR:-$HOME/projects/fellowship-dev/pylot}"

# Resolve checker script path
if [[ "$CHECKER_SCRIPT" != /* ]]; then
  CHECKER_SCRIPT="$PYLOT_DIR/$CHECKER_SCRIPT"
fi

if [ ! -f "$CHECKER_SCRIPT" ]; then
  echo "[deployment-checker] ERROR: checker script not found: $CHECKER_SCRIPT" >&2
  DEPLOY_STATUS="failed"
  FAILURE_REASON="checker script not found: $CHECKER_SCRIPT"
else
  chmod +x "$CHECKER_SCRIPT"
  # Run the script; it exits 0 on success, non-zero on failure/timeout
  # stdout: "deploy_status=success sha=abc123" or "deploy_status=failed reason=OOM"
  POLL_OUTPUT=$(HEALTH_URL="$HEALTH_URL" \
    EXPECTED_SHA="$EXPECTED_SHA" \
    TIMEOUT_MINUTES="$TIMEOUT_MINUTES" \
    POLL_INTERVAL="$POLL_INTERVAL" \
    bash "$CHECKER_SCRIPT" 2>&1) && POLL_EXIT=0 || POLL_EXIT=$?

  echo "Checker output: $POLL_OUTPUT"

  # Parse structured output (python3 avoids grep -P which is unavailable on macOS/BSD)
  DEPLOY_STATUS=$(echo "$POLL_OUTPUT" | python3 -c "import sys,re; m=re.search(r'deploy_status=(\S+)', sys.stdin.read()); print(m.group(1) if m else 'failed')" 2>/dev/null || echo "failed")
  DEPLOYED_SHA=$(echo "$POLL_OUTPUT" | python3 -c "import sys,re; m=re.search(r'sha=(\S+)', sys.stdin.read()); print(m.group(1) if m else '')" 2>/dev/null || echo "")
  FAILURE_REASON=$(echo "$POLL_OUTPUT" | python3 -c "import sys,re; m=re.search(r'reason=(.+)', sys.stdin.read()); print(m.group(1).strip() if m else 'unknown')" 2>/dev/null || echo "unknown")
fi
ステップ 3:ラベルを適用してコメントする

成功時:

if [ "$DEPLOY_STATUS" = "success" ]; then
  # Create label if missing
  gh label create "deployed" --repo $REPO --color "0e8a16" \
    --description "Deploy verified — health check passed" 2>/dev/null || true

  gh pr edit $PR --repo $REPO --add-label "deployed"

  gh pr comment $PR --repo $REPO --body "$(cat <<EOF
**Deployment verified** ✅

| Field | Value |
|-------|-------|
| Status | \`success\` |
| Deployed SHA | \`${DEPLOYED_SHA:-confirmed}\` |
| Health URL | \`$HEALTH_URL\` |
| Waited | up to ${TIMEOUT_MINUTES} min |

The \`deployed\` label triggers post-deploy file-match actions.
EOF
)"
fi

失敗またはタイムアウト時:

if [ "$DEPLOY_STATUS" != "success" ]; then
  # Create label if missing
  gh label create "deploy-failed" --repo $REPO --color "d93f0b" \
    --description "Deploy verification failed or timed out" 2>/dev/null || true

  gh pr edit $PR --repo $REPO --add-label "deploy-failed"

  gh pr comment $PR --repo $REPO --body "$(cat <<EOF
**Deployment check failed** ❌

| Field | Value |
|-------|-------|
| Status | \`failed\` |
| Reason | ${FAILURE_REASON} |
| Health URL | \`$HEALTH_URL\` |
| Timeout | ${TIMEOUT_MINUTES} min |
| Expected SHA | \`${EXPECTED_SHA:-unknown}\` |

**Action required:** Check the deployment manually. Remove \`deploy-failed\` and re-add \`deployed\` once confirmed.
EOF
)"
fi
ステップ 4:レポートを作成する
PYLOT_DIR="${PYLOT_DIR:-$HOME/projects/fellowship-dev/pylot}"
REPORT="$PYLOT_DIR/reports/$(date +%Y-%m-%d)-deployment-checker-$(echo $REPO | tr '/' '-')-pr${PR}.md"

cat > "$REPORT" <<EOF
# Deployment Checker: $REPO PR #$PR

**Date**: $(date +%Y-%m-%d)
**PR**: [$REPO#$PR]($PR_URL) — $PR_TITLE
**Status**: $DEPLOY_STATUS
**SHA**: ${DEPLOYED_SHA:-not confirmed}
**Reason**: ${FAILURE_REASON:-n/a}

## Poll Output
\`\`\`
$POLL_OUTPUT
\`\`\`
EOF

チームチェッカースクリプトのインターフェース

各チームは、チームの CLAUDE.md で設定したパスに bash スクリプトを用意します。スクリプトには以下が必要です。

入力(環境変数):

変数必須説明
HEALTH_URLはいヘルスチェックで GET する URL
EXPECTED_SHAいいえ待機対象の Git SHA(ヘルスレスポンスと比較)
TIMEOUT_MINUTESいいえ最大待機時間(分、デフォルト:5)
POLL_INTERVALいいえポーリング間隔(秒、デフォルト:30)

終了コード:

  • 0 — デプロイを確認しました
  • 1 — タイムアウトまたは失敗

stdout の形式(最終行):

deploy_status=success sha=abc123def456
deploy_status=failed reason=timeout_after_5min
deploy_status=failed reason=health_check_returned_503

最小限のスクリプトの例:

#!/bin/bash
# scripts/deployment-checker-pylot.sh
TIMEOUT=$((${TIMEOUT_MINUTES:-5} * 60))
INTERVAL=${POLL_INTERVAL:-30}
ELAPSED=0

while [ $ELAPSED -lt $TIMEOUT ]; do
  RESPONSE=$(curl -sf "$HEALTH_URL" 2>/dev/null || echo "")
  CURRENT_SHA=$(echo "$RESPONSE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('sha',''))" 2>/dev/null || echo "")

  if [ -n "$EXPECTED_SHA" ] && [ "$CURRENT_SHA" = "$EXPECTED_SHA" ]; then
    echo "deploy_status=success sha=$CURRENT_SHA"
    exit 0
  elif [ -z "$EXPECTED_SHA" ] && [ -n "$RESPONSE" ]; then
    # No sha to compare — just verify health returns 200
    echo "deploy_status=success sha=confirmed"
    exit 0
  fi

  sleep $INTERVAL
  ELAPSED=$((ELAPSED + INTERVAL))
done

echo "deploy_status=failed reason=timeout_after_${TIMEOUT_MINUTES:-5}min"
exit 1

メモ

  • ポーリング中のトークン消費はゼロです。 Claude は bash スクリプトの実行前後にのみ動作します。待機はすべて bash スクリプトが行います。
  • SHA の比較は任意です。 EXPECTED_SHA が空の場合、チェッカーはヘルスエンドポイントが 200 を返すことを確認します。
  • タイムアウトはチームごとに設定できます。 Pylot(自動プル)では 5 分、Lexgo(GitHub Actions + Fly.io)では 30 分です。
  • deployed ラベルは event-rules を通じて /post-deploy に連鎖します。 手動で引き継ぐ必要はありません。
  • モノレポの対象: 必要に応じて、対象ごとに deployment-checker ジョブをディスパッチします。

コメント