guanghulab/.github/archived-workflows/tianyan-nightly-scan.yml
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

373 lines
14 KiB
YAML
Raw 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/tianyan-nightly-scan.yml
# 🌙 天眼夜间自动修复引擎 v3.0
#
# Phase A: 天眼夜间巡查扫描过去24h失败Workflow
# Phase B: 报错智能分析Gemini API
# Phase C: 铸渊自动修复(生成修复代码)
# Phase D: 天眼审核H1-H9 检查清单)
# Phase E: 创建 PR等待冰朔晨间合并
# Phase F: 更新仪表盘
#
# 指令编号: ZY-TIANYAN-AUTOFIX-2026-0324-001
# AG-ZY-087
name: "🌙 天眼夜间自动修复引擎 v3.0"
on:
schedule:
- cron: '0 15 * * *' # 23:00 CST = 15:00 UTC
workflow_dispatch:
inputs:
force_scan:
description: '强制扫描(忽略时间窗口)'
type: boolean
default: false
repository_dispatch:
types: [watchdog-retry]
permissions:
actions: read
contents: write
pull-requests: write
checks: read
env:
REPAIR_BRANCH_PREFIX: "fix/auto-repair"
MAX_FILES_PER_REPAIR: 5
MAX_LINES_PER_FILE: 50
MAX_RETRY_ROUNDS: 2
GEMINI_MODEL: "gemini-2.0-flash"
PROTECTED_PATTERNS: "tianyan-*.yml,CODEOWNERS,.github/FUNDING.yml"
jobs:
# ========================================
# Phase A: 天眼夜间巡查
# ========================================
nightly-scan:
runs-on: ubuntu-latest
outputs:
has_errors: ${{ steps.scan.outputs.has_errors }}
error_report: ${{ steps.scan.outputs.error_report }}
steps:
- name: "🔭 扫描过去24小时 Workflow 运行记录"
id: scan
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
run: |
echo "[天眼 v3.0] Phase A 启动 — 夜间巡查扫描"
echo "═══════════════════════════════════════════"
SINCE=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)
echo "📅 扫描起始时间: $SINCE"
# 获取失败的 workflow runs
FAILED_RUNS=$(gh api \
"repos/${{ github.repository }}/actions/runs?created=>$SINCE&status=failure&per_page=50" \
--jq '.workflow_runs' 2>/dev/null || echo '[]')
FAIL_COUNT=$(echo "$FAILED_RUNS" | jq 'length')
TOTAL_RUNS=$(gh api \
"repos/${{ github.repository }}/actions/runs?created=>$SINCE&per_page=1" \
--jq '.total_count' 2>/dev/null || echo '0')
echo "📊 过去24小时统计:"
echo " 总运行数: $TOTAL_RUNS"
echo " 失败运行: $FAIL_COUNT"
if [ "$FAIL_COUNT" -eq 0 ] || [ "$FAIL_COUNT" = "null" ]; then
echo "has_errors=false" >> $GITHUB_OUTPUT
echo "✅ 今日无异常"
else
echo "has_errors=true" >> $GITHUB_OUTPUT
# 生成结构化错误报告
ERROR_JSON=$(echo "$FAILED_RUNS" | jq -c '[.[] | {
workflow: .name,
run_id: .id,
conclusion: .conclusion,
html_url: .html_url,
created_at: .created_at,
head_branch: .head_branch
}]')
# Use heredoc for multiline output
echo "error_report<<TIANYAN_EOF" >> $GITHUB_OUTPUT
echo "$ERROR_JSON" >> $GITHUB_OUTPUT
echo "TIANYAN_EOF" >> $GITHUB_OUTPUT
echo "⚠️ 发现 $FAIL_COUNT 个失败运行,进入 Phase B"
fi
# ========================================
# Phase B+C+D: 分析 → 修复 → 审核
# ========================================
analyze-and-repair:
needs: nightly-scan
if: needs.nightly-scan.outputs.has_errors == 'true'
runs-on: ubuntu-latest
outputs:
repair_branch: ${{ steps.repair.outputs.branch_name }}
repair_summary: ${{ steps.create_summary.outputs.summary }}
pr_needed: ${{ steps.review.outputs.pr_needed }}
fix_count: ${{ steps.review.outputs.fix_count }}
overall_risk: ${{ steps.review.outputs.overall_risk }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: "🧠 Phase B — Gemini 报错分析"
id: analyze
env:
GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
ERROR_REPORT: ${{ needs.nightly-scan.outputs.error_report }}
run: |
echo "[铸渊核心大脑] Phase B 启动 — 报错智能分析"
mkdir -p /tmp/tianyan
node .github/scripts/tianyan-analyze.js
- name: "⚒️ Phase C — 铸渊自动修复"
id: repair
env:
GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
run: |
echo "[铸渊核心大脑] Phase C 启动 — 自动修复"
# Check if there are fixable errors
FIXABLE=$(cat /tmp/tianyan/analysis.json | jq '.auto_fixable // 0')
if [ "$FIXABLE" -eq 0 ]; then
echo "⚠️ 没有可自动修复的错误"
echo "branch_name=" >> $GITHUB_OUTPUT
exit 0
fi
# Create repair branch (use timestamp to avoid conflicts)
BRANCH="${REPAIR_BRANCH_PREFIX}-$(date +%Y%m%d)-$(date +%H%M%S)"
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git checkout -b "$BRANCH"
# Run repair script
node .github/scripts/tianyan-repair.js
# Check if there are changes to push
if git diff --quiet && git diff --cached --quiet; then
echo "⚠️ 修复脚本未产生变更"
echo "branch_name=" >> $GITHUB_OUTPUT
else
git push origin "$BRANCH" || echo "⚠️ Push failed"
echo "branch_name=$BRANCH" >> $GITHUB_OUTPUT
fi
- name: "🔭 Phase D — 天眼审核修复代码"
id: review
if: steps.repair.outputs.branch_name != ''
run: |
echo "[天眼 v3.0] Phase D 启动 — 审核修复代码"
node .github/scripts/tianyan-review.js
# Read review result
if [ -f /tmp/tianyan/review-result.json ]; then
PR_NEEDED=$(cat /tmp/tianyan/review-result.json | jq -r '.pr_needed // false')
echo "pr_needed=$PR_NEEDED" >> $GITHUB_OUTPUT
FIX_COUNT=$(cat /tmp/tianyan/repair-result.json | jq '.repaired // 0')
echo "fix_count=$FIX_COUNT" >> $GITHUB_OUTPUT
echo "overall_risk=low" >> $GITHUB_OUTPUT
else
echo "pr_needed=false" >> $GITHUB_OUTPUT
echo "fix_count=0" >> $GITHUB_OUTPUT
fi
- name: "📝 生成 PR 摘要"
id: create_summary
if: steps.review.outputs.pr_needed == 'true'
run: |
DATE=$(date +%Y-%m-%d)
FIX_COUNT="${{ steps.review.outputs.fix_count }}"
RISK="${{ steps.review.outputs.overall_risk }}"
SUMMARY=$(cat <<'SUMMARY_EOF'
## 🌙 天眼夜间自动修复引擎 v3.0
**扫描时间:** SCAN_DATE
**修复数量:** FIX_NUM 个
**风险等级:** RISK_LEVEL
**天眼审核:** ✅ H1-H9 全部通过
### 天眼审核结果
- [x] H1 Secrets安全
- [x] H2 文件完整性
- [x] H3 依赖安全
- [x] H4 权限最小化
- [x] H5 天眼自保护
- [x] H6 变更范围
- [x] H7 Secrets引用完整性
- [x] H8 注释规范
- [x] H9 无残留调试代码
---
> 🤖 此 PR 由铸渊夜间修复引擎自动创建
> 📋 指令编号: ZY-TIANYAN-AUTOFIX-2026-0324-001
> ⏰ 请冰朔在晨间审阅后合并
SUMMARY_EOF
)
SUMMARY="${SUMMARY//SCAN_DATE/$DATE}"
SUMMARY="${SUMMARY//FIX_NUM/$FIX_COUNT}"
SUMMARY="${SUMMARY//RISK_LEVEL/$RISK}"
echo "summary<<SUMMARY_DELIM" >> $GITHUB_OUTPUT
echo "$SUMMARY" >> $GITHUB_OUTPUT
echo "SUMMARY_DELIM" >> $GITHUB_OUTPUT
- name: "🔄 Phase D 重试(如审核未通过)"
if: steps.review.outputs.pr_needed == 'false' && steps.repair.outputs.branch_name != ''
env:
GEMINI_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
run: |
echo "[天眼 v3.0] 审核未通过 — 进入重试流程"
RETRY=0
MAX_RETRY=2
while [ $RETRY -lt $MAX_RETRY ]; do
RETRY=$((RETRY + 1))
echo "🔄 重试第 $RETRY 轮..."
# Re-run repair with retry context
node .github/scripts/tianyan-repair.js
node .github/scripts/tianyan-review.js
PR_NEEDED=$(cat /tmp/tianyan/review-result.json | jq -r '.pr_needed // false')
if [ "$PR_NEEDED" = "true" ]; then
echo "✅ 重试第 $RETRY 轮通过"
break
fi
done
if [ "$PR_NEEDED" != "true" ]; then
echo "❌ $MAX_RETRY 轮重试后仍未通过 — 放弃自动修复"
# Clean up repair branch
git checkout main
git branch -D "${{ steps.repair.outputs.branch_name }}" 2>/dev/null || true
git push origin --delete "${{ steps.repair.outputs.branch_name }}" 2>/dev/null || true
fi
# ========================================
# Phase E+F: 创建 PR + 更新仪表盘
# ========================================
create-pr-and-dashboard:
needs: analyze-and-repair
if: needs.analyze-and-repair.outputs.pr_needed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
- name: "📦 Phase E — 创建 Pull Request"
id: create_pr
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
BRANCH: ${{ needs.analyze-and-repair.outputs.repair_branch }}
SUMMARY: ${{ needs.analyze-and-repair.outputs.repair_summary }}
FIX_COUNT: ${{ needs.analyze-and-repair.outputs.fix_count }}
RISK: ${{ needs.analyze-and-repair.outputs.overall_risk }}
run: |
echo "[天眼 v3.0] Phase E — 创建 Pull Request"
PR_TITLE="🌙 [AUTO-FIX] $(date +%Y-%m-%d) 天眼夜间自动修复 (${FIX_COUNT}个修复)"
# Create labels if they don't exist
gh label create "auto-fix" --color "0E8A16" --description "自动修复 PR" 2>/dev/null || true
gh label create "tianyan-v3" --color "1D76DB" --description "天眼 v3.0 引擎" 2>/dev/null || true
PR_URL=$(gh pr create \
--base main \
--head "$BRANCH" \
--title "$PR_TITLE" \
--body "$SUMMARY" \
--label "auto-fix,tianyan-v3" 2>/dev/null || echo "")
if [ -n "$PR_URL" ]; then
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
echo "✅ PR 已创建: $PR_URL"
# Add risk label
if [ "$RISK" = "low" ]; then
gh label create "safe-to-merge" --color "0E8A16" 2>/dev/null || true
gh pr edit "$PR_URL" --add-label "safe-to-merge" 2>/dev/null || true
elif [ "$RISK" = "medium" ]; then
gh label create "review-carefully" --color "FBCA04" 2>/dev/null || true
gh pr edit "$PR_URL" --add-label "review-carefully" 2>/dev/null || true
fi
else
echo "⚠️ PR 创建失败"
echo "pr_url=" >> $GITHUB_OUTPUT
fi
- name: "📊 Phase F — 更新仪表盘"
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
PR_URL: ${{ steps.create_pr.outputs.pr_url }}
FIX_COUNT: ${{ needs.analyze-and-repair.outputs.fix_count }}
run: |
echo "[天眼 v3.0] Phase F — 更新仪表盘"
DATE=$(date +%Y-%m-%d)
TIME=$(date +%H:%M)
# Update DASHBOARD.md status table
if [ -f DASHBOARD.md ]; then
sed -i "s/| 上次扫描 | .*/| 上次扫描 | $DATE $TIME CST |/" DASHBOARD.md
sed -i "s/| 扫描结果 | .*/| 扫描结果 | ⚠️ 发现错误,已自动修复 |/" DASHBOARD.md
sed -i "s/| 自动修复 | .*/| 自动修复 | ✅ ${FIX_COUNT} 个已修复 |/" DASHBOARD.md
if [ -n "$PR_URL" ]; then
PR_NUM=$(echo "$PR_URL" | grep -oP '\d+$' || echo "?")
sed -i "s/| 待合并 PR | .*/| 待合并 PR | 🟡 PR #${PR_NUM} |/" DASHBOARD.md
fi
git config user.name "tianyan-bot"
git config user.email "tianyan@guanghulab.com"
git add DASHBOARD.md
git diff --cached --quiet || git commit -m "[DASHBOARD] 更新天眼仪表盘 $DATE — ${FIX_COUNT}个修复待合并"
git push origin main || true
fi
# ========================================
# 无错误时的仪表盘更新
# ========================================
dashboard-no-errors:
needs: nightly-scan
if: needs.nightly-scan.outputs.has_errors == 'false'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "✅ 更新仪表盘 — 今日无异常"
env:
GH_TOKEN: ${{ secrets.ZY_GITHUB_PAT }}
run: |
DATE=$(date +%Y-%m-%d)
TIME=$(date +%H:%M)
echo "[天眼 v3.0] 今日无异常,更新仪表盘"
if [ -f DASHBOARD.md ]; then
sed -i "s/| 上次扫描 | .*/| 上次扫描 | $DATE $TIME CST |/" DASHBOARD.md
sed -i "s/| 扫描结果 | .*/| 扫描结果 | ✅ 今日无异常 |/" DASHBOARD.md
sed -i "s/| 自动修复 | .*/| 自动修复 | — |/" DASHBOARD.md
sed -i "s/| 需人工处理 | .*/| 需人工处理 | — |/" DASHBOARD.md
git config user.name "tianyan-bot"
git config user.email "tianyan@guanghulab.com"
git add DASHBOARD.md
git diff --cached --quiet || git commit -m "[DASHBOARD] 今日无异常 $DATE"
git push origin main || true
fi