diff --git a/.github/workflows/gate.yml b/.github/workflows/gate.yml index ebe5407..a8a708a 100644 --- a/.github/workflows/gate.yml +++ b/.github/workflows/gate.yml @@ -1,6 +1,10 @@ name: gate on: pull_request: + # edited(qodo review #1,CI-Workflows #8 同款加固):adr-required 消费 + # 可变的 PR title/body——不订阅 edited 则作者可在 check 通过后编辑掉 + # ADR 引用而不触发重验;补引用救活 fail 的 check 同样依赖 edited 重触发 + types: [opened, synchronize, reopened, edited] push: branches: [main] @@ -65,8 +69,23 @@ jobs: PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} run: | - # --paginate(评审项):>100 文件的 PR 首页截断会把 C1 变更漏检成非 C1 - FILES=$(gh api --paginate "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files?per_page=100" --jq '.[].filename') + # 文件清单三防线(qodo review #2 #3,CI-Workflows #8 同款加固): + # --paginate:>100 文件的 PR 首页截断会把 C1 变更漏检成非 C1; + # rename 的 previous_filename 一并纳入——governance/standards/CODEOWNERS + # 等 C1 资产改名移出受管路径同样是 C1 变更(files API 只在 + # previous_filename 暴露原路径); + # files API 3000 文件硬上限:返回数 < changed_files = 清单不完整, + # fail-closed(清单不全时 C1 判定不可信,宁误杀不放过)。 + PR_API="repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}" + FILES_API="$PR_API/files?per_page=100" + CHANGED=$(gh api "$PR_API" --jq '.changed_files') + FILES_CUR=$(gh api --paginate "$FILES_API" --jq '.[].filename') + GOT=$(grep -c . <<<"$FILES_CUR" || true) + if [ "$GOT" -lt "$CHANGED" ]; then + echo "::error::PR 声明变更 $CHANGED 个文件但 files API 只返回 $GOT 个(3000 上限截断)——C1 判定完整性无法保证,fail-closed" + exit 1 + fi + FILES=$( { echo "$FILES_CUR"; gh api --paginate "$FILES_API" --jq '[.[].previous_filename // empty][]'; } ) if ! echo "$FILES" | grep -qE '^(governance/|standards/|scripts/|\.github/|CODEOWNERS|profile/)'; then echo "非 C1 路径变更,跳过 adr-required" exit 0