---
description: 配置发布根目录、workspace 发现、版本文件、changelog、Git 策略和 hook。
---

# 配置发布边界

Verso 默认读取当前目录的 `verso.toml`；也可以传入 `--config <PATH>` 或 `--group <NAME>`。
`--group core` 会选择 `verso.core.toml`。所选配置文件所在目录会成为发布根目录：package 模式、
manifest、changelog、hook 和 Git 命令都从这里解析。

未知的 table 或配置项会被拒绝。配置路径必须是相对路径、使用正斜杠，且不能包含 `..` 或逃逸发布根目录。

## 完整默认模型

```toml
[version]
root_package = "package.json"
require_consistent_versions = true
cargo_manifest_paths = []

[workspaces]
patterns = []
include_root = true
ignore = []
use_gitignore = true

[changelog]
enabled = false
infile = "CHANGELOG.md"
preset = "angular"

[git]
require_clean_worktree = true
commit_message = "chore(release): release v${version}"
tag_name = "v${version}"
push = "atomic"

[hooks]
# before_version = "pnpm test"
# after_version = "pnpm build"
# before_commit = "pnpm lint"
# after_commit = "node scripts/verify-release.mjs"
# before_tag = "pnpm pack"
# after_tag = "node scripts/record-tag.mjs"
# before_push = "pnpm check"
# after_push = "node scripts/notify.mjs"

[github_release]
enabled = false
```

所有 table 和配置项都是可选的。默认配置路径不存在、但根 package manifest 存在时，Verso 会直接采用这些
值而不创建文件。显式指定但不存在的配置文件始终是错误。

## 发布组

一个配置定义一个发布组。该配置发现的每个 package 和配置的 Cargo manifest 都会获得同一个目标版本。
`version.require_consistent_versions` 必须保持为 `true`；设置为 `false` 会被拒绝，因为这样无法确定组的
当前版本。

独立版本组应使用独立配置，并且一次只运行一个组：

```text
verso.core.toml  -> verso --group core bump minor
verso.ui.toml    -> verso --group ui --version 2.0.0 --yes
```

命名组会自动给默认的 `v${version}` 模板加上组名：例如 `core-v1.2.3`、`ui-v1.2.3`。如果显式配置了
其他 `git.tag_name`，Verso 会原样使用。

`--group <NAME>` 与 `--config <PATH>` 互斥。组名必须以 ASCII 字母或数字开头，后续可以使用 ASCII 字母、
数字、`-` 和 `_`。

## Workspace 发现

`workspaces.patterns` 为空时，Verso 会先读取 `pnpm-workspace.yaml` 的 `packages`，再读取根 manifest 的
`workspaces` 字段；两者都没有模式时，只使用根 package。

| 配置项          | 默认值 | 行为                                                             |
| --------------- | ------ | ---------------------------------------------------------------- |
| `patterns`      | `[]`   | include glob；支持 `*`、`**`、`?`、字符类、brace 和前导 `!` 排除 |
| `include_root`  | `true` | 包含 `version.root_package` 选中的 manifest                      |
| `ignore`        | `[]`   | 排除匹配路径；`fixtures` 这类普通片段会排除任意位置同名目录      |
| `use_gitignore` | `true` | 遍历时读取根目录和嵌套目录的 `.gitignore`                        |

`node_modules` 和 `.git` 永远被排除。设置 `include_root = false` 时，`patterns` 必须显式且非空，不能在
这种组合下依赖自动推断 workspace 模式。

每个匹配目录按以下顺序选择第一个存在的 manifest：`package.json`、`package.json5`、`package.yaml`、
`package.yml`。Verso 只替换顶层 `version` 标量，并保留文件其余部分的格式。

## 版本来源

| 配置项                        | 默认值         | 行为                                                                        |
| ----------------------------- | -------------- | --------------------------------------------------------------------------- |
| `root_package`                | `package.json` | 提供当前版本；启用 `include_root` 时也参与更新                              |
| `require_consistent_versions` | `true`         | 必须保持为 `true`；成员版本不一致时拒绝，以确保组只有一个当前版本           |
| `cargo_manifest_paths`        | `[]`           | 更新每个 manifest 的 `[package].version`，并按需更新最近的上级 `Cargo.lock` |

默认的 `root_package` 不存在时，Verso 可以解析发布根目录中的其他受支持 manifest；自定义
`root_package` 则会严格按配置路径使用。

## Changelog

设置 `changelog.enabled = true` 后，Verso 会在 `changelog.infile` 中加入发布记录。
`changelog.preset` 接受 `angular` 和 `keep-a-changelog`。只有完整发布会生成 changelog；
`verso bump` 不会修改它。

两种 preset 都会找到符合 `git.tag_name` 且当前 `HEAD` 可达的最高 SemVer tag，读取之后的非 merge
commit，再按 Conventional Commit subject 分类。`angular` preset 使用：

- `fix` -> Bug Fixes
- `feat` -> Features
- `perf` -> Performance Improvements
- `!` 或 `BREAKING CHANGE:` footer -> BREAKING CHANGES
- 其他 conventional type -> 对应类型的 Other Changes section
- 非 conventional commit -> 忽略

当 `origin` 是可识别的 GitHub SSH 或 HTTPS 地址时，会生成 compare、commit 和 issue 链接。没有可分类
内容时会写入 `No classifiable changes.`。

`keep-a-changelog` preset 会把新版本插入 `## [Unreleased]` 之后，并把 `feat` 映射到 Added、`fix`
映射到 Fixed，把性能、breaking 和其他 conventional change 映射到 Changed。如果可以识别 GitHub
origin，还会更新 `[Unreleased]` 和版本链接定义。

## Git 策略

| 配置项                   | 默认值                                | 行为                                                     |
| ------------------------ | ------------------------------------- | -------------------------------------------------------- |
| `require_clean_worktree` | `true`                                | 写入前要求 `git status --porcelain` 为空                 |
| `commit_message`         | `chore(release): release v${version}` | 把所有 `${version}` 替换为目标版本                       |
| `tag_name`               | `v${version}`                         | 必须包含 `${version}`；命名组会自动为此默认值加组名      |
| `push`                   | `atomic`                              | 在一个原子命令中推送当前 upstream 分支和准确 release tag |

设置 `require_clean_worktree = false` 后，可以存在无关的未暂存文件，但 index 和所有 release 文件仍必须
干净。`follow-tags` 只作为旧配置别名，读取后会归一化为 `atomic`；Verso 不提供非原子推送模式。

## Hook 是受信任的 shell 命令

Hook 从发布根目录运行：macOS/Linux 使用 `sh -c`，Windows 使用 `cmd /C`。空字符串视为未配置；非零
退出状态会在对应阶段停止发布。

`verso bump` 只运行 `before_version` 和 `after_version`；commit、tag 与 push hook 只属于完整发布。

Dry-run 会输出 hook 命令，因此不要把 secret 直接写进配置。敏感值应通过进程环境传入，并让
`verso.toml` 保持可审查。各 hook 边界的清理行为见[发布流程](/zh-CN/release-workflow/)。

`github_release.enabled = true` 目前会被拒绝。请在 tag 推送完成后由 CI 创建 GitHub Release。
