mcpField
D
deployment-checker

deployment-checker

github.com/fellowship-dev云与 DevOps3123 次安装2 周前更新
代码仓库

关于 deployment-checker

deployment-checker 是部署流水线中的部署检查 Skill,通过 Bash 轮询健康端点,直到部署 SHA 匹配或超时。它为合并后的 PR 验证部署状态,并添加结果标签。

主要功能

  1. 01Bash 脚本轮询健康端点
  2. 02可选验证部署 SHA
  3. 03支持可配置超时
  4. 04为 PR 添加结果标签和评论

适用场景

  1. 01合并 PR 后确认对应版本已部署
  2. 02超时后标记部署检查失败
  3. 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