ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Beads 仓库 Required Check Topology 实战:用聚合 CI Gate 解决 GitHub 分支保护与按风险跳过 CI 的矛盾

Beads 仓库 Required Check Topology 实战:用聚合 CI Gate 解决 GitHub 分支保护与按风险跳过 CI 的矛盾 Beads 仓库 Required Check Topology 实战用聚合 CI Gate 解决 GitHub 分支保护与按风险跳过 CI 的矛盾【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads导读本指南以 Beads 仓库的工程文档 engdocs/CI_REQUIRED_CHECK_TOPOLOGY.md 为骨架系统讲解一套可落地的 GitHub Actions 分支保护拓扑在低风险 PR 跳过昂贵检查的同时仍然让分支保护只依赖一个稳定、永不被路径过滤或条件触发跳过的聚合检查aggregate gate。读完本文你将掌握 Beads 仓库PR / CI Gate / Required与PR Risk / CI Gate / Required两个聚合门的完整设计、ci-gate.sh评估器的判定规则、Embedded/Server Dolt 矩阵的按层跳过策略以及 merge queuemerge_group下必须满足的检查报告约束。问题分支保护需要稳定单门但 CI 想按风险跳过GitHub 分支保护branch protection通常要求一个或多个 Required Status Check 通过后才能合并。Beads 仓库的诉求是只要求一个稳定的 PR 门同时允许 CI 对低风险 PR 跳过昂贵的风险检查例如只改文档的 PR 不必跑完整 Embedded Dolt 矩阵。关键约束在于被设置为 required 的检查不能来自带路径过滤path-filtered或条件触发的工作流因为 GitHub 会在整个工作流被路径过滤、分支过滤或 commit-message 跳过指令如[skip ci]跳过时把该 required 检查永远留在 pending 状态PR 因此无法合并。GitHub 官方语义上的安全区分Skipping workflow runs、Troubleshooting required status checks如下被跳过的整个工作流可能让 required 检查停留在 pending工作流内部被跳过的单个 job反而会报告success作为聚合门aggregate的 job如果依赖其他 job必须使用总是运行的if: ${{ always() }}条件否则上游失败会导致聚合 job 本身被跳过任何用于 merge queue 的 required Actions 检查必须在merge_group事件上运行。这是整套拓扑设计的出发点把昂贵且按需执行的检查下沉为工作流内的 job可跳过、跳过即success把必须稳定的门上升为独立的聚合 job永远运行、聚合所有叶子 job 的结果。当前状态Beads 仓库的 PR 相关工作流全景截至文档记录2026-05-26仓库中 PR 相关工作流及其触发方式如下作者以仓库中 .github/workflows 实际文件核对工作流文件显示名称触发事件角色.github/workflows/pr.ymlPRpull_request仅mainmerge_group基线 PR job、Linux 构建产物、policy/lint 兼容 job、消费 Linux 产物的包门、storage domain/uow 聚焦覆盖以及基线聚合门PR / CI Gate / Required.github/workflows/pr-risk.ymlPR Riskpull_request仅mainmerge_groupEmbedded Dolt 风险检测、embedded 构建/测试分片、Nix flake smoke以及风险聚合门PR Risk / CI Gate / Required.github/workflows/main.ymlMainpush到mainmain 分支健康检查、包门、平台 smoke/short 覆盖、embedded Dolt 覆盖、提升后的 Linux no-short 集成分片.github/workflows/regression.ymlRegression Testspull_request、push到main、手动 dispatch当前不跑merge_group使用 job 级条件回归执行.github/workflows/cross-version-smoke.ymlCross-Version Smoke Tests每个面向main的 PR、tag push、手动 dispatch当前不跑merge_group跨版本升级冒烟.github/workflows/nix-build.ymlnix buildpull_request/push上使用工作流级paths过滤不得被直接设为 required.github/workflows/update-vendor-hash.ymlUpdate vendorHash for dependabot Go bumpspull_request_targetDependabot Go 升级会改动 Dependabot 分支不得作为 required PR 检查另外live 的默认分支 rulesetgastownhall/beads仓库的Protect main - light (beads and gastown)目前只强制删除保护与非快进保护尚未要求任何状态检查——这正是本文所述聚合门后续要接管的缺口。Required Check 契约只要求聚合门不直接要求叶子 job分支保护应指向来自未过滤工作流的稳定聚合 Actions 检查。最初的单检查方案假设所有 PR job 都生活在一个工作流里工作流拆分后工作流内部的聚合门只能覆盖同一工作流内的 job因此第一次上线采用每个 required 工作流一个聚合门基线聚合候选PR / CI Gate / Required风险聚合候选PR Risk / CI Gate / Required来源GitHub Actions应用于面向main的 pull request 与 merge queue 组而以下这些现有检查名不应被直接设为 required它们应保持可见以便诊断分支保护只指向聚合门Detect CI tierCheck build-tag policyCheck pure-Go and js/wasm boundaries (CGO_ENABLED0)Check version consistencyCheck doc flags freshnessCheck for .beads changesTest (ubuntu-latest)、Test (macos-latest)、Test (storage domain uow)Build (Embedded Dolt)Test (Embedded Dolt Storage 1/5)至Test (Embedded Dolt Storage 5/5)Test (Embedded Dolt Cmd 1/20)至Test (Embedded Dolt Cmd 20/20)Test (Windows - smoke)Check formatting、LintTest Nix FlakeDifferential Regression (v0.49.6 baseline)Upgrade smoke (version - candidate)Resolve versions to testnix build .#default从仓库当前源码看.github/workflows/pr.yml 中的ci-gatejob 的needs已实际聚合了 22 个叶子 job含build-artifacts、check-build-tags、check-cmd-bd-puregeo-tests、test-windows-liveness、worktree-remove-windows、check-version-consistency、check-migration-hygiene、check-doc-flags、check-doc-freshness-platforms、pr-preflight-platforms、check-no-beads-changes、detect-package-gates、package-mcp、package-npm、pr-policy-wrapper、pr-core-wrapper、pr-lint-wrapper、test-domain-uow、contract-corpus、fmt-check、lint、windows-make-shell而complexity-report、build-examples、test-macos、test-windows-dbproxy-server等建议性advisoryjob 刻意不进聚合门——这印证了文档中推广一个新 job 进 required 集合是维护者决策的原则。工作流拓扑三原则1. Required 工作流保持无条件触发.github/workflows/pr.yml 是 required 基线工作流的拥有者其 PR 与 merge queue 触发器必须保持无过滤on: pull_request: branches: [ main ] merge_group:不要给pr.yml或pr-risk.yml添加paths、paths-ignore或更窄的分支过滤。路径与风险决策应交给 detector job 和 job 级if条件完成而不是工作流级过滤。2. 添加聚合 Gate jobpr.yml中基线聚合门的历史初始快照如下注意这是历史快照不再与后续新增/重命名的叶子 job 同步当前接线以 .github/workflows/pr.yml 及其结构性测试为准ci-gate: name: CI Gate / Required runs-on: ubuntu-latest needs: - build-artifacts - check-build-tags - check-cmd-bd-puregeo-tests - check-version-consistency - check-no-duplicate-migrations - check-doc-flags - check-no-beads-changes - detect-package-gates - package-mcp - package-npm - package-website - pr-policy-wrapper - pr-core-wrapper - pr-lint-wrapper - test-domain-uow - fmt-check - lint if: ${{ always() }} steps: - uses: actions/checkoutde0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Evaluate CI gate env: CI_GATE_NAME: PR baseline gate CI_GATE_REQUIRED: - BUILD_ARTIFACTS CHECK_BUILD_TAGS CHECK_CMD_BD_PUREGEO_TESTS CHECK_VERSION_CONSISTENCY CHECK_NO_DUPLICATE_MIGRATIONS CHECK_DOC_FLAGS CHECK_NO_BEADS_CHANGES DETECT_PACKAGE_GATES PACKAGE_MCP PACKAGE_NPM PACKAGE_WEBSITE PR_POLICY_WRAPPER PR_CORE_WRAPPER PR_LINT_WRAPPER TEST_DOMAIN_UOW FMT_CHECK LINT BUILD_ARTIFACTS: ${{ needs.build-artifacts.result }} CHECK_BUILD_TAGS: ${{ needs.check-build-tags.result }} CHECK_CMD_BD_PUREGEO_TESTS: ${{ needs.check-cmd-bd-puregeo-tests.result }} CHECK_VERSION_CONSISTENCY: ${{ needs.check-version-consistency.result }} CHECK_NO_DUPLICATE_MIGRATIONS: ${{ needs.check-no-duplicate-migrations.result }} CHECK_DOC_FLAGS: ${{ needs.check-doc-flags.result }} CHECK_NO_BEADS_CHANGES: ${{ needs.check-no-beads-changes.result }} DETECT_PACKAGE_GATES: ${{ needs.detect-package-gates.result }} PACKAGE_MCP: ${{ needs.package-mcp.result }} PACKAGE_NPM: ${{ needs.package-npm.result }} PACKAGE_WEBSITE: ${{ needs.package-website.result }} PR_POLICY_WRAPPER: ${{ needs.pr-policy-wrapper.result }} PR_CORE_WRAPPER: ${{ needs.pr-core-wrapper.result }} PR_LINT_WRAPPER: ${{ needs.pr-lint-wrapper.result }} TEST_DOMAIN_UOW: ${{ needs.test-domain-uow.result }} FMT_CHECK: ${{ needs.fmt-check.result }} LINT: ${{ needs.lint.result }} run: | skipped_ok if [[ $GITHUB_EVENT_NAME merge_group ]]; then skipped_okCHECK_NO_BEADS_CHANGES fi export CI_GATE_SKIPPED_OK$skipped_ok bash .github/scripts/ci-gate.shpr-risk.yml则有一个针对detect-ci-tier、build-embedded、test-embedded-storage、test-embedded-cmd、test-nix的配套聚合门。ci-gate.sh评估器判定规则.github/scripts/ci-gate.sh 是一个很小的 shell 求值器set -euo pipefail从needs.*.result聚合。它对每个必需变量按result值分类判定success→ 通过skipped→ 仅当该变量在CI_GATE_SKIPPED_OK白名单中才通过否则失败failure/cancelled→ 失败未设置→ 失败unset其他意外值 → 失败unexpected result。核心的is_skipped_ok()函数用[[ $skipped_ok_vars * $var * ]]做精确的空格分隔匹配避免BUILD_EMBEDDED与BUILD_EMBEDDED_X之类的误判。任何失败都会通过::error::注解输出到日志最终exit 1聚合门变红。允许skipped的合法场景包括CHECK_NO_BEADS_CHANGESskipped在merge_group上可接受该 job 是 PR 专属见 pr.yml 中check-no-beads-changes的if: github.event_name pull_request在风险聚合中BUILD_EMBEDDED、TEST_EMBEDDED_STORAGE、TEST_EMBEDDED_CMD仅在FULL_EMBEDDED ! true时可skipped见 pr-risk.yml 中 ci-gate 对CI_GATE_SKIPPED_OK的动态赋值其余基线 job 必须全部success。这样分支保护指向稳定聚合 job同时保留底层 job 名称与日志便于诊断。3. 风险决策保持在 job 级条件风险检查应使用如下模式detector 输出 → job 级if→ 聚合门always()detect-risk: name: Detect risk outputs: run_risk: ${{ steps.detect.outputs.run_risk }} risk-check: name: Risk check needs: detect-risk if: needs.detect-risk.outputs.run_risk true ci-gate: name: CI Gate / Required needs: [detect-risk, risk-check] if: ${{ always() }}required 聚合门应仅当detect-risk.outputs.run_risk ! true时把risk-checkskipped视为成功若 detector 想要跑风险检查而它被跳过、失败或被取消聚合门必须失败。禁止在 required 检查上使用这种工作流级路径过滤on: pull_request: paths: - go.mod - go.sum若该工作流或其某个 job 被设为 required不触碰这些路径的 PR 会一直等待 GitHub 永远不会创建的检查永久阻塞。条件检查的落点各矩阵的具体处理Embedded Dolt 矩阵当前 embedded Dolt 拓扑已契合 required-check 模型detect-ci-tier总是运行build-embedded、test-embedded-storage、test-embedded-cmd使用 job 级if.github/scripts/ci-embedded-tier.sh 对push、merge_group、PR diff 边界不可用、以及命中风险路径时运行完整 embedded 覆盖。它通过git diff --name-only base head检查变更路径命中cmd/*、internal/*、tests/*、scripts/*、.github/scripts/*、.github/workflows/*、*.go、go.mod/go.sum、Makefile、default.nix、flake.nix、flake.lock、packages.nix及核心文档AGENTS.md等即判定为风险路径仅文档 PR 可以跳过 embedded 矩阵不会让 required 门悬置因为聚合 job 仍然运行。仓库结构性测试 scripts/ci_workflow_test.go 正是为这套契约兜底它解析pr.yml/pr-risk.yml/main.yml断言ci-gate的if为${{ always() }}、needs与CI_GATE_REQUIRED、env result 映射三者一致并断言各矩阵 job 的strategy.fail-fast必须为false防止单个慢/抖动分片取消兄弟分片。Server Dolt Storage 矩阵test-server-storage-full镜像test-embedded-storage的分片方式在同一工作流中降一档job 级if复用与 embedded 矩阵相同的detect-ci-tier门.github/scripts/server-storage-test-shard.sh 从internal/storage/dolt/*_test.go发现顶层Test*函数排除TestConformance它由独立的test-server-storagejob 用-test.run ^TestConformance$子测试路径分片通过提交在仓库中的 .github/scripts/server-storage-test-shards.txt 清单分配已知重型测试其余按hash(name) % total散列分配——与embedded-storage-test-shard.sh相同的清单 散列回退机制16 个分片vs embedded 的 5 个server 模式是真实的 socket 往返针对容器化 Dolt server 每次测试执行CREATE/DROP DATABASE且该包顶层测试数是 embedded 套件的 3.5 倍1126 vs 324。此前未分片的单 jobGo 15m 超时、timeout-minutes: 20从未跑完——在 256/1126 个测试处因超时死亡零失败纯属时间不足。其中TestCloudAuthCLIRouting一个测试就要约 9.5 分钟被清单单独钉在 shard 1避免拖累其他分片fail-fast: false与该工作流中所有矩阵 job 一致。回归测试RegressionRegression Tests可以保持为非 required工作流。若回归要影响合入门不要直接 requiredDifferential Regression (v0.49.6 baseline)改用以下窄方案之一把回归 detector 与回归 job 移入 required PR 拓扑接入对应聚合门并补充默认运行回归的merge_group行为保持regression.yml独立移除工作流级 skip 过滤添加merge_group追加一个最终Regression Gate / Informational聚合门并保持非 required除非有意扩展分支保护。首选拓扑只把聚合门设为 required。Nix Build.github/workflows/nix-build.yml 当前使用工作流级paths过滤pull_request与push均有。保持nix build .#default非 required。若完整 Nix 构建必须影响可合并性应把它移入未过滤的 required PR 工作流置于 detector 与 job 级if之后并教会聚合门何时接受被跳过的 Nix build。不要直接 required 路径过滤的nix build工作流或nix build .#defaultjob。跨版本冒烟Cross-Version SmokeCross-Version Smoke Tests对普通 PR 应保持非 required除非维护者明确选择在聚合门中支付该成本。若变为 required需添加merge_group并置于 required 拓扑内的 detector 聚合之后。不要直接 required 矩阵展开的Upgrade smoke (version - candidate)job。Merge Queue 行为merge_group是不可省略的一环Required 聚合检查必须为merge_group报告。否则 GitHub 可以先把 PR 入队然后因 required 检查从未对合成 merge group 提交报告而无法合并。对merge_group的策略PR与PR Risk必须包含merge_group触发器detect-ci-tier应把merge_group视为完整 embedded 覆盖ci-embedded-tier.sh 的case分支已实现merge_group → full_embeddedtrue任何加入 required 拓扑的风险 detector 都应默认在merge_group上运行——因为 merge group 提交可能把各自安全的 PR 组合成有风险的集成状态聚合门应像处理 PR 结果一样处理 merge group 结果唯一例外是 PR 专属的卫生检查如Check for .beads changes可以按设计跳过pr.yml的 ci-gate 在GITHUB_EVENT_NAME merge_group时把CHECK_NO_BEADS_CHANGES加入CI_GATE_SKIPPED_OK。首次上线清单与回滚步骤首次上线快照历史决策上下文以下清单记录了最初的部署计划作为决策背景保留不是当前部署流程工作流接线已实现第 7、8 步的分支保护/ruleset 策略变更仍是维护者的待决事项。向 required PR 工作流添加 .github/scripts/ci-gate.sh 与聚合门 job最初在分支ci/bd-am3.1-wrapper-commands上开发开一个 PR验证新聚合检查名在 GitHub Actions 中精确出现验证仅文档 PRembedded job 被跳过时聚合门成功验证风险 PR 或手动测试分支embedded job 运行且通过时聚合门成功验证一个刻意失败的底层 job 会使对应聚合门失败验证 merge queue 运行在 merge group 上报告聚合门更新默认分支 ruleset 或分支保护只要求来自 GitHub Actions 的聚合门移除对单个 CI、回归、Nix、跨版本 job 名的直接 required。回滚步骤从默认分支 ruleset 或分支保护中移除聚合门检查恢复此前存在的 required 检查列表若有还原添加聚合门 job 与评估器的工作流提交确认新的 PR 不再等待聚合门。如果回滚是因为聚合逻辑有误优先先放宽分支保护移除聚合要求——这能在不隐藏用于诊断的失败工作流日志的前提下解阻塞合并。Commit-Message 跳过指令与 fail-closed 保障上述拓扑解决了路径过滤与分支过滤导致的 pending required 检查。但当 HEAD 提交信息包含[skip ci]等跳过指令时GitHub 仍可跳过push与pull_request工作流。若维护者需要提交信息跳过也必须 fail closed而不是 pending的硬保证required 检查必须由一个不受这些指令跳过的可信小报告器发出例如一个pull_request_target工作流——不 checkout、不运行 PR 代码在检查不受信的pull_request工作流结果后于 PR head SHA 上创建名为CI Gate / Required的 check run。该报告器刻意不在第一次窄上线范围内。在此之前不要对面向main的 PR 使用 commit-message 跳过指令。小结一份可直接复用的聚合门设计蓝图Beads 仓库的 required-check 拓扑把分支保护只认一个稳定门与CI 按风险省钱统一起来required 工作流永远无过滤触发风险决策全部下沉到 detector job 级ifci-gate.sh作为小型判定器把needs.*.result收敛为单一结论always()保证聚合 job 即使上游全跳也会运行并给出明确 verdict。配合 scripts/ci_workflow_test.go 这类结构性测试工作流拓扑本身也被纳入了 CI 的可验证范围。如果你的仓库同样面临路径过滤工作流导致 required 检查悬置的经典困境这套每 required 工作流一个聚合门 skipped 白名单 merge_group 全量覆盖的方案可以直接照搬落地。【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表