关于 deployment-checker
deployment-checker 是部署流水线中的部署检查 Skill,通过 Bash 轮询健康端点,直到部署 SHA 匹配或超时。它为合并后的 PR 验证部署状态,并添加结果标签。
主要功能
- 01Bash 脚本轮询健康端点
- 02可选验证部署 SHA
- 03支持可配置超时
- 04为 PR 添加结果标签和评论
适用场景
- 01合并 PR 后确认对应版本已部署
- 02超时后标记部署检查失败
- 03由 post-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 标签。
设计目标: 轮询期间不消耗任何 token。Claude Agent 仅负责启动轮询和处理结果。所有轮询均由 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
备注
- 轮询期间不消耗任何 token。 Claude 只会在 bash 脚本运行前后执行。所有等待均由 bash 脚本完成。
- SHA 比较为可选。 如果
EXPECTED_SHA为空,检查器会确认健康检查端点是否返回 200。 - 超时时间可由团队配置。 Pylot(自动拉取)为 5 分钟,Lexgo(GitHub Actions + Fly.io)为 30 分钟。
deployed标签会通过 event-rules 衔接到/post-deploy,无需手动交接。- Monorepo 目标: 如有需要,可针对每个目标派发一个 deployment-checker 作业。
评论
支持 Markdown