Skip to main content

发布工作流程

实验性

此功能仍在孵化中,我们可能会根据你的反馈对其进行改进。

¥This feature is still incubating, and we'll likely be improving it based on your feedback.

使用 monorepos 时,一项艰巨的任务通常是在开始新版本时确定哪些包应该接收新版本。Yarn 提供了一些工具,旨在使此工作流程更容易,而无需第三方工具(当然,你可能更喜欢不同实现提供的工作流程!)。

¥When working with monorepos, a hard task often is to figure out which packages should receive a new version when starting a new release. Yarn offers a few tools that aim to make this workflow easier without the need for third-party tools (although it's possible you may prefer the workflow offered by different implementations, of course!).

自动更新依赖

¥Auto-updated dependencies

运行 yarn version 命令升级工作区的版本时,通过基本 semver 范围(^x.y.z~x.y.z 等)依赖于第一个工作区的其他每个工作区都将自动更新以引用新版本。例如,假设我们有以下工作区:

¥When running the yarn version command to upgrade the version of a workspace, every other workspace that depend on the first one through a basic semver ranges (^x.y.z, ~x.y.z, ...) will get auto-updated to reference the new version. For example, let's say we have the following workspaces:

/packages/common (1.0.0)
/packages/server (depends on common@^1.0.0)
/packages/client (depends on common@^1.0.0)

在 2.0 之前的版本中,升级 common 需要你在那里运行命令,然后进入 serverclient 中的每一个以手动升级它们的依赖以引用新版本。但现在不是了!如果我们将 yarn version 1.1.1 运行到 common,将应用以下更改:

¥In pre-2.0, upgrading common would have required you to run the command there, then go into each of server and client to manually upgrade their dependencies to reference the new version. But not anymore! If we run yarn version 1.1.1 into common, the following changes will be applied:

/packages/common (1.1.1)
/packages/server (depends on common@^1.1.1)
/packages/client (depends on common@^1.1.1)

当然,当 monorepo 中的包总是要用作 monorepo 的一部分时,这并不那么重要,但当你使用多个要发布的包时,它会变得更加有趣。如果你忘记更新任一依赖包的范围,你的用户可能会下载旧版本的 common,而该版本与新版本不兼容。

¥Of course it's not that important when the packages from the monorepo are always meant to be used as part of the monorepo, but it becomes much more interesting when you work with multiple packages meant to be published. Had you forgotten to update the range of either of your dependent packages, your users would have potentially downloaded an old version of common which wouldn't have been compatible with the newer one.

延迟版本控制

¥Deferred versioning

从 2.0 开始,yarn version 命令现在接受一个新标志:--deferred。设置后,此标志将导致命令不会立即更改本地清单的 version 字段,而是在内部记录一个条目,表明当前包需要在下一个发布周期内进行升级。例如,以下内容:

¥Starting from the 2.0, the yarn version command now accepts a new flag: --deferred. When set, this flag will cause the command to not immediately change the version field of the local manifest, but to instead internally record an entry stating that the current package will need to receive an upgrade during the next release cycle. For example, the following:

yarn version minor --deferred

不会导致 package.json 文件更改!相反,Yarn 将在 .yarn/versions 目录中创建(或重用,如果你在分支内)。此文件将记录请求的升级:

¥Will not cause the package.json file to change! Instead, Yarn will create (or reuse, if you're inside a branch) a file within the .yarn/versions directory. This file will record the requested upgrade:

releases:
my-package@1.0.0: minor

然后稍后,一旦你准备好,只需运行 yarn version apply。然后,Yarn 将找到它之前保存的所有升级记录,并一次性应用它们(包括通过处理我们所看到的升级相互依赖)。

¥Then later on, once you're ready, just run yarn version apply. Yarn will then locate all the upgrade records it previously saved, and apply them all at once (including by taking care of upgrading inter-dependencies as we saw).

签入延期记录

¥Checked-in deferred records

我们在上一节中看到,yarn version patch 可以将未来版本存储在内部文件夹 .yarn/versions 中。但为什么会这样?这有什么好处?要回答这个问题,请考虑一个通过 monorepo 开发的流行开源项目。该项目收到许多外部拉取请求,但它们不会立即发布 - 它们通常作为批处理的一部分发布。每隔一段时间,首席维护者就会接受所有更改,将它们转换为新版本,然后开始部署。

¥We've seen in the previous section that yarn version patch could store the future versions in an internal folder, .yarn/versions. But why is that? What good is it? To answer this question, consider a popular open-source project developed through a monorepo. This project receives many external pull requests, but they aren't released right away - they're often released as part of a batch. Every once in a while, the lead maintainer will take all the changes, convert them into new versions, and start the deployment.

让我们关注必须将更改转换为版本的部分。它是如何工作的?这并不容易。以 Lerna 为例(最流行的 monorepos 版本管理工具),你有两种解决方案:

¥Let's focus on the part where changes have to be converted into versions. How does that work? This isn't easy. Taking Lerna, for example (the most popular version management tool for monorepos), you have two solutions:

  • 使用固定模式,你的所有包都有一个版本。因此,它们会一次性升级。

    ¥With the fixed mode, all your packages have a single version. As such, they get upgraded all at once.

  • 使用独立模式,你可以为每个源发生变化的包选择一个版本。

    ¥With the independent mode, you get to chose a version for each package whose sources changed.

但是,仍有一个关键问题:即使你使用独立模式,你如何知道哪些包需要升级?同样重要的是,它们应该是补丁版本吗?小版本?很难知道 - 大型项目每周可以收到数十个 PR,跟踪哪些单元需要发布以及发布到哪个版本是一项相当困难的任务。

¥One critical problem remains, though: even if you use the independent mode, how will you know which packages are meant to be upgraded? And, just as critical, should they be patch releases? Minor releases? Hard to know - large projects can receive dozens of PRs a week, and keeping track of which units need to be released and to which version is a pretty difficult task.

但是,使用 Yarn 的工作流程,这一切都变得非常容易!由于升级保存在一个文件中,并且由于该文件神奇地绑定到 Git 分支,因此它只需提交发布文件夹即可 - 所有预期版本都将成为项目历史的一部分,直到 yarn version apply 到来 - 然后 Yarn 将使用所有单个记录,合并它们(这样需要次要版本的 PR 将具有比需要补丁的 PR 更高的优先级),并同时应用它们。

¥With Yarn's workflow, however, this all becomes very easy! Since the upgrades are kept in a file, and since this file is magically bound to a Git branch, it simply becomes a matter of committing the release folder - all expected releases will then become part of the project history until comes the time of yarn version apply - then Yarn will consume all the individual records, merge them (so that a PR requiring a minor will have higher precedence than the PR requiring a patch), and apply them simultaneously.

作为额外的奖励,你甚至可以将软件包升级作为典型 PR 审查的一部分进行审查!这将赋予你的社区更多权力,同时确保每个人都遵守规则。

¥As an added bonus, you'll even be able to review the package upgrades as part of the typical PR review! This will have the effect of delegating more power to your community while being able to ensure that everyone follows rules.

确保版本升级(CI)

¥Ensuring that versions are bumped (CI)

但是,提交延期发布的一个问题是,确保收到的 PR 包含正确的软件包发布定义变得非常重要。例如,你应该能够相信定义包含每个修改工作区的发布策略(补丁、次要、主要……)。

¥One problem with committing the deferred releases, however, is that it becomes important to make sure that the PRs you receive include the correct package release definitions. For example, you should be able to trust that the definition contains release strategies (patch, minor, major, ...) for each modified workspace.

为了以自动化方式解决此问题,出现了 yarn version check 命令。运行时,此命令将确定哪些包已更改以及它们是否在发布定义文件中列出。如果不是,则会抛出错误,并且 - 假设你将其集成到 CI 系统中,例如 GitHub Actions - PR 作者将被要求填写发布定义文件。

¥To solve this problem in an automated way, the yarn version check command appeared. When run, this command will figure out which packages changed and whether they are listed in the release definition file. If they aren't, an error will be thrown and - assuming you integrate this into a CI system such as the GitHub Actions - the PR author will be asked to fill out the release definition file.

编写此文件可能很乏味;幸运的是 yarn version check 实现了一个名为 --interactive 的非常方便的标志。设置(yarn version check --interactive)后,Yarn 将打印一个终端界面,其中汇总了所有更改的文件、所有更改的工作区、所有相关的依赖工作区以及每个条目的复选框,允许你选择要为每个工作区设置的发布策略。

¥Writing this file can be tedious; fortunately yarn version check implements a very handy flag named --interactive. When set (yarn version check --interactive), Yarn will print a terminal interface that will summarize all the changed files, all the changed workspaces, all relevant dependent workspaces, and checkboxes for each entry allowing you to pick the release strategies you want to set for each workspace.

changesetIgnorePatterns 配置选项可用于在检查哪些文件已更改时忽略文件。它对于排除不影响发布过程的文件(例如测试文件)很有用。

¥The changesetIgnorePatterns configuration option can be used to ignore files when checking which files have changed. It is useful for excluding files that don't affect the release process (e.g. test files).

警告

¥Caveat

提交历史

¥Commit history

版本插件 需要访问提交历史记录,以便能够正确推断哪些包需要发布规范。特别是,当使用带有 actions/checkout@v2 或更高版本的 GitHub Actions 时,默认行为是 Git 仅获取正在检查的版本,这会导致问题。要纠正这个问题,你需要覆盖 fetch-depth 配置值以获取整个提交历史记录:

¥The version plugin requires access to the commit history in order to be able to correctly infer which packages require release specifications. In particular, when using GitHub Actions with actions/checkout@v2 or greater the default behavior is for Git to fetch just the version being checked, which would cause problems. To correct this, you will need to override the fetch-depth configuration value to fetch the whole commit history:

- uses: actions/checkout@v2
with:
fetch-depth: 0