# 完成第一次发布

初始化一座小仓库、记录变更、检查受影响的软件包、修改版本并执行发布。

Source: https://semifold.noctisynth.org/zh/docs/getting-started/first-release/
Language: zh



本教程使用正常的交互式命令行。你会创建 Semifold 配置、记录一份变更集、检查受影响的软件包、修改文件，并准备一次软件包仓库发布。

## 开始之前 [#开始之前]

准备一座默认分支为 `main`、工作区没有未提交修改的 Git 仓库。示例假设仓库中至少有一个包含有效 `Cargo.toml` 的 Rust 软件包；其他内置软件生态使用相同的生命周期。

如果 `smif --version` 还不能运行，请先按照[安装指南](https://semifold.noctisynth.org/zh/docs/getting-started/installation/)安装 Semifold。

## 1. 初始化仓库 [#1-初始化仓库]

在仓库根目录运行：

```bash
smif init
```

交互提示会依次询问：

1. 要发现哪些软件包生态；
2. 基础分支和发布分支名称；
3. 是否使用默认的变更日志分类；
4. 是否生成 GitHub Actions 工作流。

本教程选择 Rust，分支保留 `main` 和 `release`，接受默认分类，并生成工作流。

<ExpectedOutput title="创建的文件">
  <Files>
    <Folder name=".changes">
      <File name="config.toml" />
    </Folder>

    <Folder name=".github">
      <Folder name="workflows">
        <File name="semifold-ci.yaml" />

        <File name="semifold-status.yaml" />
      </Folder>
    </Folder>
  </Files>
</ExpectedOutput>

打开 `.changes/config.toml`。在 `[packages]` 下确认每个软件包的路径和解析器符合预期。配置表的 key 是稳定的软件包 ID（`PackageId`），它可能不同于清单文件中用于发布的名称。

如果仓库已经初始化，只是后来增加或删除了软件包，请使用 `smif config sync`，不要再次运行 `init --force`。

### 配置 GitHub Actions 权限 [#配置-github-actions-权限]

运行生成的工作流前，请打开仓库的 **Settings → Actions → General → Workflow permissions**，然后：

1. 选择 **Read and write permissions**，让发布工作流能够推送准备好的版本提交。
2. 勾选 **Allow GitHub Actions to create and approve pull requests**，让工作流能够创建或更新发布 Pull Request。

保存设置后再继续。如果组织或企业策略禁止启用这些仓库级选项，请联系管理员在上级策略中开放相应能力。参见 GitHub 的[仓库 Actions 设置文档](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository)。

## 2. 完成一项用户可见的改动 [#2-完成一项用户可见的改动]

修改一个公开 API，或者完成其他使用者能感知的行为变化。第一次练习尽量保持改动小而明确，便于判断版本影响。

现在记录发布意图：

```bash
smif commit
```

按照提示选择发生变化的软件包，选择 `patch`、`minor` 或 `major`，选择变更日志分类，输入 `add-api` 这样的简短变更集名称，再写一段给使用者阅读的摘要。

Semifold 会创建类似下面的文件：

```md title=".changes/add-api.md"
---
my-package: "minor:feat"
---

开放新的公共 API。
```

`minor` 表示期望的版本提升；`feat` 选择变更日志分组，不会选择发布通道。

把变更集与代码改动放在同一个提交或拉取请求中，让审查者一起判断实现和版本影响。

## 3. 检查受影响的软件包 [#3-检查受影响的软件包]

```bash
smif status
```

<ExpectedOutput title="需要确认的内容">
  * 发生变化的软件包具有正确的当前版本和目标版本；
  * 直接原因指向文件名为 `.changes/add-api.md` 的变更集；
  * 额外出现的软件包都有可以理解的依赖传播原因；
  * 最后的提示表示发布计划已经就绪，而不是文件已经被修改。
</ExpectedOutput>

如果软件包或版本不正确，请在这里停止。修改变更集、软件包 ID 或依赖配置，然后重新运行 `smif status`。

## 4. 选择自动或手工发布路径 [#4-选择自动或手工发布路径]

如果 `smif init` 已经生成 GitHub Actions 工作流，推荐从这里开始交给自动化处理：

1. 推送代码改动和 `.changes/add-api.md`，再把这次拉取请求合入 `main`；
2. 生成的工作流运行 `smif ci`，更新配置中的 `release` 分支，并创建或刷新对应的发布拉取请求；
3. 在发布拉取请求中检查自动生成的版本与变更日志，确认后把它合入 `main`；
4. 下一次工作流运行发现已经没有待处理的变更集，于是按照依赖关系发布准备好的软件包版本。

同一次发布不要再在本地额外运行 `smif version` 或 `smif publish`。只有仓库没有使用生成的工作流，或者正在一次性测试仓库中专门学习手工机制时，才继续执行下面的命令。

## 5. 手工预览并应用版本修改 [#5-手工预览并应用版本修改]

先预览待修改文件和待运行命令：

```bash
smif version --dry-run
```

预演不会应用正常的版本副作用。配置命令只有明确设置 `dry-run = true` 时才会在预演中运行，因此这类命令必须能够安全重复执行。

确认预览符合预期后，应用修改：

```bash
smif version
```

Semifold 会修改软件包版本和符合条件的内部依赖要求，写入变更日志，运行配置的版本修改后工作，并消费已经应用的变更集。

审查 Git diff，再运行仓库原有的测试。把生成文件提交到 `release` 分支，或者让生成的 GitHub Actions 工作流维护发布拉取请求。

## 6. 手工发布 [#6-手工发布]

版本修改进入用于发布的分支后，为相关软件生态提供所需的软件包仓库凭据。

先预览发布执行：

```bash
smif publish --dry-run
```

这条命令会验证软件包顺序并执行只读的版本存在性检查，但不会发布软件包，也不会创建代码托管平台 Release。

确认预览正确后执行：

```bash
smif publish
```

软件包按照依赖关系发布。最终报告会分别列出成功、跳过、失败和尚未开始的软件包。在持续集成环境中，如果还要创建已经配置的 GitHub Release 与附件，可以加入 `--github-release`。

## 发生失败时 [#发生失败时]

* <strong>找不到软件包：</strong>使用 `.changes/config.toml` 中 `[packages]` 的 `PackageId`，不要猜测软件包仓库名称。
* <strong>工作区不干净：</strong>先检查并提交无关文件。`--allow-dirty` 表示有意接受当前 diff 作为输入，不会替你清理仓库。
* <strong>软件包仓库中已经存在目标版本：</strong>Semifold 会跳过对应发布命令。启用 GitHub Release 时仍可以补建缺失的 Release；已经存在的 Release 不会触发附件恢复。
* <strong>部分发布失败：</strong>根据最终报告中的成功、失败和尚未开始状态，修复失败的凭据、版本检查或命令后重试。不要手工再次发布已经确认存在的版本。

## 理解工作流后再做自动化 [#理解工作流后再做自动化]

交互提示是正常的学习和本地维护路径。持续集成与输入受限环境可以通过参数提供相同答案：

```bash
smif init --resolvers rust \
  --base-branch main \
  --release-branch release \
  --default-tags \
  --github-actions

smif commit --name add-api \
  --package my-package=minor \
  --tag feat \
  --summary "开放新的公共 API。"
```

这些参数只是自动化兼容接口，不代表另一套发布模型，也不是开始使用 Semifold 的前置知识。

至此，你已经走完基础生命周期：发现软件包、记录变更集、联动修改相关版本与变更日志，再按依赖关系发布。仓库需要更多策略时，继续阅读[配置概览](https://semifold.noctisynth.org/zh/docs/configuration/overview/)。

