From a6fd2c0bebe151bf3a443d812b52b16e6cd42986 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 25 Jul 2026 05:35:48 +0000 Subject: [PATCH 1/4] fix(release): prefer HEAD~1 tags; trust empty release-tags state LSP: stop CI auto --from-existing (fetch-depth:0 should version-diff); empty .sfmc-release-tags.json must not fall back to scanning all tags. DRY: resolveReleaseTagEntries shared by push / gh-release. Co-authored-by: Shiroha --- .changeset/pre.json | 8 +------ .github/workflows/changeset-release.yml | 4 ++-- docs/dev/npm-publish.md | 7 +++++- tools/CHANGELOG.md | 30 ++++++++++++++---------- tools/changeset-github-release.mjs | 31 ++++++++++++++----------- tools/changeset-push.mjs | 21 +++++++++-------- tools/changeset-release.test.mjs | 25 ++++++++++++++++++++ tools/changeset-tag.mjs | 13 ++++++----- tools/lib/changeset-release.mjs | 13 +++++++++++ tools/package.json | 2 +- 10 files changed, 101 insertions(+), 53 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index c7a833b..8d2fdb7 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -13,12 +13,6 @@ "@sfmc-bds/tools": "0.1.1" }, "changesets": [ - "bds-tools-0-2-beta", - "cli-0-2-beta", - "db-server-0-2-beta", - "qq-bridge-0-1-1-beta", - "sdk-0-2-beta", - "sfmc-meta-0-2-beta", - "tools-0-2-beta" + "fix-release-tag-shallow" ] } diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml index c81f37b..9d68990 100644 --- a/.github/workflows/changeset-release.yml +++ b/.github/workflows/changeset-release.yml @@ -23,7 +23,7 @@ jobs: pull-requests: write id-token: write steps: - # fetch-depth:0:tag-packages 需 HEAD~1 做版本 diff;浅克隆会误触发全量 tag 回退路径 + # fetch-depth:0:tag-packages 需 HEAD~1 做版本 diff;浅克隆时 resolvePackagesNeedingTags 才回退 from-existing - uses: actions/checkout@v5 with: fetch-depth: 0 @@ -53,7 +53,7 @@ jobs: with: version: npm run version-packages # CI 不跑交互 changeset/version;只 publish + tag + gh release - # tag-packages 在 CI=true 时默认 --from-existing(publish 已建 tag,避免浅克隆误打全量) + # tag-packages 默认 HEAD~1 版本 diff(空状态文件亦信任,禁止扫全仓 tag) publish: npm run ci-release-packages title: "chore(release): version packages" commit: "chore(release): version packages" diff --git a/docs/dev/npm-publish.md b/docs/dev/npm-publish.md index 9222b8d..ab7755f 100644 --- a/docs/dev/npm-publish.md +++ b/docs/dev/npm-publish.md @@ -39,6 +39,11 @@ 2. PR 合入 `main` 后,[changeset-release.yml](../../.github/workflows/changeset-release.yml) 会开/更新 **Version Packages** PR。 3. 维护者审查并合并 Version PR → CI 跑 `ci-release-packages`(publish + tag + GitHub Release;pre mode → npm **`beta`**)。 +> **仓库设置(必开)**:Settings → Actions → General → Workflow permissions 勾选 +> **Allow GitHub Actions to create and approve pull requests**。 +> 未勾选时 `changesets/action` 能 push `changeset-release/main`,但创建 Version PR 会报 +> `GitHub Actions is not permitted to create or approve pull requests`(workflow 已具备 `pull-requests: write` 仍不够)。 + ### 本地一键发版(`npm-run-all2`) 当前 pre mode 请用: @@ -53,7 +58,7 @@ npm run prerelease-packages |------|--------| | `prerelease-packages` | **现在**(pre/beta) | | `release-packages` | 仅 `changeset pre exit` 之后(latest) | -| `ci-release-packages` | CI 专用(无交互)。`CI=true` 时 `tag-packages` 默认 `--from-existing`:只收录 `changeset publish` 已创建的 tag,避免浅克隆误为未发版包打 tag / 建 GH Release。 | +| `ci-release-packages` | CI 专用(无交互)。`tag-packages` 默认按 `HEAD~1` 版本 diff;仅显式 `--from-existing` / `SFMC_TAG_FROM_EXISTING=1`(或浅克隆无法解析父提交)才只收录已有 tag。空的 `.sfmc-release-tags.json` 表示本轮无目标,下游不得回退扫全仓。 | | `publish-packages` | 仅 npm publish 包装 | 需要:本机已登录 `gh`、npm(或 `NPM_TOKEN`),且对 `origin` 有推送权限。 diff --git a/tools/CHANGELOG.md b/tools/CHANGELOG.md index 2f00c81..c4c1a53 100644 --- a/tools/CHANGELOG.md +++ b/tools/CHANGELOG.md @@ -1,12 +1,18 @@ -# @sfmc-bds/tools - -## 0.2.0-beta.0 - -### Minor Changes - -- tsc7 双轨入口;sdk-lint / manifest schema / 模块脚手架;zipx DRY;pack:verify 从 NPM_PUBLISH_PACKAGES 派生;ootb 断言对齐。 - -### Patch Changes - -- Updated dependencies - - @sfmc-bds/bds-tools@0.2.0-beta.0 +# @sfmc-bds/tools + +## 0.2.0-beta.1 + +### Patch Changes + +- 44ca909: 修复发版编排:浅克隆不再误打全量 tag;CHANGELOG 摘录正则;release-tags 状态 DRY + +## 0.2.0-beta.0 + +### Minor Changes + +- tsc7 双轨入口;sdk-lint / manifest schema / 模块脚手架;zipx DRY;pack:verify 从 NPM_PUBLISH_PACKAGES 派生;ootb 断言对齐。 + +### Patch Changes + +- Updated dependencies + - @sfmc-bds/bds-tools@0.2.0-beta.0 diff --git a/tools/changeset-github-release.mjs b/tools/changeset-github-release.mjs index b604f9f..a372f62 100644 --- a/tools/changeset-github-release.mjs +++ b/tools/changeset-github-release.mjs @@ -17,6 +17,7 @@ import { packageDirFor, packageTagName, readReleaseTagsState, + resolveReleaseTagEntries, run, } from "./lib/changeset-release.mjs"; @@ -25,21 +26,23 @@ const forceLatest = process.argv.includes("--latest"); function loadTargets() { const state = readReleaseTagsState(); - if (state && state.tags.length > 0) { - return state.tags.map((t) => ({ - name: t.name, - version: t.version, - tag: t.tag, - })); - } - const out = []; - for (const p of listPublishablePackages()) { - const tag = packageTagName(p.name, p.version); - if (gitCapture(["tag", "-l", tag])) { - out.push({ name: p.name, version: p.version, tag }); + const entries = resolveReleaseTagEntries(state, () => { + /* 仅状态文件缺失时回退:当前版本对应 tag 已在本地的可发包 */ + console.warn("[changeset] 无 .sfmc-release-tags.json,回退扫描本地 name@version tag"); + const out = []; + for (const p of listPublishablePackages()) { + const tag = packageTagName(p.name, p.version); + if (gitCapture(["tag", "-l", tag])) { + out.push({ name: p.name, version: p.version, tag }); + } } - } - return out; + return out; + }); + return entries.map((t) => ({ + name: t.name, + version: t.version, + tag: t.tag, + })); } function isPrereleaseVersion(version) { diff --git a/tools/changeset-push.mjs b/tools/changeset-push.mjs index 5e56b60..2151b9b 100644 --- a/tools/changeset-push.mjs +++ b/tools/changeset-push.mjs @@ -7,6 +7,7 @@ import { git, gitCapture, readReleaseTagsState, + resolveReleaseTagEntries, } from "./lib/changeset-release.mjs"; const tagsOnly = @@ -26,23 +27,23 @@ if (!tagsOnly) { console.log("[changeset] CI/tags-only:跳过分支推送"); } -/** @type {string[]} */ -let tags = []; const state = readReleaseTagsState(); -if (state && state.tags.length > 0) { - tags = state.tags.map((t) => t.tag).filter(Boolean); -} - -if (tags.length === 0) { - /* 回退:推送本机尚未在 origin 的 name@version 风格 tag */ +const entries = resolveReleaseTagEntries(state, () => { + /* 回退:仅当状态文件缺失时,推送本机尚未在 origin 的 name@version 风格 tag */ + console.warn("[changeset] 无 .sfmc-release-tags.json,回退扫描本地未推送 tag"); + /** @type {{ tag: string }[]} */ + const out = []; const local = gitCapture(["tag", "-l", "@sfmc-bds/*"]) .split(/\r?\n/) .filter(Boolean); for (const tag of local) { const remote = gitCapture(["ls-remote", "--tags", "origin", `refs/tags/${tag}`]); - if (!remote) tags.push(tag); + if (!remote) out.push({ tag }); } -} + return out; +}); + +const tags = entries.map((t) => t.tag).filter(Boolean); if (tags.length === 0) { console.log("[changeset] 无待推送 tag,跳过"); diff --git a/tools/changeset-release.test.mjs b/tools/changeset-release.test.mjs index bafedd0..a209650 100644 --- a/tools/changeset-release.test.mjs +++ b/tools/changeset-release.test.mjs @@ -6,6 +6,7 @@ import { describe, it } from "node:test"; import { packageTagName, extractChangelogNotes, + resolveReleaseTagEntries, RELEASE_TAGS_STATE, PRE_JSON, ROOT, @@ -46,3 +47,27 @@ describe("release paths (DRY)", () => { assert.equal(path.basename(RELEASE_TAGS_STATE), ".sfmc-release-tags.json"); }); }); + +describe("resolveReleaseTagEntries (LSP)", () => { + it("trusts empty tags array — does not call fallback", () => { + let called = false; + const out = resolveReleaseTagEntries({ tags: [], createdAt: "t" }, () => { + called = true; + return [{ tag: "should-not-appear" }]; + }); + assert.deepEqual(out, []); + assert.equal(called, false); + }); + + it("uses fallback only when state is missing", () => { + const fb = [{ tag: "@sfmc-bds/tools@0.2.0-beta.1" }]; + const out = resolveReleaseTagEntries(null, () => fb); + assert.equal(out, fb); + }); + + it("returns state.tags when present", () => { + const tags = [{ name: "@sfmc-bds/tools", version: "0.2.0-beta.1", tag: "@sfmc-bds/tools@0.2.0-beta.1" }]; + const out = resolveReleaseTagEntries({ tags, createdAt: "t" }, () => []); + assert.equal(out, tags); + }); +}); diff --git a/tools/changeset-tag.mjs b/tools/changeset-tag.mjs index 9360dfd..3d3d40f 100644 --- a/tools/changeset-tag.mjs +++ b/tools/changeset-tag.mjs @@ -3,10 +3,12 @@ * 为当前可发包创建 git tag(与 changeset publish 同格式: name@version)。 * 已存在的 tag 跳过。写入 .sfmc-release-tags.json 供后续 push / gh release 使用。 * - * node tools/changeset-tag.mjs # 按 HEAD~1 版本 diff 打 tag - * node tools/changeset-tag.mjs --from-existing # 仅收录本地已有 name@version(CI publish 之后) + * node tools/changeset-tag.mjs # 按 HEAD~1 版本 diff 打 tag + * node tools/changeset-tag.mjs --from-existing # 仅收录本地已有 name@version + * SFMC_TAG_FROM_EXISTING=1 # 同上 * - * CI=true 且未传 --create 时默认 --from-existing(changeset publish 已建 tag,避免浅克隆误打全量)。 + * HEAD~1 不可用时由 resolvePackagesNeedingTags 安全回退到 from-existing(勿因 CI=true 强制)。 + * CI 已 fetch-depth:0 时应走版本 diff,避免误收录仓内历史全量 name@version。 */ import path from "node:path"; import { @@ -19,9 +21,7 @@ import { } from "./lib/changeset-release.mjs"; const fromExisting = - process.argv.includes("--from-existing") || - process.env.SFMC_TAG_FROM_EXISTING === "1" || - (process.env.CI === "true" && !process.argv.includes("--create")); + process.argv.includes("--from-existing") || process.env.SFMC_TAG_FROM_EXISTING === "1"; const needed = resolvePackagesNeedingTags({ fromExisting }); if (needed.length === 0) { @@ -30,6 +30,7 @@ if (needed.length === 0) { ? "[changeset] 无已存在的 name@version tag 可收录,跳过" : "[changeset] 无包版本变化,跳过打 tag" ); + /* 空数组仍写入:下游须信任「本轮无 tag」,禁止回退扫全仓 */ writeReleaseTagsState([]); process.exit(0); } diff --git a/tools/lib/changeset-release.mjs b/tools/lib/changeset-release.mjs index 65899a4..0cb5cfb 100644 --- a/tools/lib/changeset-release.mjs +++ b/tools/lib/changeset-release.mjs @@ -75,6 +75,19 @@ export function readReleaseTagsState() { } } +/** + * LSP:状态文件存在时一律信任(含 `tags: []` = 本轮无目标); + * 仅文件缺失 / 无法解析时调用 fallback(禁止把空数组当成「无状态」再扫全仓 tag)。 + * @template T + * @param {ReleaseTagsState | null} state + * @param {() => T[]} fallback + * @returns {T[] | ReleaseTagEntry[]} + */ +export function resolveReleaseTagEntries(state, fallback) { + if (state) return state.tags; + return fallback(); +} + /** @param {ReleaseTagEntry[]} tags */ export function writeReleaseTagsState(tags) { const state = { diff --git a/tools/package.json b/tools/package.json index 668b8a4..38f9582 100644 --- a/tools/package.json +++ b/tools/package.json @@ -1,6 +1,6 @@ { "name": "@sfmc-bds/tools", - "version": "0.2.0-beta.0", + "version": "0.2.0-beta.1", "description": "SFMC dev tools - testing before build", "type": "module", "license": "AGPL-3.0-only", From 4609b2c3804923bbcd379b0d9dcb7b7c4b8c83f5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 25 Jul 2026 05:35:55 +0000 Subject: [PATCH 2/4] chore(release): consume tools beta.1 changeset; DIP remote-controller ROOT Delete applied fix-release-tag-shallow.md; document empty-state/HEAD~1 in CHANGELOG. Extract remote-controller project-root.ts (align db/qq DIP). Co-authored-by: Shiroha --- .changeset/fix-release-tag-shallow.md | 5 ---- remote-controller/src/log.ts | 9 +++---- remote-controller/src/project-root.ts | 12 +++++++++ tools/CHANGELOG.md | 37 ++++++++++++++------------- 4 files changed, 34 insertions(+), 29 deletions(-) delete mode 100644 .changeset/fix-release-tag-shallow.md create mode 100644 remote-controller/src/project-root.ts diff --git a/.changeset/fix-release-tag-shallow.md b/.changeset/fix-release-tag-shallow.md deleted file mode 100644 index 5dafead..0000000 --- a/.changeset/fix-release-tag-shallow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@sfmc-bds/tools": patch ---- - -修复发版编排:浅克隆不再误打全量 tag;CHANGELOG 摘录正则;release-tags 状态 DRY diff --git a/remote-controller/src/log.ts b/remote-controller/src/log.ts index cdc9463..ad093a4 100644 --- a/remote-controller/src/log.ts +++ b/remote-controller/src/log.ts @@ -4,15 +4,12 @@ * stdout bare + 落盘 `/.sfmc/logs/remote-controller.log`。 */ import { createNodeServiceLogger } from "@sfmc-bds/sdk/logs"; -import { logFile, resolveRuntimeRoot } from "@sfmc-bds/sdk/node/config"; -import { dirname, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -const ROOT = resolveRuntimeRoot(resolve(dirname(fileURLToPath(import.meta.url)), "..", "..")); +import { logFile } from "@sfmc-bds/sdk/node/config"; +import { PROJECT_ROOT } from "./project-root.js"; export const log = createNodeServiceLogger({ source: "remote-controller", - logPath: logFile(ROOT, "remote-controller"), + logPath: logFile(PROJECT_ROOT, "remote-controller"), }); process.on("exit", () => log.close()); diff --git a/remote-controller/src/project-root.ts b/remote-controller/src/project-root.ts new file mode 100644 index 0000000..6f0e45f --- /dev/null +++ b/remote-controller/src/project-root.ts @@ -0,0 +1,12 @@ +/** + * project-root.ts — 仓根唯一解析点(DRY/DIP:log 勿各自上溯) + */ + +import { resolveRuntimeRoot } from "@sfmc-bds/sdk/node/config"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const HERE = dirname(fileURLToPath(import.meta.url)); + +/** SFMC_ROOT > 相对 remote-controller/src 上溯两级 */ +export const PROJECT_ROOT: string = resolveRuntimeRoot(resolve(HERE, "..", "..")); diff --git a/tools/CHANGELOG.md b/tools/CHANGELOG.md index c4c1a53..d2a0988 100644 --- a/tools/CHANGELOG.md +++ b/tools/CHANGELOG.md @@ -1,18 +1,19 @@ -# @sfmc-bds/tools - -## 0.2.0-beta.1 - -### Patch Changes - -- 44ca909: 修复发版编排:浅克隆不再误打全量 tag;CHANGELOG 摘录正则;release-tags 状态 DRY - -## 0.2.0-beta.0 - -### Minor Changes - -- tsc7 双轨入口;sdk-lint / manifest schema / 模块脚手架;zipx DRY;pack:verify 从 NPM_PUBLISH_PACKAGES 派生;ootb 断言对齐。 - -### Patch Changes - -- Updated dependencies - - @sfmc-bds/bds-tools@0.2.0-beta.0 +# @sfmc-bds/tools + +## 0.2.0-beta.1 + +### Patch Changes + +- 44ca909: 修复发版编排:浅克隆不再误打全量 tag;CHANGELOG 摘录正则;release-tags 状态 DRY +- tag-packages 默认 HEAD~1 版本 diff(不再因 CI=true 强制 from-existing);空 `.sfmc-release-tags.json` 下游一律信任,禁止回退扫全仓 tag + +## 0.2.0-beta.0 + +### Minor Changes + +- tsc7 双轨入口;sdk-lint / manifest schema / 模块脚手架;zipx DRY;pack:verify 从 NPM_PUBLISH_PACKAGES 派生;ootb 断言对齐。 + +### Patch Changes + +- Updated dependencies + - @sfmc-bds/bds-tools@0.2.0-beta.0 From 077f5386b3463422b83cf7c8f9f7507cf1c82869 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 25 Jul 2026 05:37:01 +0000 Subject: [PATCH 3/4] fix(ci): CHANGESETS_GITHUB_TOKEN fallback + pending changeset LSP Wire optional PAT for Version PR when Actions cannot create PRs. Exclude pre.json consumed ids from listPendingChangesetFiles (pre mode). Co-authored-by: Shiroha --- .github/workflows/changeset-release.yml | 6 +++++- docs/dev/npm-publish.md | 17 +++++++++++++---- tools/changeset-release.test.mjs | 14 ++++++++++++++ tools/lib/changeset-release.mjs | 11 ++++++++++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml index 9d68990..69b4031 100644 --- a/.github/workflows/changeset-release.yml +++ b/.github/workflows/changeset-release.yml @@ -47,6 +47,10 @@ jobs: npm run build --workspace @sfmc-bds/tools --if-present npm run build --workspace @sfmc-bds/sfmc --if-present + # Version PR 需要「创建 PR」权限。仅用 GITHUB_TOKEN 且仓库关闭 + # Settings→Actions→General→「Allow GitHub Actions to create and approve pull requests」时, + # changesets/action 会 HttpError(分支已推送但 PR 未创建)。 + # 优先 PAT Secret CHANGESETS_GITHUB_TOKEN;未配置则回退 GITHUB_TOKEN(需上述勾选)。 - name: Create Release Pull Request or Publish id: changesets uses: changesets/action@v1 @@ -59,6 +63,6 @@ jobs: commit: "chore(release): version packages" createGithubReleases: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.CHANGESETS_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/docs/dev/npm-publish.md b/docs/dev/npm-publish.md index ab7755f..7b71956 100644 --- a/docs/dev/npm-publish.md +++ b/docs/dev/npm-publish.md @@ -39,10 +39,18 @@ 2. PR 合入 `main` 后,[changeset-release.yml](../../.github/workflows/changeset-release.yml) 会开/更新 **Version Packages** PR。 3. 维护者审查并合并 Version PR → CI 跑 `ci-release-packages`(publish + tag + GitHub Release;pre mode → npm **`beta`**)。 -> **仓库设置(必开)**:Settings → Actions → General → Workflow permissions 勾选 -> **Allow GitHub Actions to create and approve pull requests**。 -> 未勾选时 `changesets/action` 能 push `changeset-release/main`,但创建 Version PR 会报 -> `GitHub Actions is not permitted to create or approve pull requests`(workflow 已具备 `pull-requests: write` 仍不够)。 +### Version PR 权限(必读) + +`changesets/action` 用 `GITHUB_TOKEN` 开 PR 时,若仓库/组织关闭了 **Allow GitHub Actions to create and approve pull requests**,会报: + +`HttpError: GitHub Actions is not permitted to create or approve pull requests` + +(版本 bump 分支 `changeset-release/main` 可能已推送,但 PR 未创建。workflow 已声明 `pull-requests: write` 仍不够。) + +任选其一: + +1. **推荐(零 Secret)**:Repo Settings → Actions → General → Workflow permissions → 勾选 *Allow GitHub Actions to create and approve pull requests*。 +2. **PAT**:写入 Secret **`CHANGESETS_GITHUB_TOKEN`**(能开本仓 PR);workflow 优先用该 token,未配置时回退 `GITHUB_TOKEN`。 ### 本地一键发版(`npm-run-all2`) @@ -100,6 +108,7 @@ npm run pack:verify 1. npm 账号登录并确认 org [sfmc-bds](https://www.npmjs.com/org/sfmc-bds) 2. Granular Access Token(Automation)写入 GitHub Secret `NPM_TOKEN` +3. (可选)若无法开启 Actions「create and approve pull requests」:写入 `CHANGESETS_GITHUB_TOKEN`(见上文 Version PR 权限) ## 模块包 diff --git a/tools/changeset-release.test.mjs b/tools/changeset-release.test.mjs index a209650..2afb95d 100644 --- a/tools/changeset-release.test.mjs +++ b/tools/changeset-release.test.mjs @@ -6,6 +6,7 @@ import { describe, it } from "node:test"; import { packageTagName, extractChangelogNotes, + listPendingChangesetFiles, resolveReleaseTagEntries, RELEASE_TAGS_STATE, PRE_JSON, @@ -71,3 +72,16 @@ describe("resolveReleaseTagEntries (LSP)", () => { assert.equal(out, tags); }); }); + +describe("listPendingChangesetFiles (pre mode LSP)", () => { + it("excludes ids already recorded in pre.json#changesets", () => { + const pre = JSON.parse(fs.readFileSync(PRE_JSON, "utf8")); + assert.equal(pre.mode, "pre"); + assert.ok(Array.isArray(pre.changesets)); + const pending = listPendingChangesetFiles(); + const pendingIds = pending.map((p) => path.basename(p, ".md")); + for (const id of pre.changesets) { + assert.ok(!pendingIds.includes(id), `consumed ${id} must not be pending`); + } + }); +}); diff --git a/tools/lib/changeset-release.mjs b/tools/lib/changeset-release.mjs index 0cb5cfb..bbe9ea6 100644 --- a/tools/lib/changeset-release.mjs +++ b/tools/lib/changeset-release.mjs @@ -25,12 +25,21 @@ export function isPreMode() { return Boolean(pre && pre.mode === "pre"); } -/** 待消费的 changeset 文件(不含 README / config / pre) */ +/** + * 待消费的 changeset 文件(不含 README / config / pre)。 + * pre mode 下 `.md` 会留在磁盘直到 `pre exit`;须排除已写入 `pre.json#changesets` 的 id + *(与 @changesets getRelevantChangesets 一致,LSP)。 + */ export function listPendingChangesetFiles() { if (!fs.existsSync(CHANGESET_DIR)) return []; + const pre = readPreState(); + const consumed = new Set( + pre && pre.mode === "pre" && Array.isArray(pre.changesets) ? pre.changesets : [] + ); return fs .readdirSync(CHANGESET_DIR) .filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md") + .filter((f) => !consumed.has(f.replace(/\.md$/i, ""))) .map((f) => path.join(CHANGESET_DIR, f)); } From 27d4b7d05f99987b2bed247935438ea48e88b953 Mon Sep 17 00:00:00 2001 From: Shiroha <65802880+Tanya7z@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:48:45 +0800 Subject: [PATCH 4/4] Update GITHUB_TOKEN secret in release workflow --- .github/workflows/changeset-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/changeset-release.yml b/.github/workflows/changeset-release.yml index 69b4031..f166396 100644 --- a/.github/workflows/changeset-release.yml +++ b/.github/workflows/changeset-release.yml @@ -63,6 +63,6 @@ jobs: commit: "chore(release): version packages" createGithubReleases: false env: - GITHUB_TOKEN: ${{ secrets.CHANGESETS_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.SFMC_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }}