Files
market/.github/workflows/upstream-health.yml
mashagua 6cd60a7141 feat: 新增外部条目上游健康检查与每周巡检工作流 (#188)
## 背景
外部条目只存上游指针,上游仓库被删除、分支被重写或技能目录移动时,客户端安装会静默失败,目前没有任何机制能发现(例如
`dingtalk-cli` 的上游已 404,见修复 PR)。

## 变更
- **`scripts/catalog/check_upstream_health.py`**:只读,逐个检查
`skills/`、`agents/`、`teams/` 下的 `entry.json`:
- 失效(退出码 1):`gone` 上游不存在 · `bad-branch` 分支不存在 · `bad-ref` 固定提交无法获取 ·
`bad-path` `source.path`、根 `SKILL.md` 或 children 路径在分支最新提交下缺失
- 提示:`unreachable` 网络错误(不等于失效)· `new-skill` 集合有未声明子技能(发现规则直接复用
`gen-collection-children.py` 的 `discover_children`,两者结论一致)· `outdated`
固定 ref 落后于分支 · `unpinned` 未锁定 ref
  - 只稀疏检出 `SKILL.md`,39 个条目本地全量运行约 12 秒
- **`scripts/catalog/test_check_upstream_health.py`**:9 个基于本地 Git
仓库的单测,已加入 `i18n-validate.yml`。
- **`.github/workflows/upstream-health.yml`**:每周一 01:23 UTC 运行(可手动触发),仅在
`desirecore/market` 运行:
- 报告写入 Job Summary,并维护唯一一个带 `upstream-health` 标签的
Issue:有待处理项时创建或更新,全部正常时评论并关闭
  - 有失效条目时任务标红
- 权限仅 `contents: read` + `issues: write`,**不改写任何目录文件**;修复与 `source.ref`
更新仍通过评审 PR(与固定 ref 的审查语义一致)
- README 中英文补充用法。

## 当前主干的检查结果
- 失效 1:`dingtalk-cli`(已有修复 PR)
- 未声明子技能 3:`khazix-skills`、`marketingskills`、`mattpocock-skills`
- 可更新 21 个,未锁定 1 个
- `amap-jsapi-skill`、`luckin-my-coffee` 在本地因代理显示 `unreachable`,需要 CI
环境确认

## 验证
```
uv run scripts/catalog/test_check_upstream_health.py   # Ran 9 tests OK
uv run scripts/catalog/check_upstream_health.py        # 如上
uv run scripts/i18n/validate-i18n.py                   # 0 error(s)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_0191D9g1FhRQzEGTefUn6mTb

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Yige <a@wyr.me>
2026-09-26 16:13:14 +08:00

88 lines
3.2 KiB
YAML

name: Upstream Health
# Weekly check that every external pointer (skills/agents/teams entry.json)
# still resolves upstream. Results go to one tracking issue labelled
# `upstream-health`, which is updated in place and closed once nothing is
# actionable. Fixing an entry stays a normal reviewed PR; this workflow never
# rewrites catalog files.
on:
schedule:
- cron: "23 1 * * 1" # Mondays 01:23 UTC
workflow_dispatch:
permissions:
contents: read
issues: write
concurrency:
group: upstream-health
cancel-in-progress: false
jobs:
check:
if: github.repository == 'desirecore/market'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Check upstreams
id: check
run: |
set +e
uv run --quiet scripts/catalog/check_upstream_health.py --format markdown > report.md
code=$?
set -e
if [ "$code" -gt 1 ]; then
echo "health check crashed with exit code $code" >&2
exit "$code"
fi
echo "broken=$([ "$code" = 1 ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
if grep -qE '^### (Broken|Undeclared upstream skills|Updates available) ' report.md; then
echo "actionable=true" >> "$GITHUB_OUTPUT"
else
echo "actionable=false" >> "$GITHUB_OUTPUT"
fi
cat report.md >> "$GITHUB_STEP_SUMMARY"
- name: Update tracking issue
env:
GH_TOKEN: ${{ github.token }}
ACTIONABLE: ${{ steps.check.outputs.actionable }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
label=upstream-health
gh label create "$label" --color D93F0B \
--description "Upstream availability of external catalog entries" 2>/dev/null || true
{
echo "_Updated by [Upstream Health]($RUN_URL) on $(date -u +%Y-%m-%d)._"
echo
echo "Fix entries through a normal PR: repoint or remove \`gone\` entries, correct \`bad-*\` paths, and review upstream changes before bumping \`source.ref\` for \`outdated\` entries (rerun \`scripts/gen-collection-children.py\` for collections). \`unreachable\` means a network error, not a confirmed failure."
echo
cat report.md
} > body.md
issue=$(gh issue list --label "$label" --state open --limit 1 --json number --jq '.[0].number // empty')
if [ "$ACTIONABLE" = "true" ]; then
if [ -n "$issue" ]; then
gh issue edit "$issue" --body-file body.md
else
gh issue create --title "Upstream health report" --label "$label" --body-file body.md
fi
elif [ -n "$issue" ]; then
gh issue comment "$issue" --body "All external entries resolve upstream and are current as of $RUN_URL. Closing."
gh issue close "$issue"
fi
- name: Fail when an entry is broken
if: steps.check.outputs.broken == 'true'
run: |
echo "::error::At least one external entry no longer resolves upstream; see the upstream-health issue."
exit 1