从零到一:实现 Changesets 自动化发版全流程

发布于:2025-02-27 ⋅ 阅读:(7) ⋅ 点赞:(0)

在上篇文章中,我们对 Changesets 的基本使用进行了简单介绍。本文将在此基础上,进一步深入讲解如何实现 Changesets 的自动化流程,帮助你更高效地管理版本发布。

Changesets: 一个高效的版本管理工具

前置准备

初始化 Monorepo 项目

coreplugin-dashboard 两个库中,分别提供最基础的 package.json 信息:

-| packages/
-|-| core
-|-| plugin-dashboard
-|-| ...
-| package.json
-| pnpm-workspace.yaml

然后在 coreplugin-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,可以是任意分支名称)

整体流程概述如下:

  1. develop 分支上开发功能,并进行测试。

  2. 完成功能开发后,基于 main 分支新建一个 release/xxx 分支,将需要发布的功能合并进来。

    自动化流程细节:

    1. 基于 release/xxx 分支创建一个 changelog/xxx 分支。
    2. 在该分支上执行 pnpm pub:version,生成版本信息。
    3. 创建一个 PR,包含所有需要发布库的 CHANGELOG,并将此分支合并到 release/xxx 上。
  3. release/xxx 分支测试无误后,将其合并到 main 分支。

    自动化流程细节:

    1. 执行 pnpm pub:build,对库的内容进行打包。
    2. 执行 pnpm pub:release,对库进行发布。

主要的自动化流程集中在 release/xxxmain 分支上,接下来进入实操环节。

首先,将需要用到的 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 中创建对应的组织,才能正常使用。

解决方法如下:

  1. 登录 npm 官网,进入组织创建页面。
  2. 填写相关信息,创建组织,其中名称需与 @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 的权限。

这里有两种方式去解决:

  1. 在仓库的设置里为工作流添加权限。

在这里插入图片描述

  1. 在工作流文件中配置权限,即上文中提到的 permissions: write-all

    如果需要,也可以专门指定特定的权限,例如:

    permissions:
      pull-requests: write
      contents: write
    

问题2:error TypeError: Cannot read property 'prerelease' of null

关联 ISSUE:

  1. Fixed the prerelease version parse by vzt7 · Pull Request #847 · changesets/changesets
  2. 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 自动化发版流程在实际项目中的应用,从而更好地将其应用到自己的项目中。