mcpField
V
vercel-deploy

vercel-deploy

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

vercel-deploy について

既存のVercelプロジェクトをローカルディレクトリから本番環境へデプロイする、段階的なスキルです。明示的なプロジェクト情報を要求して各段階を検証し、失敗時は停止します。プロジェクトの新規作成や暗黙の状態には依存しません。

主な機能

  1. 01ディレクトリとプロジェクト情報の明示
  2. 02Vercel APIによるプロジェクト連携の確認
  3. 03CLIによる非対話型デプロイ
  4. 04デプロイがREADYまたはERRORになるまで確認
  5. 05本番ドメインの応答検証

活用シーン

  1. 01ローカルのチェックアウトから既存プロジェクトをデプロイ
  2. 02設定済みドメインへの本番デプロイを検証

インストール

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

$npx skills add https://github.com/fellowship-dev/dogfooded-skills --skill vercel-deploy

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

詳細

目的

ローカルディレクトリから既存の Vercel プロジェクトを本番環境にデプロイします。ハングせず、新しいプロジェクトを作成せず、暗黙の状態を前提としないように設計されています。

必須シークレット

環境変数(crew のシークレットストアから)として利用できる必要があります。

  • VERCEL_TOKEN — デプロイ権限を持つアクセストークン(実際のシークレットはこれだけです)

必須入力

すべての入力は、スキルの呼び出し時またはタスクの説明内で KEY=value ペアとして渡されます。引数から解析してください。これらを環境変数から読み取らないでください。

  • DEPLOY_DIR — デプロイ可能なディレクトリのパス(例:./ui、リポジトリのルート)
  • PROD_DOMAIN — 想定される本番ドメイン(例:pylot.fellowship.dev)
  • VERCEL_ORG_ID — 組織/チーム ID(team_ で始まります)
  • VERCEL_PROJECT_ID — プロジェクト ID(prj_ で始まります)

これらの値はシークレットではなく、リポジトリのプレイブック(GET /admin/playbooks/<repo>)に記載されています。オペレーターはプレイブックを読み取り、このスキルを呼び出す際に値を渡します。このスキルの CLI フローを通じてのみデプロイしてください。Vercel の Git 自動デプロイ連携は、上記のプレイブック由来の入力と「禁止事項」に記載されたチェックを迂回するため、決して利用しないでください。

任意入力

  • DEPLOY_BRANCH — デプロイ元の Git ブランチ。指定がない場合はデフォルトで main です。デプロイ前に必ずチェックアウトしてプルします。
  • DEPLOY_AUTHOR — 検証済み Vercel チームメンバーの Git 名(例:maxfindel)。DEPLOY_EMAIL とともに指定された場合、ステージ 00 でデプロイ前にコミットの作成者を修正します。Vercel がコミット作成者のチームメンバーシップを強制する場合にのみ必要です。
  • DEPLOY_EMAIL — 作成者に一致する Git メールアドレス。DEPLOY_AUTHOR を設定する場合は必須です。

禁止事項

  1. Vercel プロジェクトを新規作成しないでください。 存在しない場合は停止し、失敗を報告してください。
  2. プロジェクトが自動的にリンクされると想定しないでください。 常に .vercel/project.json を明示的に確認または書き込んでください。
  3. Git リポジトリを Vercel プロジェクトに接続しないでください。 すべてのデプロイは CLI によるプッシュであり、Git をトリガーとするものではありません。
  4. --token と --yes を指定せずに vercel を実行しないでください。 指定しないと CLI が永久にハングします。
  5. vercel link を実行しないでください。 対話的な入力を求められます。.vercel/project.json を直接書き込んでください。
  6. vercel project create または同等のコマンドを実行しないでください。 そのための手順は別にあります。

ステージの概要

ステージ名前目的
00author-fixコミット作成者を修正します(DEPLOY_AUTHOR が設定されている場合。任意で、それ以外はスキップ)
01preflightシークレットとツールを確認し、デプロイのコンテキストを算出します
02link.vercel/project.json が存在することを確認し、API 経由でプロジェクトを検証します
03deploy対話なしで vercel deploy --prod を実行します
04pollデプロイが READY または ERROR になるまで Vercel API をポーリングします
05verify本番ドメインに到達できることを確認し、結果を出力します

ステージ 00 — 作成者の修正(条件付き)

DEPLOY_AUTHOR が指定されていない場合は、このステージをスキップしてください。 すべての Vercel プロジェクトでコミット作成者のチームメンバーシップが必須というわけではありません。

Vercel がこれを強制する場合(TEAM_ACCESS_REQUIRED/seatBlock)、ボットアカウント(例:fry-lobster)によって CLI デプロイがブロックされます。チームメンバーを作成者とする空のコミットで修正します。

# Only run if DEPLOY_AUTHOR is set in the skill params
if [ -n "$DEPLOY_AUTHOR" ] && [ -n "$DEPLOY_EMAIL" ]; then
  HEAD_AUTHOR=$(git log -1 --format='%an')
  if [ "$HEAD_AUTHOR" != "$DEPLOY_AUTHOR" ]; then
    echo "[vercel-deploy] HEAD author '$HEAD_AUTHOR' is not a Vercel team member."
    echo "[vercel-deploy] Creating empty commit with author '$DEPLOY_AUTHOR' to unblock deploy."
    git commit --allow-empty \
      --author="$DEPLOY_AUTHOR <$DEPLOY_EMAIL>" \
      -m "chore: vercel deploy author fix (empty commit)"
    git push origin HEAD
  fi
else
  echo "[vercel-deploy] Stage 00 skipped — no DEPLOY_AUTHOR configured"
fi

ステージ 01 — 事前確認

すべてのシークレットと入力が存在し、ツールがインストールされていることを確認してから、デプロイブランチをチェックアウトします。

# Verify required secret (from crew secret store — the only real secret)
[ -z "$VERCEL_TOKEN" ] && { echo "[vercel-deploy] MISSING secret: VERCEL_TOKEN"; exit 1; }

# Verify required inputs (parsed from skill args / task description — from the repo playbook)
[ -z "$DEPLOY_DIR" ]        && { echo "[vercel-deploy] MISSING input: DEPLOY_DIR — check the repo playbook"; exit 1; }
[ -z "$PROD_DOMAIN" ]       && { echo "[vercel-deploy] MISSING input: PROD_DOMAIN — check the repo playbook"; exit 1; }
[ -z "$VERCEL_ORG_ID" ]     && { echo "[vercel-deploy] MISSING input: VERCEL_ORG_ID — check the repo playbook"; exit 1; }
[ -z "$VERCEL_PROJECT_ID" ] && { echo "[vercel-deploy] MISSING input: VERCEL_PROJECT_ID — check the repo playbook"; exit 1; }

# Optional: warn if author-fix params are incomplete (both or neither)
if [ -n "$DEPLOY_AUTHOR" ] && [ -z "$DEPLOY_EMAIL" ]; then
  echo "[vercel-deploy] WARNING: DEPLOY_AUTHOR set but DEPLOY_EMAIL missing — Stage 00 will be skipped"
fi

# Verify vercel CLI is available
command -v vercel >/dev/null 2>&1 || command -v npx >/dev/null 2>&1 || {
  echo "[vercel-deploy] vercel CLI not available — install with: npm i -g vercel"
  exit 1
}

# Verify deploy directory exists
[ -d "$DEPLOY_DIR" ] || { echo "[vercel-deploy] DEPLOY_DIR not found: $DEPLOY_DIR"; exit 1; }

# Checkout and pull deploy branch
DEPLOY_BRANCH="${DEPLOY_BRANCH:-main}"
git checkout "$DEPLOY_BRANCH" && git pull origin "$DEPLOY_BRANCH" || {
  echo "[vercel-deploy] Failed to checkout/pull $DEPLOY_BRANCH"
  exit 1
}

# Save state for downstream stages
cat > /tmp/vercel-deploy-ctx.env <<EOF
DEPLOY_BRANCH=$DEPLOY_BRANCH
DEPLOY_DIR=$DEPLOY_DIR
PROD_DOMAIN=$PROD_DOMAIN
EOF

echo "[vercel-deploy] Stage 01 complete — preflight passed, branch: $DEPLOY_BRANCH"

ステージ 02 — リンク

.vercel/project.json を直接書き込み(vercel link は使用しないでください)、API 経由でプロジェクトが存在することを確認します。

source /tmp/vercel-deploy-ctx.env

# Write project link file directly
mkdir -p "$DEPLOY_DIR/.vercel"
cat > "$DEPLOY_DIR/.vercel/project.json" <<EOF
{
  "orgId": "$VERCEL_ORG_ID",
  "projectId": "$VERCEL_PROJECT_ID"
}
EOF

# Verify project exists via Vercel API
PROJECT_JSON=$(curl -sf \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  "https://api.vercel.com/v9/projects/$VERCEL_PROJECT_ID?teamId=$VERCEL_ORG_ID")

[ -z "$PROJECT_JSON" ] && {
  echo "[vercel-deploy] Stage 02 failed: project $VERCEL_PROJECT_ID not found — STOP, do not create"
  exit 1
}

PROJECT_NAME=$(echo "$PROJECT_JSON" | python3 -c \
  "import sys,json; d=json.load(sys.stdin); print(d.get('name','unknown'))" 2>/dev/null || echo "unknown")

echo "PROJECT_NAME=$PROJECT_NAME" >> /tmp/vercel-deploy-ctx.env
echo "[vercel-deploy] Stage 02 complete — linked to project '$PROJECT_NAME' ($VERCEL_PROJECT_ID)"

ステージ 03 — デプロイ

対話なしで vercel deploy --prod を実行します。--token と --yes は必ず指定してください。指定しないと CLI がハングします。

source /tmp/vercel-deploy-ctx.env

cd "$DEPLOY_DIR"
DEPLOY_OUTPUT=$(npx vercel deploy --prod --token="$VERCEL_TOKEN" --yes 2>&1)
DEPLOY_EXIT=$?

echo "$DEPLOY_OUTPUT"

if [ $DEPLOY_EXIT -ne 0 ]; then
  echo "[vercel-deploy] Stage 03 failed: vercel deploy exited $DEPLOY_EXIT"
  exit 1
fi

# Extract deployment URL (last https:// line in output)
DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -E '^https://' | tail -1)
[ -z "$DEPLOY_URL" ] && {
  echo "[vercel-deploy] Stage 03 failed: no deployment URL found in vercel output"
  exit 1
}

echo "DEPLOY_URL=$DEPLOY_URL" >> /tmp/vercel-deploy-ctx.env
echo "[vercel-deploy] Stage 03 complete — deployment URL: $DEPLOY_URL"

ステージ 04 — ポーリング

デプロイが READY または ERROR になるまで Vercel API をポーリングします。120 秒後にタイムアウトします。

source /tmp/vercel-deploy-ctx.env

MAX_WAIT=120
ELAPSED=0
DEPLOY_HOST=$(echo "$DEPLOY_URL" | sed 's|https://||')

while [ $ELAPSED -lt $MAX_WAIT ]; do
  DEPLOY_STATE=$(curl -sf \
    -H "Authorization: Bearer $VERCEL_TOKEN" \
    "https://api.vercel.com/v13/deployments?url=${DEPLOY_HOST}&teamId=$VERCEL_ORG_ID&limit=1" \
    | python3 -c \
      "import sys,json; d=json.load(sys.stdin); deps=d.get('deployments',[]); print(deps[0].get('state','UNKNOWN') if deps else 'NOT_FOUND')" \
      2>/dev/null || echo "API_ERROR")

  echo "[vercel-deploy] Deploy state: $DEPLOY_STATE (${ELAPSED}s elapsed)"

  case "$DEPLOY_STATE" in
    READY)
      echo "[vercel-deploy] Stage 04 complete — deployment READY"
      break
      ;;
    ERROR|CANCELED)
      echo "[vercel-deploy] Stage 04 failed: deployment reached terminal state $DEPLOY_STATE"
      exit 1
      ;;
    *)
      sleep 10
      ELAPSED=$((ELAPSED + 10))
      ;;
  esac
done

[ $ELAPSED -ge $MAX_WAIT ] && {
  echo "[vercel-deploy] Stage 04 failed: timed out after ${MAX_WAIT}s — last state: $DEPLOY_STATE"
  exit 1
}

ステージ 05 — 検証

本番ドメインにアクセスできること(HTTP 200、301、または 302)を確認してから、結果を出力します。

source /tmp/vercel-deploy-ctx.env

VERIFY_URL="https://$PROD_DOMAIN"
HTTP_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" --max-time 15 "$VERIFY_URL" 2>/dev/null || echo "000")

echo "[vercel-deploy] $VERIFY_URL → HTTP $HTTP_STATUS"

case "$HTTP_STATUS" in
  200|301|302)
    echo "[vercel-deploy] Stage 05 complete — production domain verified"
    ;;
  *)
    echo "[vercel-deploy] Stage 05 failed: $VERIFY_URL returned HTTP $HTTP_STATUS"
    exit 1
    ;;
esac

検証コマンドの実行後、対応する解決済みマーカーを最後のアシスタント行として出力してください(Bash から出力せず、コードフェンスにも入れないでください)。

  • 検証成功:[pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy succeeded" project=$PROJECT_NAME domain=$PROD_DOMAIN deploy_url=$DEPLOY_URL status=success
  • 失敗:[pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy failed at stage 05: $PROD_DOMAIN returned HTTP $HTTP_STATUS" status=failed

実行モデル

  • ステージは順番どおりに実行してください。次に進む前に、各ステージのチェックポイントを通過する必要があります。
  • ステージをスキップしないでください。 すべてのチェックポイントを検証します。
  • 速やかに失敗を報告してください。 チェックポイントが失敗した場合は停止し、status=failed を報告してください。
  • ステージ間では、/tmp/vercel-deploy-ctx.env を介して状態を渡します。

重要なルール

  1. 順次実行のみです。ステージ N のチェックポイントを通過してから、ステージ N+1 を開始してください。
  2. スキップは禁止です。すべてのステージを実行し、すべてのチェックポイントを検証してください。
  3. 速やかに失敗を報告してください。チェックポイントが失敗した場合は停止し、報告してください。
  4. vercel または npx vercel の呼び出しには、必ず --token="$VERCEL_TOKEN" --yes を含めてください。

エラー処理

いずれかのステージが失敗した場合:

  1. 失敗したステージと正確なエラーを出力してください
  2. 利用可能な場合は、Vercel API のレスポンス本文を含めてください
  3. [pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy failed at stage <NN>: <reason>" status=failed を出力してください
  4. 自動的に再試行しないでください

結果

成功した場合、次を出力してください:

[pylot:$PYLOT_OUTCOME_NONCE] outcome="vercel-deploy succeeded" project=$PROJECT_NAME domain=$PROD_DOMAIN deploy_url=$DEPLOY_URL status=success

コメント