diff --git a/docs/releases/v1.5.0.md b/docs/releases/v1.5.0.md new file mode 100644 index 0000000..3def5da --- /dev/null +++ b/docs/releases/v1.5.0.md @@ -0,0 +1,56 @@ +# v1.5.0 + +`v1.5.0` 让维护者显式排除不应同步的仓库,并在不提供 GitHub 凭据、不访问网络的情况下校验标签与仓库策略。 + +## 升级 + +- 新增可选的 `repositories.exclude` 策略;未配置时保持 `v1.4.0` 的仓库选择行为。 +- 新增 `validate_only` Action input;设置为 `"true"` 时不要求 `token` 或 `owner`。 +- 新增 `pnpm validate:config` 本地命令,与 Action 复用同一套配置规则。 +- 使用方无需迁移标签清单、现有 inputs 或 outputs;应审核发布提交并固定 README 中的完整 SHA。 + +## 仓库范围 + +- 选择顺序固定为:全部仓库或 `repositories.include` → `repositories.exclude` → 可选的 `repository` input。 +- `repositories.exclude` 可以单独配置,也可以与 `include` 配合使用。 +- 同一仓库不能同时出现在 `include` 与 `exclude` 中;名称比较忽略大小写,冲突会在访问 GitHub 前报错。 +- 显式的 `include: []` 会报错,避免意外扩大同步范围;`exclude: []` 是合法的空排除规则。 +- 全部仓库模式继续跳过 archived、disabled 和 fork 仓库;显式选择这些仓库时会失败。 + +## 离线校验 + +- `validate_only: "true"` 只读取 `config_file` 与 `policy_file`,不创建 GitHub 客户端,也不访问 GitHub API。 +- `pnpm validate:config` 支持通过 `--config-file` 和 `--policy-file` 指定配置文件。 +- Action 与本地命令对非法配置返回相同的核心错误和非零退出码。 +- 校验成功时同步输出保持零值,`changed` 为 `false`。 + +## 兼容性保证 + +- 默认仍为 dry-run。 +- 未设置 `repositories.exclude` 和 `validate_only` 的 workflow 保持 `v1.4.0` 行为。 +- `changed` 在预览模式表示完整计划是否包含变更;在写入模式表示是否实际完成至少一项变更。 +- 删除安全、读取重试、写入不自动重试、部分失败计数和 Unicode 行为保持不变。 + +## 生产验证 + +- [`v1.5.0-rc.1`](https://github.com/matharts/sync-labels-action/releases/tag/v1.5.0-rc.1) 候选版本固定到完整提交 SHA。 +- [全组织 exclude dry-run](https://github.com/matharts/sync-labels-action/actions/runs/29458270313) 从 6 个合格仓库中排除 `ziwei`,只处理其余 5 个仓库,且没有执行写入。 +- [Issue #32 演练记录](https://github.com/matharts/sync-labels-action/issues/32#issuecomment-4986231343) 保存无 token、无 owner、断网 `validate_only`、非法配置一致性和现有 workflow 兼容性证据。 +- 演练未观察到仓库范围、离线校验或兼容性偏差。 + +## 已知限制 + +- `validate_only` 不验证 GitHub 凭据、权限、仓库可见性或网络连通性。 +- 本版本不引入稳定的错误原因分类、失败仓库输出或可归档计划文件。 +- 并发、缓存和批处理优化不在本版本范围内。 + +## 验证 + +- `pnpm check` +- Node.js 24 持续集成 +- 可复现 `dist/index.js` bundle 比对 +- Actionlint workflow 校验 +- CodeQL +- 全组织仓库范围演练 +- 无凭据、断网离线校验 +- 现有 workflow 兼容性演练 diff --git a/package.json b/package.json index 772fd6f..0d68c3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sync-labels-action", - "version": "1.5.0-rc.1", + "version": "1.5.0", "private": true, "description": "Synchronize organization-owned GitHub labels while preserving repository-specific labels.", "scripts": { diff --git a/tests/action-metadata.test.ts b/tests/action-metadata.test.ts index d2a0d84..5fec05a 100644 --- a/tests/action-metadata.test.ts +++ b/tests/action-metadata.test.ts @@ -5,7 +5,7 @@ import { parse } from "yaml"; import { describe, expect, it } from "vitest"; describe("action metadata", () => { - it("declares the v1.5.0 release candidate with repository exclusions and offline validation", async () => { + it("declares the stable v1.5.0 release with repository exclusions and offline validation", async () => { const packageMetadata = JSON.parse( await readFile(join(process.cwd(), "package.json"), "utf8"), ) as { version: string }; @@ -27,7 +27,7 @@ describe("action metadata", () => { "failures", ]; - expect(packageMetadata.version).toBe("1.5.0-rc.1"); + expect(packageMetadata.version).toBe("1.5.0"); expect(metadata.runs).toEqual({ using: "node24", main: "dist/index.js" }); expect(metadata.inputs.repository?.description).toContain("repositories.exclude"); expect(metadata.inputs.token?.required).toBe(false);