其他
发布 OpenSpec 时如何审计合并工作、补齐…
在需要发布 OpenSpec(或类似 Changesets 驱动的 npm 包)时,按可恢复状态机审计 GitHub 状态、决定是否补 changeset、验证 Version Packages PR 并核实发布产物。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
发布 OpenSpec 时如何审计合并工特定
解决思路
- 把 `Fission-AI/OpenSpec` 和 `origin/main` 作为发布事实来源;每次调用都检查实时 GitHub 状态,只执行下一个安全动作,不要假设上次调用已完成。
- 用户询问状态、就绪度或建议时默认只做只读审计;用户要求 release、prepare、continue 或 resume 时才视为授权执行相应发布动作。
- 保留用户的 checkout:不要丢弃无关改动,也不要为了准备 changeset 而切换用户当前分支;当 checkout 脏或不在 `main` 上时,从当前 `origin/main` 创建临时 worktree 来提交发布相关改动。
- 绝不批准自己的 PR;人工审查是刻意的关卡。
- 把进入 merge queue 视为中间状态而非已合并;只有 GitHub 报告 `mergedAt` 且提交出现在 `main` 上才继续推进。
- 绝不手动创建自动化的 Version Packages PR,它由 Changesets action 拥有。
- 绝不为了重触发 CI 而推送空提交;先诊断失败或缺失的运行。
- 暂停时报告 URL、所处状态以及需要人工执行的确切动作。
- 区分两类 PR:Changeset PR 是人工编写、添加 `.changeset/*.md` 文件的普通 PR(优先把 changeset 加到 feature/fix PR;仅对已合并但应纳入的工作创建 catch-up changeset PR);Version Packages PR 是自动化的 `changeset-release/main` PR,标题为 `chore(release): version packages`,合并它会发布稳定版。
- 注意:打开的 Version Packages PR 不禁止 catch-up changeset PR;只有当审计发现缺失的应发布工作时,catch-up PR 才有用。该 PR 合并后,等待现有 Version Packages PR 更新。
- 审计第 1 步:用 `gh repo view --json nameWithOwner,url` 解析仓库;写操作前要求已认证的 `gh`、`git` 和 `pnpm`;若规范仓库不是 `Fission-AI/OpenSpec` 则在发布变更前停止。
- 审计第 2 步:用 `git fetch origin main` 刷新而不修改 worktree;不要无差别 fetch 所有 tag,因为仓库可能存在冲突的历史本地 tag 导致 `git fetch --tags` 失败。
- 审计第 3 步:用 `gh release list --repo Fission-AI/OpenSpec --exclude-drafts --exclude-pre-releases --limit 100 --json tagName,publishedAt --jq 'max_by(.publishedAt) | {tagName, publishedAt}'` 找最新稳定 GitHub release;不要用 `git describe`,因为 beta tag 可能比稳定基线更新。使用前确保该稳定 tag 在本地可解析,缺失时只 fetch 该 tag;若同名本地 tag 与规范远端不一致,报告不匹配并使用单独解析的规范提交,绝不在审计中强制重写用户 tag。
- 审计第 4 步:用 `gh pr list --repo Fission-AI/OpenSpec --state open --head changeset-release/main --json number,title,headRefName,baseRefName,url,reviewDecision,statusCheckRollup` 找打开的发布相关 PR;通过 `headRefName == "changeset-release/main"` 而非仅标题识别 Version Packages PR;单独列出可能的 changeset PR 并检查其文件,要求对 `.changeset/*.md` 有正向新增;不要把 Version Packages PR 的 changeset 删除误认为人工 changeset,也不要仅凭标题判断。
- 审计第 5 步:阅读 `.changeset/README.md` 中的实时发布策略、`origin/main` 上待处理的 `.changeset/*.md` 文件,以及存在时的 Version Packages PR 正文/文件。
- 审计第 6 步:用 `git log --first-parent --date=short --pretty=format:'%h%x09%ad%x09%s' <stable-tag>..origin/main` 列出最新稳定 tag 以来的 first-parent 提交。
- 审计第 7 步:把应发布的已合并 PR 映射到现有 changeset;使用 PR 文件和 changeset 历史,不要仅凭相似措辞推断覆盖。
- 审计第 8 步:将审计分类为 `missing-tracking`、`awaiting-changeset-review`、`awaiting-merge-queue`、`awaiting-version-update`、`awaiting-version-review`、`ready-to-publish`、`publishing`、`needs-finalization` 或 `complete`。
- 呈现紧凑审计:稳定基线、拟议版本、已覆盖变更、可能遗漏、有意跳过的内部/文档工作、打开的 PR 以及下一步动作。
- 决定 changeset 覆盖时遵循 `.changeset/README.md`,不要假设每个已合并 PR 都需要 changeset;纳入应发布跟踪的工作(新用户功能或命令、显著修复或 hotfix、破坏性变更或弃用、用户可见的性能改进),通常跳过仅文档、测试、CI/工具和内部重构;对模糊的用户可见变更要标记而非静默排除;仅当模糊性实质影响发布范围或语义版本时才询问用户,否则用最佳判断并让 PR 审查作为批准关卡。
- 仅在 `missing-tracking` 时创建或继续 changeset PR:若已有打开的 changeset PR 覆盖缺失工作则复用它,检查其 `headRefName`、head 仓库和 `maintainerCanModify`,从所属仓库 fetch 该确切 head 分支到临时 worktree,在那里更新并推回同一 PR head;若分支不可写则停止;不要创建重复 PR 或替换分支。
- 编写前立即阅读 `.changeset/README.md`。
- 仅当不存在合适 PR 时,才从当前 `origin/main` 创建短的 `changeset-<scope>` 分支,使用临时 worktree 以保持操作者 checkout 不变。
- 优先每个连贯发布单元一个 changeset;单个 catch-up changeset 可汇总同一发布中选定的多个小项。
- 使用确切包名 `"@fission-ai/openspec"`、所需最高语义 bump、仅相关标题和面向用户的描述。
- 推送前用 `pnpm exec changeset status` 验证。
- 提交、推送并打开 PR,正文列出覆盖的已合并 PR 并解释为何需要 catch-up。
- 返回 PR URL 并请求人工批准后停止;不要自己批准。
- 后续调用时,若 PR 已批准且检查通过,仅在用户要求继续或完成发布时合并或入队;若 GitHub 使用 merge queue,检查 `mergeQueueEntry`、队列检查和 `mergedAt`,在 PR 真正落到 `main` 前保持 `awaiting-merge-queue`;然后等待 `main` 上的 Changesets action 更新现有 Version Packages PR;用简洁进度更新轮询,不要推送空提交或额外分支更新,因为那可能撤销批准并重启队列。
- 验证 Version Packages PR 就绪前第 1 步:确认它从 `changeset-release/main` 指向 `main` 且由预期自动化生成。
- 第 2 步:枚举当前 `main` 上所有待处理 `.changeset/*.md`(排除 `.changeset/README.md`),验证 PR 消耗了每一个并包含相应 changelog 内容;若有待处理 changeset 应推迟,停止:通过单独审查的变更移除或修订它,并等待自动化重新生成 Version Packages PR 后再继续。
- 第 3 步:用 `gh pr view` 获取 `baseRefOid` 和 `headRefOid`,要求 `baseRefOid` 等于当前 `origin/main`,并为两个修订创建干净的 detached 临时 worktree;若本地缺失 head 对象,先 fetch 不可变的 `pull/<number>/head` ref;绝不从操作者当前 worktree 验证。
- 第 4 步:在 base worktree 中运行 `pnpm exec changeset status --output changeset-status.json` 并从该文件读取预期包/版本;若 Changesets CLI 不可用,先在临时 worktree 安装锁定依赖。
- 第 5 步:把 base 状态和完整待处理 changeset 集合与 head worktree 比较:`package.json`、`CHANGELOG.md`、被移除的 changeset 文件、PR 正文和拟议版本必须全部一致;这是 base 到 head 的比较,因为 head 已消耗 changeset 无法自行计算待发布版本。
- 第 6 步:验证后移除临时 worktree,然后用 `gh pr view` / `gh pr checks` 检查所有必需检查和审查状态。
- 若 Version Packages PR 是最新但未批准,返回 URL 并暂停等待人工批准;若已批准且通过,仅在用户要求发布或继续时合并或入队;启用 merge queue 时,不要把批准、启用 auto-merge 或入队当作稳定发布触发,等待 `mergedAt` 并确认合并到达 `main`。
- 稳定发布验证第 1 步:找到合并提交的 release workflow 运行并等待完成。
- 第 2 步:独立验证三个产物:`npm view @fission-ai/openspec@<version> version`、远端 tag `v<version>` 指向预期提交、`gh release view v<version>` 存在且不是 prerelease。
- 第 3 步:若只有部分产物存在,报告部分状态并在重试任何发布动作前恢复验证;绝不重新发布已在 npm 上的版本。
- 第 4 步:所有产物存在后,阅读 [references/release-notes.md](references/release-notes.md),润色 GitHub Release 并验证保存的标题/正文。
- 仅在用户明确要求 beta 或 prerelease 时进入 beta 路径:运行相同审计并确认待处理 changeset 产生下一个稳定版本;说明 beta 发布不消耗 changeset 也不替换稳定 Version Packages PR;在 `main` 上触发现有 `release-prepare.yml` workflow,不要在本地计算或设置 beta 版本;验证 workflow 选择的版本、npm `beta` dist-tag、远端 tag 和 prerelease GitHub Release;不要作为 beta 请求的一部分合并稳定 Version Packages PR。
- 处理失败:CI 失败时先检查失败检查和日志再提议重跑或改代码;Version Packages PR 过期时先确认最新 changeset 到达 `main` 后 `release-prepare.yml` 的 `push` 运行成功;分支分叉时让 Changesets action 更新其分支,不要 force-push `changeset-release/main`;PR 排队时检查 merge-group 检查和队列状态,正常推进时不要重新入队、更新分支或重跑无关检查;版本已存在于 npm 时停止并协调 tag/GitHub Release,而不是隐式递增或重新发布;缺少 GitHub 权限或必需审查时报告确切关卡和 URL,保留检测到的状态以便下次调用通过检查恢复。
- 完成报告包含:发布版本和稳定/beta 渠道;changeset PR 和 Version Packages PR URL(如适用);release workflow 结果;npm 包、tag 和 GitHub Release 验证;release notes 最终化状态;任何有意推迟的变更。
适用边界 · 注意事项
- 不适用于非 OpenSpec 仓库或非 Changesets 驱动的发布流程。
- 不适用于用户仅询问状态、就绪度或建议时执行写操作(此时应只做只读审计)。
- 不适用于用户未明确要求 beta/prerelease 时走 beta 发布路径。