Merge pull request #113 from qinfendebingshuo/copilot/fix-readme-override-issue
fix: restore README.md, fix 4 broken workflows, add meta-watchdog
This commit is contained in:
commit
7abefa7935
|
|
@ -185,11 +185,14 @@ jobs:
|
||||||
|
|
||||||
# ── Step 6: 向 Notion 回报巡检结果 ──
|
# ── Step 6: 向 Notion 回报巡检结果 ──
|
||||||
- name: 向 Notion 回报巡检结果
|
- name: 向 Notion 回报巡检结果
|
||||||
if: ${{ secrets.NOTION_TOKEN != '' && secrets.SYSLOG_DB_ID != '' }}
|
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
|
||||||
SYSLOG_DB_ID: ${{ secrets.SYSLOG_DB_ID }}
|
SYSLOG_DB_ID: ${{ secrets.SYSLOG_DB_ID }}
|
||||||
run: |
|
run: |
|
||||||
|
if [ -z "$NOTION_TOKEN" ] || [ -z "$SYSLOG_DB_ID" ]; then
|
||||||
|
echo "⚠️ NOTION_TOKEN 或 SYSLOG_DB_ID 未配置,跳过 Notion 回报"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
echo "📡 向 Notion 跨平台信号日志回报..."
|
echo "📡 向 Notion 跨平台信号日志回报..."
|
||||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
|
||||||
BRAIN_STATUS="${{ steps.brain_check.outputs.brain_status }}"
|
BRAIN_STATUS="${{ steps.brain_check.outputs.brain_status }}"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
name: "🐕 元看门狗 · 巡检健康监控"
|
||||||
|
|
||||||
|
# ━━━ 元看门狗:极简独立 workflow,监控巡检本身是否在跑 ━━━
|
||||||
|
# 设计原则:
|
||||||
|
# · 极简:不依赖任何外部脚本,只用 curl + 内联 node,PR 无法意外破坏它
|
||||||
|
# · 独立:与被监控的 workflow 完全分离
|
||||||
|
# · 写 Notion:告警直接写入霜砚可读的 Notion 数据库
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 */6 * * *' # 每6小时一次(北京时间 2/8/14/20点)
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-patrol-health:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 检查 daily-maintenance 最近运行状态
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# 用 GitHub API 查 daily-maintenance 最近一次运行时间
|
||||||
|
LAST_RUN=$(curl -s \
|
||||||
|
-H "Authorization: Bearer $GH_TOKEN" \
|
||||||
|
"https://api.github.com/repos/${{ github.repository }}/actions/workflows/daily-maintenance.yml/runs?per_page=1&status=completed" \
|
||||||
|
| node -e "const d=require('fs').readFileSync('/dev/stdin','utf8'); \
|
||||||
|
const r=JSON.parse(d).workflow_runs && JSON.parse(d).workflow_runs[0]; \
|
||||||
|
console.log(r ? r.updated_at : 'NEVER')")
|
||||||
|
|
||||||
|
echo "daily-maintenance 最后运行:$LAST_RUN"
|
||||||
|
|
||||||
|
# 计算距上次运行的时间差,超过 26 小时则告警(24h 调度周期 + 2h 缓冲)
|
||||||
|
node -e "
|
||||||
|
const last = new Date('$LAST_RUN');
|
||||||
|
const now = new Date();
|
||||||
|
const hours = (now - last) / 3600000;
|
||||||
|
if (isNaN(hours) || hours > 26) {
|
||||||
|
console.log('ALERT: daily-maintenance 已超 ' + Math.round(hours) + 'h 未运行');
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
console.log('OK: 距上次运行 ' + Math.round(hours) + 'h,正常');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: 写入 Notion 告警(仅在失败时触发)
|
||||||
|
if: failure()
|
||||||
|
env:
|
||||||
|
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
|
echo "⚠️ NOTION_API_TOKEN 未配置,跳过 Notion 告警"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -s -X POST https://api.notion.com/v1/pages \
|
||||||
|
-H "Authorization: Bearer $NOTION_TOKEN" \
|
||||||
|
-H "Notion-Version: 2022-06-28" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"parent\": {\"database_id\": \"f983bdc24b654888913ca254160bff33\"},
|
||||||
|
\"properties\": {
|
||||||
|
\"标题\": {\"title\": [{\"text\": {\"content\": \"⚠️ 元看门狗告警:daily-maintenance 巡检中断\"}}]},
|
||||||
|
\"处理状态\": {\"status\": {\"name\": \"待处理\"}}
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
@ -294,20 +294,19 @@ jobs:
|
||||||
|
|
||||||
# ━━━ 阶段三:生成 Notion 诊断报告 ━━━
|
# ━━━ 阶段三:生成 Notion 诊断报告 ━━━
|
||||||
- name: "📋 阶段三 · 写入 Notion 工单"
|
- name: "📋 阶段三 · 写入 Notion 工单"
|
||||||
if: ${{ secrets.NOTION_API_TOKEN != '' }}
|
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID || '84edd0640bf146a9a5a7840107013e8c' }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID || '84edd0640bf146a9a5a7840107013e8c' }}
|
||||||
PM2_REPORT: ${{ steps.pm2_diagnose.outputs.pm2_report }}
|
PM2_REPORT: ${{ steps.pm2_diagnose.outputs.pm2_report }}
|
||||||
CLEANUP_REPORT: ${{ steps.pm2_cleanup.outputs.cleanup_report }}
|
CLEANUP_REPORT: ${{ steps.pm2_cleanup.outputs.cleanup_report }}
|
||||||
HEALTH_REPORT: ${{ steps.health_check.outputs.health_report }}
|
HEALTH_REPORT: ${{ steps.health_check.outputs.health_report }}
|
||||||
run: node scripts/server-diagnose-report.js
|
|
||||||
|
|
||||||
- name: "📋 阶段三 · 写入 Notion 工单(环境检查)"
|
|
||||||
if: ${{ secrets.NOTION_API_TOKEN == '' }}
|
|
||||||
run: |
|
run: |
|
||||||
echo "⚠️ Notion credentials 未配置,跳过工单创建"
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
echo "诊断报告仅输出到 Actions 日志"
|
echo "⚠️ Notion credentials 未配置,跳过工单创建"
|
||||||
|
echo "诊断报告仅输出到 Actions 日志"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
node scripts/server-diagnose-report.js
|
||||||
|
|
||||||
- name: "✅ 诊断完成"
|
- name: "✅ 诊断完成"
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,6 @@ jobs:
|
||||||
|
|
||||||
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
||||||
id: ticket
|
id: ticket
|
||||||
if: ${{ secrets.NOTION_API_TOKEN }}
|
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
|
|
@ -143,7 +142,12 @@ jobs:
|
||||||
MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }}
|
MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }}
|
||||||
DEVELOPER: ${{ steps.parse.outputs.author }}
|
DEVELOPER: ${{ steps.parse.outputs.author }}
|
||||||
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
||||||
run: node scripts/create-standardized-ticket.js
|
run: |
|
||||||
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
|
echo "⚠️ NOTION_API_TOKEN 未配置,跳过 Notion 工单创建"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
node scripts/create-standardized-ticket.js
|
||||||
|
|
||||||
- name: 📡 推送广播到 GitHub(Phase B4)
|
- name: 📡 推送广播到 GitHub(Phase B4)
|
||||||
if: steps.persona.outcome == 'success' && steps.parse.outputs.type == 'syslog'
|
if: steps.persona.outcome == 'success' && steps.parse.outputs.type == 'syslog'
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,6 @@ jobs:
|
||||||
|
|
||||||
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
||||||
id: ticket
|
id: ticket
|
||||||
if: ${{ secrets.NOTION_API_TOKEN }}
|
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
|
|
@ -224,7 +223,12 @@ jobs:
|
||||||
MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }}
|
MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }}
|
||||||
DEVELOPER: ${{ steps.parse.outputs.author }}
|
DEVELOPER: ${{ steps.parse.outputs.author }}
|
||||||
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
||||||
run: node scripts/create-standardized-ticket.js
|
run: |
|
||||||
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
|
echo "⚠️ NOTION_API_TOKEN 未配置,跳过 Notion 工单创建"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
node scripts/create-standardized-ticket.js
|
||||||
|
|
||||||
- name: 📋 步骤 5/8 · 创建 Notion 工单(成功)
|
- name: 📋 步骤 5/8 · 创建 Notion 工单(成功)
|
||||||
if: always() && steps.ticket.outcome == 'success'
|
if: always() && steps.ticket.outcome == 'success'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue