Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

338 lines
14 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ═══════════════════════════════════════════════
# 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
# 📜 Copyright: 国作登字-2026-A-00037559
# ═══════════════════════════════════════════════
# .github/workflows/merge-watchdog.yml
# 👁️ Merge Watchdog · 合并指令看守者
#
# 事件驱动:当 auto-repair PR 被合并到 main 时触发
# 跟踪修复是否真正生效
# 三次失败 → 邮件通知冰朔手动介入
# 修复成功 → 静默更新仪表盘
#
# 指令编号: ZY-MERGE-WATCHDOG-2026-0324-001
# AG-ZY-088
name: "👁️ Merge Watchdog · 合并指令看守者"
on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
inputs:
pr_number:
description: '手动指定要观察的 PR 编号'
type: number
required: false
permissions:
actions: read
contents: write
pull-requests: write
issues: write
env:
MAX_RETRIES: 3
OBSERVATION_WINDOW_HOURS: 48
WATCHDOG_DATA: "docs/dashboard/watchdog-records.json"
jobs:
# ========================================
# Gate: 只看行动类(已合并的 auto-repair PR
# ========================================
gate:
runs-on: ubuntu-latest
if: >
(github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'fix/auto-repair-'))
|| github.event_name == 'workflow_dispatch'
outputs:
should_watch: ${{ steps.check.outputs.should_watch }}
target_workflows: ${{ steps.check.outputs.target_workflows }}
pr_number: ${{ steps.check.outputs.pr_number }}
steps:
- name: "🔍 识别修复目标"
id: check
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
run: |
echo "[Merge Watchdog] 检测到 auto-repair PR 合并"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
PR_NUM="${{ github.event.inputs.pr_number }}"
if [ -z "$PR_NUM" ] || [ "$PR_NUM" = "0" ]; then
echo "should_watch=false" >> $GITHUB_OUTPUT
echo "⚠️ 手动触发但未指定 PR 编号"
exit 0
fi
PR_TITLE=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUM" --jq '.title' 2>/dev/null || echo "")
else
PR_NUM="${{ github.event.pull_request.number }}"
PR_TITLE="${{ github.event.pull_request.title }}"
fi
echo "PR #$PR_NUM: $PR_TITLE"
# 从 PR body/commits 中提取修复的目标 Workflow
# 先尝试从 PR body 获取修复清单,再用 PR 标题作为回退
if [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
PR_BODY="${{ github.event.pull_request.body }}"
# Try to extract workflow names from commit messages or PR body
WORKFLOW=$(echo "$PR_BODY" | grep -oP '\b[\w-]+\.yml\b' | sort -u | head -5 | tr '\n' ',' | sed 's/,$//' || echo "")
fi
if [ -z "$WORKFLOW" ]; then
# Fallback: use branch name to extract date info, mark as "nightly-repair"
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
WORKFLOW="nightly-repair-$(echo "$BRANCH_NAME" | grep -oP '\d{8}' || echo 'unknown')"
fi
echo "target_workflows=$WORKFLOW" >> $GITHUB_OUTPUT
echo "should_watch=true" >> $GITHUB_OUTPUT
echo "pr_number=$PR_NUM" >> $GITHUB_OUTPUT
echo "👁️ 开始看守: PR #$PR_NUM (targets: $WORKFLOW)"
# ========================================
# 注册看守 + 观察目标 Workflow 运行结果
# ========================================
observe:
needs: gate
if: needs.gate.outputs.should_watch == 'true'
runs-on: ubuntu-latest
outputs:
workflow_result: ${{ steps.wait.outputs.result }}
run_url: ${{ steps.wait.outputs.run_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: "📝 注册看守记录"
env:
PR_NUM: ${{ needs.gate.outputs.pr_number }}
PR_TITLE: ${{ github.event.pull_request.title }}
TARGET: ${{ needs.gate.outputs.target_workflows }}
run: |
node .github/scripts/merge-watchdog.js register "$PR_NUM" "$PR_TITLE" "$TARGET"
git config user.name "watchdog-bot"
git config user.email "watchdog@guanghulab.com"
git add docs/dashboard/watchdog-records.json
git diff --cached --quiet || git commit -m "[WATCHDOG] 注册看守 PR #$PR_NUM"
git push origin main || true
- name: "⏳ 等待目标 Workflow 运行"
id: wait
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
TARGET: ${{ needs.gate.outputs.target_workflows }}
run: |
echo "[Merge Watchdog] 等待目标 Workflow 下一次运行..."
MERGE_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Wait up to 30 minutes checking every 2 minutes
# (the full 48h observation is handled by the nightly scan cycle)
MAX_WAIT=1800
POLL_INTERVAL=120
ELAPSED=0
FOUND="false"
while [ $ELAPSED -lt $MAX_WAIT ]; do
sleep $POLL_INTERVAL
ELAPSED=$((ELAPSED + POLL_INTERVAL))
echo "⏳ 检查中... ($ELAPSED / $MAX_WAIT 秒)"
# Query recent runs that completed after merge
RUNS=$(gh api \
"repos/${{ github.repository }}/actions/runs?per_page=10&status=completed&created=>$MERGE_TIME" \
--jq '.workflow_runs[] | {name: .name, conclusion: .conclusion, html_url: .html_url}' 2>/dev/null || echo "")
if [ -n "$RUNS" ]; then
# Check if any run matches the target
CONCLUSION=$(echo "$RUNS" | jq -r 'select(.name != null) | .conclusion' | head -1)
RUN_URL=$(echo "$RUNS" | jq -r 'select(.name != null) | .html_url' | head -1)
if [ "$CONCLUSION" = "success" ]; then
echo "result=success" >> $GITHUB_OUTPUT
echo "run_url=$RUN_URL" >> $GITHUB_OUTPUT
echo "✅ 目标 Workflow 运行成功"
FOUND="true"
break
elif [ "$CONCLUSION" = "failure" ]; then
echo "result=failure" >> $GITHUB_OUTPUT
echo "run_url=$RUN_URL" >> $GITHUB_OUTPUT
echo "❌ 目标 Workflow 仍然失败"
FOUND="true"
break
fi
fi
done
if [ "$FOUND" = "false" ]; then
echo "result=pending" >> $GITHUB_OUTPUT
echo "run_url=" >> $GITHUB_OUTPUT
echo "⏰ 初始观察窗口结束 — 将在下次夜间扫描中继续跟踪"
fi
# ========================================
# 判定: 成功 → 静默 / 失败 → 计数+告警
# ========================================
verdict:
needs: [gate, observe]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: "📊 读取看守记录"
id: load
env:
PR_NUM: ${{ needs.gate.outputs.pr_number }}
run: |
if [ -f "$WATCHDOG_DATA" ]; then
RETRY_COUNT=$(jq -r ".records[] | select(.pr_number == $PR_NUM) | .retry_count // 0" "$WATCHDOG_DATA" | head -1)
echo "retry_count=${RETRY_COUNT:-0}" >> $GITHUB_OUTPUT
else
echo "retry_count=0" >> $GITHUB_OUTPUT
fi
# -------- 成功路径:静默更新 --------
- name: "✅ 修复确认 — 静默更新仪表盘"
if: needs.observe.outputs.workflow_result == 'success'
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
PR_NUM: ${{ needs.gate.outputs.pr_number }}
run: |
echo "[Merge Watchdog] ✅ 修复已生效 — 静默更新仪表盘"
# Update watchdog records
node .github/scripts/merge-watchdog.js success "$PR_NUM"
# Update DASHBOARD.md
if [ -f DASHBOARD.md ]; then
sed -i "s/| 活跃看守 | .*/| 活跃看守 | $(jq '.merge_watchdog.active_watches' $WATCHDOG_DATA) |/" DASHBOARD.md
sed -i "s/| 已确认修复 | .*/| 已确认修复 | $(jq '.merge_watchdog.resolved_watches' $WATCHDOG_DATA) |/" DASHBOARD.md
fi
git config user.name "watchdog-bot"
git config user.email "watchdog@guanghulab.com"
git add "$WATCHDOG_DATA" DASHBOARD.md
git diff --cached --quiet || git commit -m "[WATCHDOG] ✅ PR #$PR_NUM 修复已确认生效"
git push origin main || true
# Add silent comment to PR
gh pr comment "$PR_NUM" \
--body "✅ **Merge Watchdog 确认:修复已生效** — 仪表盘已静默更新。" 2>/dev/null || true
echo "🤫 不发邮件,不通知,安静收工。"
# -------- 失败路径 --------
- name: "❌ 修复未生效 — 判断重试或告警"
if: needs.observe.outputs.workflow_result == 'failure'
env:
RETRY_COUNT: ${{ steps.load.outputs.retry_count }}
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
PR_NUM: ${{ needs.gate.outputs.pr_number }}
run: |
NEW_COUNT=$((RETRY_COUNT + 1))
echo "[Merge Watchdog] ❌ 第 $NEW_COUNT 次失败"
# Update watchdog records
node .github/scripts/merge-watchdog.js failure "$PR_NUM" "$NEW_COUNT"
if [ $NEW_COUNT -lt ${{ env.MAX_RETRIES }} ]; then
echo "🔄 触发重新修复(策略 $NEW_COUNT"
# Trigger nightly scan for retry with different strategy
gh api "repos/${{ github.repository }}/dispatches" \
--method POST \
-f event_type="watchdog-retry" \
-f "client_payload[pr_number]=$PR_NUM" \
-f "client_payload[retry_round]=$NEW_COUNT" \
-f "client_payload[run_url]=${{ needs.observe.outputs.run_url }}" 2>/dev/null || true
git config user.name "watchdog-bot"
git config user.email "watchdog@guanghulab.com"
git add "$WATCHDOG_DATA"
git diff --cached --quiet || git commit -m "[WATCHDOG] 🔄 PR #$PR_NUM 第${NEW_COUNT}次修复失败,触发重试"
git push origin main || true
else
echo "⛔ 三振出局!"
# Update dashboard
if [ -f DASHBOARD.md ]; then
sed -i "s/| 已升级(需人工) | .*/| 已升级(需人工) | $(jq '.merge_watchdog.escalated_watches' $WATCHDOG_DATA) |/" DASHBOARD.md
fi
git config user.name "watchdog-bot"
git config user.email "watchdog@guanghulab.com"
git add "$WATCHDOG_DATA" DASHBOARD.md
git diff --cached --quiet || git commit -m "[WATCHDOG] ⛔ PR #$PR_NUM 三次修复失败,已升级通知"
git push origin main || true
# Create Issue as fallback alert (in case email is not configured)
gh issue create \
--title "⛔ [WATCHDOG] 自动修复三次失败 — PR #$PR_NUM 需手动介入" \
--body "## ⛔ Merge Watchdog 三振出局通知
PR #$PR_NUM 的修复经过 **3轮自动修复** 仍未解决。
**最新失败日志:** ${{ needs.observe.outputs.run_url }}
### 📋 冰朔需要做什么:
1. 查看上面的失败日志链接
2. 手动定位报错根因
3. 修复代码并推送到 main
4. 等待下一次 Workflow 运行验证
> 看守者已暂停对该问题的自动修复。
> — 光湖系统 · Merge Watchdog" \
--label "tianyan-v3,auto-fix" 2>/dev/null || true
fi
# -------- 三振出局:发邮件(如已配置) --------
- name: "📧 发送人类介入邮件"
if: >
needs.observe.outputs.workflow_result == 'failure' &&
steps.load.outputs.retry_count >= 2
continue-on-error: true
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
secure: true
username: ${{ secrets.ZY_SMTP_USER }}
password: ${{ secrets.ZY_SMTP_PASS }}
subject: "⛔ [光湖系统] 自动修复三次失败 — 需要手动介入"
to: ${{ secrets.ZY_SMTP_USER }}
from: "光湖 Merge Watchdog <noreply@guanghulab.com>"
html_body: |
<h2>⛔ 合并指令看守者 · 三振出局通知</h2>
<p>以下修复经过 <strong>3轮自动修复</strong> 仍未解决:</p>
<table border="1" cellpadding="8">
<tr><td><b>PR</b></td><td>#${{ needs.gate.outputs.pr_number }}</td></tr>
<tr><td><b>目标 Workflow</b></td><td>${{ needs.gate.outputs.target_workflows }}</td></tr>
<tr><td><b>最新失败日志</b></td><td><a href="${{ needs.observe.outputs.run_url }}">点击查看</a></td></tr>
</table>
<h3>📋 你需要做什么:</h3>
<ol>
<li>打开上面的失败日志链接</li>
<li>查看报错信息和上下文</li>
<li>手动修复代码并推送到 main</li>
<li>等待下一次 Workflow 运行验证</li>
</ol>
<p>看守者已暂停对该 Workflow 的自动修复。</p>
<p style="color:gray;">— 光湖系统 · Merge Watchdog</p>
# -------- Pending 路径 --------
- name: "⏰ 观察待续"
if: needs.observe.outputs.workflow_result == 'pending'
run: |
echo "[Merge Watchdog] ⏰ 初始观察窗口内未检测到目标 Workflow 运行"
echo "将在下次天眼夜间扫描中继续跟踪"