从零到一:实现 Changesets 自动化发版全流程
在上篇文章中,我们对 Changesets 的基本使用进行了简单介绍。本文将在此基础上,进一步深入讲解如何实现 Changesets 的自动化流程,帮助你更高效地管理版本发布。
Changesets: 一个高效的版本管理工具
前置准备
初始化 Monorepo 项目
在 core
和 plugin-dashboard
两个库中,分别提供最基础的 package.json
信息:
-| packages/
-|-| core
-|-| plugin-dashboard
-|-| ...
-| package.json
-| pnpm-workspace.yaml
然后在 core
和 plugin-dashboard
两个库中提供最基础的 package.json
信息:
package.json
{
"name": "@easy-editor/plugin-dashboard",
"version": "0.0.0",
"description": "xxx",
"type": "module",
"main": "src/index.ts",
"files": [
"dist",
"README.md"
],
"publishConfig": {
"access": "public",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"typings": "dist/index.d.ts",
"module": "dist/index.js",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/cjs/index.js",
"default": "./dist/index.js"
}
}
},
// ...
}
初始化 Changesets
接下来,安装并配置 Changesets:
pnpm add @changesets/cli
pnpm changeset init
此时,项目结构变为:
-| ++ .changesets/
-|-| ++ config.json
-| packages/
-|-| core
-|-| plugin-dashboard
-|-| ...
-| package.json
-| pnpm-workspace.yaml
同时,为 Changesets 添加一些便捷的 scripts:
packages.json
{
// ...
"scripts": {
// ...
"pub:changeset": "pnpm changeset",
// 换成自己的打包工具,这里使用的是 turbo
"pub:build": "turbo run build --filter=\"@easy-editor/*\" && turbo run types --filter=\"@easy-editor/*\"",
"pub:alpha": "pnpm changeset pre enter alpha",
"pub:beta": "pnpm changeset pre enter beta",
"pub:rc": "pnpm changeset pre enter rc",
"pub:exit-pre": "pnpm changeset pre exit",
"pub:version": "pnpm changeset version",
"pub:release": "pnpm changeset publish"
}
}
现在,你可以通过运行 pnpm pub:changeset
来为库添加变更日志。例如:
pnpm pub:changeset
> @easy-editor/repository@1.0.0 pub:changeset C:\Users\jinso\Desktop\Study\EasyEditor\EasyEditor
> pnpm changeset
🦋 Which packages would you like to include? · @easy-editor/plugin-dashboard
🦋 Which packages should have a major bump? · No items were selected
🦋 Which packages should have a minor bump? · No items were selected
🦋 The following packages will be patch bumped:
🦋 @easy-editor/plugin-dashboard@0.0.2-alpha.2
🦋 Please enter a summary for this change (this will be in the changelogs).
🦋 (submit empty line to open external editor)
🦋 Summary · feat: first publish
🦋
🦋 === Summary of changesets ===
🦋 patch: @easy-editor/plugin-dashboard
🦋
🦋 Note: All dependents of these packages that will be incompatible with the new version will be patch bumped when this changeset is applied.
🦋
🦋 Is this your desired changeset? (Y/n) · true
🦋 Changeset added! - you can now commit it
🦋
🦋 If you want to modify or expand on the changeset summary, you can find it here
🦋 info ...Project\.changeset\stale-walls-train.md
随后,在 .changesets
目录下会生成一个 changelog 文件。
自动化流程
假设项目分支结构如下:
- main(主分支)
- develop(开发分支,不限制为 develop,可以是任意分支名称)
整体流程概述如下:
-
在
develop
分支上开发功能,并进行测试。 -
完成功能开发后,基于
main
分支新建一个release/xxx
分支,将需要发布的功能合并进来。自动化流程细节:
- 基于
release/xxx
分支创建一个changelog/xxx
分支。 - 在该分支上执行
pnpm pub:version
,生成版本信息。 - 创建一个 PR,包含所有需要发布库的 CHANGELOG,并将此分支合并到
release/xxx
上。
- 基于
-
在
release/xxx
分支测试无误后,将其合并到main
分支。自动化流程细节:
- 执行
pnpm pub:build
,对库的内容进行打包。 - 执行
pnpm pub:release
,对库进行发布。
- 执行
主要的自动化流程集中在 release/xxx
和 main
分支上,接下来进入实操环节。
首先,将需要用到的 token 进行配置
- GITHUB_TOKEN:用于 changeset 生成 PR。
- NPM_TOKEN:用于发版。
GITHUB_TOKEN 的配置
在 changesets/action
中,会创建一个版本更新 PR,这需要借助 GITHUB_TOKEN 来获取相应权限。
进入用户个人设置中心,依次点击 Setting
> Developer Settings
> Personal access tokens
,来添加一个新的 token。
点击按钮新增 token 。
生成后,会看到对应的 token(请妥善保存,一旦丢失,只能删除后重新配置)。
将 token 添加到 environment secrets(环境密钥)
接着,将该 token 配置到项目的环境密钥中,操作步骤如下:
点击按钮添加 environment secret。
填写名称和 token,完成配置。
NPM_TOEKN 的配置
登录 npm 官网,找到 Access Token 目录。
点击按钮创建 token。
token 的配置界面与 GitHub 类似:
生成后,在页面顶部可以看到你创建的 token。
按照之前配置 GITHUB_TOKEN 的方法,将 NPM_TOKEN 也配置到项目的环境密钥中。
在配置过程中,可能会遇到以下问题:
问题:@xxx/xxx 发布错误
例如,当你尝试发布一个名为 @easyeditor/core 的库时,可能会遇到发布失败的情况,并提示如下错误:
原因在于,以 @xxx 开头的库,需要先在 npm 中创建对应的组织,才能正常使用。
解决方法如下:
- 登录 npm 官网,进入组织创建页面。
- 填写相关信息,创建组织,其中名称需与 @xxx 中的 xxx 保持一致,即对应组织名。
这里的名称要对应 @xxx 中的 xxx,也就是组织名才行。
创建完成后,记得将自己邀请到该组织中,然后再尝试重新发布。
自动化实现:Github Action + changesets/action
在根目录下创建如下两个自动化工作流文件:
-| .github/
-|-| workflows
-|-|-| release.yml # 发布
-|-|-| version.yml # 生成版本
关于 Github Action 的具体使用细节在此不做过多展开,但会详细讲解这两个工作流文件的内容。
version 工作流
# 工作流名称
name: Version
# 当推送到 release/ 开头的分支时触发
on:
push:
branches:
- release/**
# 授予工作流权限,后续会详细解释
permissions: write-all
# 工作流任务
jobs:
version: # 任务ID
name: Version
runs-on: ubuntu-latest # 运行环境
strategy:
matrix:
node-version: [18] # Node 环境版本
# 执行步骤
steps:
# 1. 检出代码
- name: Checkout Branch
uses: actions/checkout@v3
# 2. 安装 pnpm
- name: Install pnpm
uses: pnpm/action-setup@v4
# 3. 设置 Node.js 环境
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
# 4. 安装项目依赖
- name: Install Dependencies
run: pnpm install
# 5. 创建版本更新 PR
- name: Create Release Pull Request
uses: changesets/action@v1
with:
version: pnpm run pub:version # 自定义版本命令
commit: 'chore: update versions' # 提交信息
title: 'chore: update versions' # PR 标题
env: # 环境变量
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
其中,secrets.PERSONAL_GITHUB_TOKEN 对应项目环境密钥中配置的 GITHUB_TOKEN 名称。
release 工作流
name: Release
# 当推送到 main 分支时触发
on:
push:
branches:
- main
permissions: write-all
jobs:
release:
name: Release
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18]
steps:
# 1. 检出代码
- name: Checkout Branch
uses: actions/checkout@v3
# 2. 安装 pnpm
- name: Install pnpm
uses: pnpm/action-setup@v4
# 3. 设置 Node.js 环境
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
# 4. 安装项目依赖
- name: Install Dependencies
run: pnpm install
# 5. 对库进行打包
- name: Setup
run: pnpm run pub:build
# 6. 发版
- name: Publish to npm
id: changesets
uses: changesets/action@v1
with:
version: pnpm run pub:version # 执行版本升级命令(生成 CHANGELOG 和更新版本号)
commit: 'chore: update versions' # 版本更新后的提交信息
title: 'chore: update versions' # 创建版本提交的标题
publish: pnpm run pub:release # 执行实际发布命令
createGithubReleases: false # 不自动创建 GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
将上述 workflows 文件推送到仓库后,创建对应的 release/xxx
分支,即可触发相应的工作流。
在 version 工作流执行过程中,可以看到如下内容:
完成后,在 PR 中会看到一条新的合并请求:
合并完成后,对 release/xxx
分支进行测试,确认是否可以进行发版。
准备就绪后,将 release/xxx
分支合并到 main
分支:
同时,会触发发版的工作流:
至此,整个自动化发版流程便完成了。
在实践过程中,可能会遇到以下问题:
问题1:remote: Permission to xxx.git denied to github-actions[bot].
关联的 ISSUE:Permission to create PR denied · Issue #268 · changesets/action
原因:工作流缺乏创建 PR 的权限。
这里有两种方式去解决:
- 在仓库的设置里为工作流添加权限。
-
在工作流文件中配置权限,即上文中提到的
permissions: write-all
。如果需要,也可以专门指定特定的权限,例如:
permissions: pull-requests: write contents: write
问题2:error TypeError: Cannot read property 'prerelease' of null
关联 ISSUE:
- Fixed the prerelease version parse by vzt7 · Pull Request #847 · changesets/changesets
- Fix issue with bumping packages without
package.json#version
by Andarist · Pull Request #705 · changesets/changesets
原因:在发布 prerelease 版本时,项目库中可能存在 examples/demos 等案例项目,这些项目设置了 private: true
,但未设置 version,从而导致该错误。
解决方法:为案例项目添加 version 字段,虽然它不会生效(记得在 .changeset/config.json
中忽略该项目),但可以避免这个错误。
参考项目
为了更好地理解和实践上述自动化发版流程,你可以参考以下已经成功实现的项目:
Easy-Editor/EasyEditor: A cross-framework low-code engine with scale-out design
通过该项目,你可以直观地看到 Changesets 自动化发版流程在实际项目中的应用,从而更好地将其应用到自己的项目中。