@icebreakers/monorepo-templates 2.0.5 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,10 @@ on:
35
35
  required: false
36
36
  default: false
37
37
  type: boolean
38
+ source-sha:
39
+ description: Original main commit to recover (publish modes only)
40
+ required: false
41
+ type: string
38
42
 
39
43
  env:
40
44
  HUSKY: 0
@@ -104,6 +108,7 @@ jobs:
104
108
  REPO_RELEASE_PACKAGE: ${{ inputs.package }}
105
109
  REPO_RELEASE_VERSION: ${{ inputs.version }}
106
110
  REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }}
111
+ REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }}
107
112
  run: pnpm exec repo release ci
108
113
 
109
114
  - name: Preserve npm publish progress
@@ -114,5 +119,6 @@ jobs:
114
119
  path: |
115
120
  pnpm-publish-summary.json
116
121
  repoctl-publish-progress.json
122
+ repoctl-release-progress.json
117
123
  if-no-files-found: ignore
118
124
  retention-days: 14
package/assets/gitignore CHANGED
@@ -46,3 +46,5 @@ config.ts.timestamp-*.mjs
46
46
  /repoctl-publish-progress.json
47
47
  /pnpm-publish-summary.json.*.tmp
48
48
  /repoctl-publish-progress.json.*.tmp
49
+
50
+ /repoctl-release-progress.json
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "version": "0.0.0",
5
5
  "private": true,
6
- "packageManager": "pnpm@12.6.0",
6
+ "packageManager": "pnpm@12.8.1",
7
7
  "description": "Source workspace for repoctl and Icebreaker's shared development packages",
8
8
  "author": "ice breaker <hi@sonofmagic.top>",
9
9
  "license": "MIT",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@icebreakers/monorepo-templates",
3
3
  "type": "module",
4
- "version": "2.0.5",
4
+ "version": "2.0.7",
5
5
  "description": "Built-in project templates and managed workspace assets for repoctl",
6
6
  "author": "ice breaker <hi@sonofmagic.top>",
7
7
  "license": "MIT",
File without changes
@@ -39,7 +39,48 @@ Two files remain in the workspace root:
39
39
 
40
40
  The managed Release workflow uploads both files as `npm-publish-progress-<run_id>-<run_attempt>` on success or failure, retained for 14 days. Missing reports are ignored. After upgrading repoctl, run `repo upgrade` to refresh managed workflows; custom workflows can add the same upload step.
41
41
 
42
- After a failure, download the artifact and reconcile exact versions with `npm view <name>@<version> version`. Continue read-only checks for accepted but unconfirmed versions instead of rerunning the entire release lifecycle. Use the workflow's `reconcile` mode to repair metadata for visible versions, and `publish-unpublished` only for versions verified as still requiring upload. Reports are diagnostic: a new invocation does not trust old reports or automatically resume across processes.
42
+ ## Recovery across runners
43
+
44
+ `repo release ci --mode=publish` tracks release targets separately from new npm uploads. Before uploading, the built-in GitHub client writes exact versions, original commits, accepted-upload evidence, metadata progress, and individual hook states to the repository's `repoctl-release-state` branch. The key includes repository, dist-tag, and candidate versions. Writes compare the file SHA to reject concurrent changes. Keep this branch, grant `contents: write`, and serialize all workflows that publish the same packages.
45
+
46
+ `repoctl-release-progress.json` is an archived diagnostic copy. Its `complete: true` requires npm version/dist-tag visibility, tags pointing to the original commits, published GitHub Releases, and all required hooks. The older npm progress file only describes the npm stage.
47
+
48
+ Reruns query the registry and GitHub and finish missing stages without reuploading accepted versions or repeating completed hooks. Prereleases push the version commit before uploading. Source discovery requires complete Git history (`fetch-depth: 0`), and recovery checks the original manifest and changelog. If a later commit changed the changelog, check out the reported original commit before recovery.
49
+
50
+ Legacy releases without a checkpoint use npm `gitHead`; if absent, verify the source manually and set `REPO_RELEASE_SOURCE_SHA`. Never substitute the rerun HEAD. Historical targets with existing Releases remain no-ops. Hooks for legacy targets with missing metadata have unknown outcomes.
51
+
52
+ ```bash
53
+ repo release ci --mode=publish --dry-run
54
+ repo release ci --mode=publish
55
+ ```
56
+
57
+ Dry-run queries remote state and shows versions, original commits, npm stage, missing tags/Releases, and hook states without uploads, hooks, or checkpoint writes. Unknown registry states fail after bounded retries. Tag conflicts and unknown source commits fail without moving tags. GitHub requests have a 30-second timeout and bounded backoff.
58
+
59
+ ### Hook outcomes
60
+
61
+ Hook script names must be unique; retain the original script set when recovering. Each hook is checkpointed as `running` before execution and `complete` after success. Optional failures become `ignored`. Unknown non-idempotent outcomes require manual review. Set `idempotent: true` on an `afterPublish` hook only when repeated execution is safe. After verifying external completion, `REPO_RELEASE_ACKNOWLEDGE_HOOKS=script-name` acknowledges it without execution (comma-separated for multiple scripts).
62
+
63
+ If a runner disappears during upload before responses are persisted, recovery performs read-only visibility confirmation for up to five minutes. It fails with evidence if versions remain unknown, rather than blindly uploading again. After manually verifying that a version was never uploaded, use the existing exact `publish-unpublished` entry, then rerun the original target set to finish its hooks. Arbitrary external hooks cannot be guaranteed exactly-once.
64
+
65
+ Legacy injected `GitHubOperations` adapters retain their previous behavior. Recovery-capable adapters must implement `readReleaseState`, `writeReleaseState`, `listReleases`, and `ensureTag`; `readTagTarget` is recommended. Enforce revision comparison on writes and throw on query errors. A local summary is not a remote checkpoint.
66
+
67
+ ## No-release intents and original-source recovery
68
+
69
+ An intent containing only `none` (or empty frontmatter) records that no release is needed. It does not open a version PR or block publishing an already prepared release. Consumed intents resurrected by a merge are not versioned twice. pnpm cleans these files during the next effective version operation.
70
+
71
+ Release PRs use the applied package list returned by pnpm, not arbitrary Git changes. A new package can keep its initial version; it still appears in the release notes. Cleanup alone never opens a release PR.
72
+
73
+ If an existing prepared version has not completed publication, new version preparation stops before consuming intents and prints its source commit and recovery command. Finish that release first, then run preparation again:
74
+
75
+ ```bash
76
+ repo release ci --mode publish --source-sha <full-main-commit-sha> --dry-run
77
+ repo release ci --mode publish --source-sha <full-main-commit-sha>
78
+ repo release ci --mode prepare
79
+ ```
80
+
81
+ The managed Release workflow exposes the same `source-sha` input for `publish` and `publish-unpublished`. Current tooling checks out the original commit into an isolated directory, installs its locked dependencies, builds and verifies that source, and recovers the full set of versions introduced by its manifests or ledger, including dependency propagation. Package/version inputs validate membership; they do not split the original release. The SHA must belong to `origin/main`. Dry-run only inspects the source and remote release state; it does not install, upload, run hooks, or write checkpoints. Later changes stay pending for a new version. The original source must already include all intended version changes; no versions are changed during recovery.
82
+
83
+ Recovery preserves GitHub's workflow environment for trusted publishing and provenance: its signed identity refers to the workflow run's commit. The isolated checkout, release checkpoint, Git tags, and Release targets refer to `source-sha`. Do not overwrite `GITHUB_SHA` to recover an older source; npm rejects provenance that disagrees with the signed workflow identity.
43
84
 
44
85
  ## Next
45
86
 
@@ -33,7 +33,7 @@ CI 将版本号、各包 `CHANGELOG.md` 和 `.changeset/ledger.yaml` 提交到 R
33
33
  pnpm publish -r --report-summary --provenance --no-git-checks
34
34
  ```
35
35
 
36
- pnpm 根据 registry 中已有的版本自动跳过已发布包。CI 读取 `pnpm-publish-summary.json` 创建 `package@version` tag 和 GitHub Release,发布器在本次调用内保留已接收上传的版本,确认 registry 可见性后再执行后置流程;失败后的处理见[部分发布与 registry 延迟](/zh/tasks/release#部分发布与-registry-延迟)。
36
+ pnpm 会跳过 registry 已有版本;CI 根据精确目标版本和远端生命周期检查点恢复 Git tag、GitHub Release 与后置 hook,不再只依赖本轮上传 summary。查询未知、标签冲突或非幂等 hook 结果未知时明确失败;详见[发布任务](/zh/tasks/release)。
37
37
 
38
38
  ## Workspace versioning 配置
39
39
 
@@ -38,7 +38,7 @@ pnpm version -r
38
38
  pnpm publish -r --report-summary --provenance --no-git-checks
39
39
  ```
40
40
 
41
- pnpm 会跳过 registry 中已经存在的版本,并把新发布包写入 `pnpm-publish-summary.json`。CI 根据 summary 创建 `package@version` Git tag 和 GitHub Release,发布器会保留本次调用的部分成功状态,等待 registry 确认可见后再创建元数据;不要在传播延迟期间直接重跑整个生命周期,详见[发布任务](/zh/tasks/release)。
41
+ pnpm 会跳过 registry 已有版本;CI 根据精确目标版本和远端生命周期检查点恢复 Git tag、GitHub Release 与后置 hook,不再只依赖本轮上传 summary。查询未知、标签冲突或非幂等 hook 结果未知时明确失败;详见[发布任务](/zh/tasks/release)。
42
42
 
43
43
  本地推荐使用 repoctl 包装命令:
44
44
 
@@ -39,7 +39,54 @@ repo release --dry-run
39
39
 
40
40
  受管 Release 工作流会在发布成功或失败后上传 `npm-publish-progress-<run_id>-<run_attempt>` artifact,保留 14 天;没有清单时跳过上传。现有项目升级 repoctl 后运行 `repo upgrade` 更新受管工作流;自定义工作流可自行添加相同上传步骤。
41
41
 
42
- 失败后先下载 artifact,并用 `npm view <name>@<version> version` 对账。对于已接收但未确认的版本,继续只读确认,不要直接重跑整个发布生命周期。确认已经可用的版本可通过工作流的 `reconcile` 模式补齐元数据;仅对核实仍未上传的版本使用 `publish-unpublished`。旧清单仅用于诊断,新调用不会自动信任旧清单或跨进程续传。
42
+ ## 跨 runner 恢复与完成判定
43
+
44
+ `repo release ci --mode=publish` 不再把本轮 npm 上传列表当作发布目标。内置 GitHub 客户端在首次上传前,将精确包版本、原提交、npm 接收证据、元数据和逐个 hook 状态写入同仓库的 `repoctl-release-state` 分支。记录键包含仓库、dist-tag 和候选版本集合,写入采用文件 SHA 比较并交换。分支需要 `contents: write` 权限,并应保留;不要删除或手动修改检查点。受管工作流仍须保持发布串行,其他自定义工作流也应避免重叠发布。
45
+
46
+ 根目录的 `repoctl-release-progress.json` 是该记录的诊断副本,会与 npm 进度一起归档。只有 npm 精确版本和 dist-tag、指向原提交的标签、已发布的 GitHub Release、所有必要 hook 都完成后,生命周期记录才有 `complete: true`。`repoctl-publish-progress.json` 的 `complete` 仅表示 npm 阶段。
47
+
48
+ 重跑会读取远端检查点,核对 registry 和 GitHub,只补齐缺失阶段,不重新上传已接收的版本,也不重复已完成的 hook。预发布在上传前先推送版本提交,确保新 runner 能检出原版本。新发布从完整 Git 历史确定版本来源(checkout 必须 `fetch-depth: 0`);恢复时还会核对原提交的 manifest 和 changelog。若后续提交修改了 changelog,请检出提示的原提交后恢复。
49
+
50
+ 旧版发布没有检查点时,可从 npm 的 `gitHead` 恢复原提交。缺失该字段时必须人工核对来源后显式设置 `REPO_RELEASE_SOURCE_SHA`,不能使用重跑 HEAD 猜测。所有目标已有 Release 的历史任务保持 no-op,不倒推重放历史 hook。无记录且缺失元数据的历史任务中,hook 结果按未知处理。
51
+
52
+ ```bash
53
+ repo release ci --mode=publish --dry-run
54
+ repo release ci --mode=publish
55
+ ```
56
+
57
+ 预演会查询远端并展示目标版本、原提交、npm 阶段、缺失标签/Release 和 hook 状态,不执行上传、hook 或检查点写入。查询超时、TLS 错误、鉴权失败、限流和服务端错误不当成版本不存在;原提交未知或标签冲突明确失败,绝不强制移动标签。GitHub 请求有 30 秒超时和有界退避。
58
+
59
+ ### Hook 恢复策略
60
+
61
+ `afterPublish` 脚本名必须唯一,重跑时须保留原脚本集合。每个脚本执行前写入 `running`,成功后写入 `complete`;允许忽略的失败记为 `ignored`。未知结果的非幂等脚本不会自动重试。只有重复执行不会增加副作用时,才声明:
62
+
63
+ ```ts
64
+ const hook = { script: 'publish:extension', idempotent: true }
65
+ ```
66
+
67
+ 如果外部系统已确认脚本成功,可显式设置 `REPO_RELEASE_ACKNOWLEDGE_HOOKS=publish:extension` 后恢复;多个脚本用逗号分隔。该操作表示人工确认完成,不会再次执行脚本。确认失败或未知时,不应使用此开关。
68
+
69
+ 如果 runner 在上传期间消失,检查点可能只有 `running`,而响应尚未持久化。恢复会先进行最多 5 分钟的只读可见性确认;仍不能确认时失败,保留证据,不盲目重传。真正未上传的版本经人工核实后,可用已有 `publish-unpublished` 精确恢复入口,再重跑原发布目标完成其 hook。对任意外部 hook 不承诺 exactly-once。
70
+
71
+ 程序化注入的旧 `GitHubOperations` adapter 保留原行为;要启用跨 runner 恢复,需要实现 `readReleaseState`、`writeReleaseState`、`listReleases`、`ensureTag`,并建议提供 `readTagTarget`。写入必须校验 revision,查询错误必须抛出。仅有本地 summary 不能代替远端检查点。
72
+
73
+ ## 无需发布的记录与原提交恢复
74
+
75
+ 仅包含 `none` 或空 frontmatter 的 intent 表示无需发布。它不会创建版本 PR,也不阻断已经准备好的版本发布。合并后重新出现、但 ledger 已记录消费的 intent 不会再次升级版本;pnpm 会在下一次有效版本操作中清理这些文件。
76
+
77
+ 版本 PR 以 pnpm 返回的实际发布包列表为依据,不再把任意 Git 改动视为版本变化。新包首次发布可以保留初始版本号,但仍会列入发布说明。仅清理记录不会创建发布 PR。
78
+
79
+ 已有版本尚未完成发布时,新的版本准备会在消费 intent 前失败,并给出原始提交和恢复命令。先恢复旧发布,再准备新版本:
80
+
81
+ ```bash
82
+ repo release ci --mode publish --source-sha <完整的-main-提交-SHA> --dry-run
83
+ repo release ci --mode publish --source-sha <完整的-main-提交-SHA>
84
+ repo release ci --mode prepare
85
+ ```
86
+
87
+ 受管 Release 工作流为 `publish` 和 `publish-unpublished` 提供相同的 `source-sha` 输入。当前工具会在独立目录检出原提交,按照其锁文件安装、构建和验证,恢复该提交 manifest 或 ledger 新增的整批版本,包括依赖传播升级的包。package/version 输入只校验是否属于该批发布,不拆分原发布批次。SHA 必须属于 `origin/main` 历史。dry-run 只检查源码与远端状态,不安装、不上传、不运行 hook、不写检查点。后续变更保留到下一版本;恢复过程中不修改版本号。
88
+
89
+ 恢复保留 GitHub 工作流环境,供可信发布和 provenance 使用:签名身份对应运行工作流的提交;独立检出的源码、发布检查点、Git tag 和 Release 目标则对应 `source-sha`。不要通过覆盖 `GITHUB_SHA` 恢复旧源码,npm 会拒绝与工作流签名身份不一致的 provenance。
43
90
 
44
91
  ## 下一步
45
92