自动化CHANGELOG,持续集成

前言

最近在开发使用 Github Issue 编写 blog 的项目。目前还在持续开发中,已经 300+ commits,npm 上已经发布的版本迭代有 9个。后面仍然会继续维护,有许多准备增加的能供,需要优化的点,以及已知的需要重构的逻辑,应该还会有相当的bug需要修复。

抱着负责任的态度,个人认为需要一个渠道使得 Isubo 的使用者获知这些一系列的变动。因此,需要编写 CHANGELOG 记录每个项目版本的变动。

但是,由于目前还是一个人在开发此项目,精力有限,需要更多地聚焦在功能新增、优化、重构和Bug修复。

CHANGELOG 自动化是最终的答案!

自动化的优点

  • 简化了 changelog 的创建流程:手动创建 changelog 可能需要花费大量的时间和精力,特别是对于大型项目来说。自动化创建 changelog 可以减少这种繁琐的工作,允许开发者更专注于编写代码和解决问题。

  • 提高了 changelog 的准确性:手动创建 changelog 可能会出现遗漏或错误,因为开发者需要手动记录每个版本的更改。自动化创建 changelog 可以消除这些错误,因为它们会自动从版本控制系统中提取信息。

  • 帮助团队更好地协作:自动化创建 changelog 可以帮助团队更好地协作和沟通。开发者可以更轻松地了解项目的演变历史和当前状态,从而更好地协调和分配任务。

  • 提高了项目的可维护性:自动化创建 changelog 可以提高项目的可维护性。由于 changelog 可以自动生成,因此开发者可以更容易地了解每个版本的更改,从而更好地维护和更新代码。

总之,自动化创建 changelog 可以提高项目的开发效率、降低错误率、加强团队协作,从而提高项目的可维护性和稳定性。

CHANGELOG 的预期

页面是列表的结构,列表的子项是版本变动说明。下面是子项的结构:

1
2
3
4
5
6
7
8
// 标题
# 版本号-1

// 内容
- 新增的功能 1
- 修复的bug
- 优化
- ...

主要由标题和内容两部分构成:

  • 标题:版本号
  • 内容:子列表描述变动,包含但不限于功能新增、Bug修复等等

自动化思路

1. Commits 规范

所谓巧妇难为无米之炊,所以得先有“米”才有 CHANGELOG,这里的“米”就是commits。

既然要描述新增的功能、修复的bug 和 优化等不同类型的实现,那些就要让这些实现对应的 commits 符合规范。

因此,第一步是了解现有那些 commits 的规范。选择需要遵循的规范或者基于它们指定符合预期的规范。

下面将分别详细介绍:Angular规范、Conventional Commits规范 和 Gitmoji规范。

2. 约束 Commit 编写

既有规范,则需要有 commit msg 的校验逻辑。使用 git-hooks 钩子拦截开发者输入的 commit msg,然后对其进行校验,打回或通过后提交commit到 git-log

下文将使用 husky 拦截 commit-msg 钩子,然后使用 Commitlint 校验。

3. 优化 Commit 编写

校验终归是校验而已。如果对所遵循的规范不熟悉,编写格式正确的 commit 存在一定的心智成本。或许该增加辅助工具降低心智成本,无需数值规范,按着步骤输入即可。

下文将分别介绍 2 款 prompt 工具辅助commit的编写,它们分别是 @commitlint/prompt-cli ↗Commitizen ↗

4. 版本管理

CHANGELOG 的生成节点是版本的创建。由创建版本这个行为,产生 CHANGELOG 这个结果,因此得先处理如何进行版本管理这个问题。

制定合理的版本管理策略前,同样需要了解现有的版本管理规范,在前人路上汲取养分。同样是需要工具去约束,以版本创建的结果符合规范。

下文将介绍SemVer规范,版本管理工具 npm-versionstandard-version。包含2个工具的使用和各自工作的生命周期

5. CHANGELOG自动化

结合前面提到的 2 个版本管理工具,利用它们各自的生命周期,适时触发 CHANGELOG 的生成。

standard-version 的功能不限于版本管理,还兼具 CHANGELOG 的生成。以及与 standard-version 来自同一个工具集的 conventional-changelog-cli。2 个都是比较常用的工具。

下文将 CHANGELOG自动化 详细价绍它们的安装、使用、配置。

工作流

1. 基于 main 分支创建 develop 分支(feat/xxx、fix/xxx、…);

2. commit 变动;

3. develop 分支内容开发完成,push分支;

4. 合并 develop 分支,触发 post-merge Git 钩子;

5. 创建版本、创建 git-tag 和生成 CHANGELOG

6. 发布 git-tag 和 CHANGELOG 变动、build 源码并发布至 npm

Git Commit 规范

首先要解决的问题是

规范名称描述
Angular规范 ↗Angular规范是非常流行的Git Commit规范之一,拥有众多的用户和贡献者。它提供了一套完整的Git Commit规范。Angular规范要求Commit message必须包含三个部分:类型、范围和描述。类型可以是feat、fix、docs、style、refactor、test、chore等。范围是可选的,用于表示代码变更的影响范围。描述应该清晰地描述代码变更的内容。
Conventional Commits规范 ↗Conventional Commits是一种通用的Git Commit规范,它要求Commit message必须包含三个部分:类型、作用域和描述。类型可以是feat、fix、docs、style、refactor、test、build等。作用域是可选的,用于表示代码变更的影响范围。描述应该清晰地描述代码变更的内容。Conventional Commits还支持关键词,用于表示代码变更的重要性,例如:BREAKING CHANGE表示这个Commit会破坏向后兼容性。
Gitmoji规范 ↗Gitmoji是一种基于Emoji表情符号的Git Commit规范,它要求Commit message必须包含一个Emoji表情符号,用于表示代码变更的类型。例如::sparkles:表示新增功能,:bug:表示修复Bug,:pencil2:表示修改文档等等。Gitmoji规范还支持在Emoji后面添加一个简短的描述,用于更详细地描述代码变更的内容。

下面是每种规范的格式的列表:

Angular 规范

Angular 规范要求每个 commit message 都包含三个部分:Header、Body 和 Footer。其中,Header 包含一个必填字段和一个可选字段,必填字段为 Type,可选字段为 Scope。Body 和 Footer 都是可选的,用于提供更详细的信息。

Type 字段包含以下值:

  • feat:新功能
  • fix:修复问题
  • docs:文档修改
  • style:代码格式修改,不影响代码逻辑
  • refactor:重构代码,既不修复错误也不添加功能
  • perf:性能优化
  • test:添加或修改测试代码
  • build:构建系统或外部依赖项修改
  • ci:持续集成修改
  • chore:其他修改,如修改构建流程或辅助工具等
  • revert:回滚到之前的提交

Angular 规范的格式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<type>[(scope)]: <subject>

[body]

[footer]

# e.g.
# slim
feat: add user management module

# fully
feat(users): add user management module

This commit adds the user management module to the project.

Closes #123

其中,<type> 表示 commit 的类型,[scope] 表示 commit 的影响范围,<subject> 表示 commit 的简短描述,[body] 表示 commit 的详细描述,<footer> 表示 commit 的元信息,如关闭 issue、引入变更等。

Conventional Commits 规范

Conventional Commits 规范要求每个 commit message 都包含三个部分:Type、Scope 和 Subject。其中,Type 和 Subject 是必填的,Scope 是可选的。

Type 包含以下值:

  • feat:新功能
  • fix:修复问题
  • docs:文档修改
  • style:代码格式修改,不影响代码逻辑
  • refactor:重构代码,既不修复错误也不添加功能
  • perf:性能优化
  • test:添加或修改测试代码
  • build:构建系统或外部依赖项修改
  • ci:持续集成修改
  • chore:其他修改,如修改构建流程或辅助工具等
  • revert:回滚到之前的提交
  • feat!: 不兼容的新功能
  • fix!: 不兼容的修复问题
  • docs!: 不兼容的文档修改
  • style!: 不兼容的代码格式修改
  • refactor!: 不兼容的重构代码
  • perf!: 不兼容的性能优化
  • test!: 不兼容的添加或修改测试代码
  • build!: 不兼容的构建系统或外部依赖项修改
  • ci!: 不兼容的持续集成修改
  • chore!: 不兼容的其他修改,如修改构建流程或辅助工具等

Conventional Commits 规范的格式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<type>[scope]: <subject>

[body]

[footer]

# e.g.
# slim
feat: add user management module

# fully
feat(users): add user management module

This commit adds the user management module to the project.

Closes #123

其中,<type> 表示 commit 的类型,[scope] 表示 commit 的影响范围,<subject> 表示 commit 的简短描述,[body] 表示 commit 的详细描述,[footer] 表示 commit 的元信息。

Gitmoji 规范

以下是 Gitmoji 规范中一些常用的 emoji 和它们的含义:

  • :sparkles::新增功能
  • 🐛 :bug::修复 bug
  • 📚 :books::修改文档
  • 💄 :lipstick::修改样式
  • ♻️ :recycle::重构代码。
  • :white_check_mark::修改测试用例
  • 🔧 :wrench::修改构建过程或工具
  • 🚀 :rocket::优化性能
  • 💚 :green_heart::修改持续集成流程
  • 📦 :package::修改构建过程
  • :rewind::撤销之前的提交

Gitmoji 规范的格式为:

1
2
3
4
5
6
7
8
9
10
11
12
<gitmoji> <description>

[body]

# e.g.
# slim
✨ add user management module

# fully
✨ add user management module

This commit adds the user management module to the project.

其中,<gitmoji> 是一个表情符号,表示 commit 的类型和含义,<description> 表示 commit 的简短描述 ,[body]?: commit 的详细描述。

小结

从以上可以看出 Conventional Commits 规范 与 Angular 规范有比较多的相同之处。是的,Conventional Commits 规范借鉴了 Angular 规范。

事实上,Conventional Commits 规范的创始人 Tim Pope 是 Karma 团队的成员,他在开发 Karma 过程中使用了 Angular 规范,认为这个规范非常有用。因此,他在 Angular 规范的基础上,扩充和修改了一些内容,提出了 Conventional Commits 规范。可以说,Conventional Commits 规范是在 Angular 规范的基础上发展而来的,但是相对于 Angular 规范,Conventional Commits 规范更加通用,可以适用于更多的项目和开发语言。

以下是 Angular 规范和 Conventional Commits 规范在某些方面存在的一些差异,具体如下:

  • Header 格式不同:Angular 规范要求 Header 必须包含 Type 字段和可选的 Scope 字段,如 “feat(core): add new feature”;而 Conventional Commits 规范要求 Header 必须包含 Type 和 Subject 字段,Scope 字段是可选的,如 “feat: add new feature”。

  • Type 值的定义略有不同:Angular 规范和 Conventional Commits 规范都定义了一些 Type 值,但有些值的含义略有不同。例如,Conventional Commits 规范将 “build” 和 “ci” 两个 Type 值分别定义为构建和持续集成修改,而 Angular 规范将它们合并为 “build”。

  • Conventional Commits 规范定义了特殊的 Type 值:Conventional Commits 规范定义了一些特殊的 Type 值,如 “feat!” 和 “fix!”,用于表示不兼容的新功能或修复问题。而 Angular 规范没有这样的定义。

Gitmoji 规范的显著特点是供了大量的 emoji 来描述不同类型和目的的 Git 提交,这使得开发者可以更加准确地描述自己的 Git 提交,简单易懂,具有很强的可读性。Commit的格式在一定程度上与前两者有相似之处,从提出时间上看,它算是采百家之长的集大成者了。

Gitmoji 规范的制定者 Carlos Cuesta 在规范的 Github 页面上并没有明确提到他借鉴了哪些规范。然而,从 Gitmoji 规范的内容来看,它借鉴了一些其他的规范和标准,例如:

  • Emoji:Gitmoji 规范使用 Emoji 表情符号来表示不同类型的提交,这一做法和 Slack、微信等工具中使用 Emoji 表情符号的方式类似。

  • Semantic Versioning:Gitmoji 规范中使用了类似 Semantic Versioning 的方式来表示版本,例如 “:bookmark:” 表示打标签,”:bookmark: v1.0.0” 表示打了一个 v1.0.0 的标签。

  • Conventional Commits:Gitmoji 规范和 Conventional Commits 规范类似,都是使用 commit message 来描述代码库的变化。不过,Gitmoji 规范使用 Emoji 表情符号来表示不同类型的提交,而 Conventional Commits 规范使用文本标识符来表示。

Commit 语法检测

Commitlint ↗ 是一个用于检查 commit message 是否符合规范的工具,可以自定义规则和配置。它支持多种规范,如 Angular 规范、Conventional Commits 规范、ESLint 规范等。

Commitlint ↗ 的作用仅仅是检测 Commit 语法。还需要使用 Git Hook (commit-msg)拦截 git commit 动作以达到强制执行规范的目的。

commit-msg
This hook is invoked by git-commit[1] and git-merge[1], and can be bypassed with the --no-verify option. It takes a single parameter, the name of the file that holds the proposed commit log message. Exiting with a non-zero status causes the command to abort.

The hook is allowed to edit the message file in place, and can be used to normalize the message into some project standard format. It can also be used to refuse the commit after inspecting the message file.

The default commit-msg hook, when enabled, detects duplicate Signed-off-by trailers, and aborts the commit if one is found.

Refenrence: githooks - Hooks used by Git

Husky ↗ 是一个 Git hook 工具,它可以在 Git 执行特定操作时自动触发预定义的脚本。常用于配合 Commitlint 进行 commit message 的校验。与原生的 Git hook 相比,Husky 有以下优点:

  • 易于使用:Husky 提供了简单易用的 API,可以轻松地在项目中添加和配置 Git hook。与原生的 Git hook 相比,Husky 的配置更加直观和简单,不需要手动编写脚本。

  • 跨平台支持:Husky 可以在 Windows、Linux、macOS 等多个平台上运行,而原生的 Git hook 可能会因为操作系统和 shell 的不同而产生兼容性问题。

  • 更强大的功能:Husky 支持多个 Git hook,可以在不同的 Git 操作时自动触发相应的任务。而原生的 Git hook 只支持有限的几个 hook,需要手动编写脚本来实现更复杂的功能。

  • 安全性:Husky 的配置文件存储在项目的 package.json 文件中,这意味着可以将配置文件提交到代码仓库中进行版本控制,保证配置的安全性和一致性。而原生的 Git hook 需要手动将 hook 脚本添加到 .git/hooks 目录中,容易被意外覆盖或删除。

因此,接下来需要做的事情是,安装 Husky,配置 commit-msg 拦截git commit 动作,再安装 Commitlint 对拦截到的 commit 信息进行校验。

安装 Husky

1
2
3
4
5
# npm
npm install husky --save-dev

# pnpm
pnpm add husky --save-dev

使用 Husky 安装 Git Hooks

1
2
3
4
5
# npx 调用 局部命令 husky 
npx husky install

# 直接路径访问局部命令 husky
./node_modules/.bin/husky install
💡 npx 是什么?

npx是一个Node.js命令行工具,它提供了一种方便的方式来运行本地安装的Node.js包中的可执行文件。npx的作用是在不全局安装包的情况下,运行这些包中的命令。

通常情况下,在运行命令行工具时,需要全局安装相关的包和依赖项。但是,这种方式可能会导致一些问题,例如不同版本的包之间的冲突,或者需要手动更新全局安装的包等。npx提供了一个解决方案,可以在不全局安装包的情况下,运行这些包中的命令。

使用npx,可以直接在命令行中指定需要运行的包和命令,npx将会自动查找并运行该包中的命令。例如,可以使用以下命令运行"create-react-app"包中的命令来创建一个新的React应用程序:

npx create-react-app my-app

在这个例子中,npx将在本地查找"create-react-app"包,并运行它中的"create-react-app"命令,然后使用"my-app"作为应用程序的名称创建一个新的React应用程序。

更多 npx 相关信息可参考:Npx | Run a command from a local or remote npm package



添加 prepare 脚本到 package.jsonscripts 中,使得在新环境初始化项目时,自动安装 Git Hooks。

📢 此为可选操作,不做也不影响后续操作,但是推荐执行

1
2
3
4
5
6
7
8
npm pkg set scripts.prepare="husky install"

# 执行以上命令得到的结果是:
{
"scripts": {
+ "prepare": "husky install"
}
}

prepare (since npm@4.0.0)

Runs BEFORE the package is packed
Runs BEFORE the package is published
Runs on local “npm install” without any arguments
Run AFTER prepublish, but BEFORE prepublishOnly
NOTE: If a package being installed through git contains a prepare script, its dependencies and devDependencies will be installed, and the prepare script will be run, before the package is packaged and installed.

Refenrence: How npm handles the “scripts” field

Husky 配置 Hooks 的方式如下

1
2
3
4
5
npx husky add .husky/<git hook> "<command that needs to be executed when the hook is triggered>"

# e.g.
# 将在 `git commit` 执行前触发 `npm test` 命令
npx husky add .husky/pre-commit "npm test"

至此,Git Hooks 的准备工作已经完成,commit-msg 钩子的配置要在 commitlint 安装完成后配置。

安装 Commitlint

@commitlint 是一个由多个相关包组成的集合,可以根据需要安装和配置这些包来实现不同的功能。

@commitlint 的核心包是@commitlint/cli,它提供了命令行工具,用于检查提交信息是否符合规范。@commitlint/cli可以通过命令行参数来指定规范,也可以通过配置文件来指定规范。例如,可以使用@commitlint/config-conventional包来定义一个常规的提交信息规范,然后使用@commitlint/cli来检查提交信息是否符合该规范。

除了@commitlint/cli之外,@commitlint还提供了其他几个相关包,包括:

  • @commitlint/load: 提供了一个函数,用于加载配置文件并解析它们,以便@commitlint/cli可以使用它们进行检查。
  • @commitlint/config-conventional: 提供了一组常见的规范,用于检查常规的Git提交信息格式。
  • @commitlint/config-angular: 提供了一个用于检查Angular项目的提交信息规范。
  • @commitlint/config-lerna-scopes: 提供了一个用于检查Lerna项目的提交信息规范。
  • 更多相关包…

这些包可以根据具体需要进行安装和配置。


📢 根据当前的需求,接下来则安装 @commitlint/cli@commitlint/config-conventional(Conventional Commits 规范)

1
2
3
4
5
# npm
npm install --save-dev @commitlint/config-conventional @commitlint/cli

# pnpm
pnpm add --save-dev @commitlint/config-conventional @commitlint/cli

添加 配置文件

@commitlint/cli 支持以下这些默认的配置文件名:

  • commitlint.config.js
  • .commitlintrc.js
  • .commitlintrc
  • .commitlintrc.json
  • .commitlintrc.yml

为了避免切换模块化语法问题,接下来使用 .commitlintrc.yml 作为配置文件

1
2
3
4
5
# .commitlintrc.yml

# 使用 extends 引用 @commitlint/config-conventional 规范
extends:
- '@commitlint/config-conventional'

更多的配置项参考:Commitlint > Configuration

Test Commitlint-CLI

Husky + Commitlint

使用 Husky 设置 commit-msg 钩子执行 commitlint-cli, 对 git commit 动作提交的信息进行校验。

1
npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

在这个命令中,--no 参数是用来禁用 npx 的默认行为的。

默认情况下,npx 会在运行目标命令之前检查本地是否已经安装了目标命令所在的包,如果没有安装,则会先安装该包,然后再运行目标命令。这种行为通常是有用的,因为它可以确保运行的命令使用的是最新的包版本,并且可以避免不同版本之间的兼容性问题。

但是,在某些情况下,我们可能不想让 npx 自动安装包,而是希望使用本地已经安装的包。在这种情况下,可以使用 --no 参数来禁用 npx 的默认行为,以便直接使用本地安装的包。

在这个具体的命令中,--no 参数用来禁用 npx 自动安装 commitlint 包,而是使用本地已经安装的 commitlint 包。

--edit ${1} 是用来编辑指定文件的第一个参数的提交信息,${1} 代表第一个参数的值,通常是一个文件路径。这个命令的作用是使用本地安装的 commitlint 包来检查指定文件的提交信息是否符合规范,并在编辑器中打开该文件,以便修改提交信息。

Commitlint by hook

半自动编写 Commit

以下是使用 Markdown 表格输出 @commitlint/prompt-cli 和 Commitizen 的信息:

工具名称描述npm周下载量(2023/07/17)
@commitlint/prompt-cli ↗一个命令行交互式工具,用于帮助开发人员规范化提交信息。它使用 commitlint 配置文件中定义的规则来检查提交信息,确保它们符合预定的格式和风格。该工具还提供了一些提示,帮助开发人员更好地理解如何编写符合规则的提交信息。67,802
Commitizen ↗一个命令行交互式工具,用于帮助开发人员规范化提交信息。它使用预定义的提交信息模板来引导开发人员编写符合规则的提交信息,并根据模板中的规则进行验证。与@commitlint/prompt-cli不同的是,Commitizen不检查提交信息是否符合commitlint配置文件中定义的规则,而是依靠模板中的规则来确保提交信息的正确性。此外,Commitizen还提供了一些功能,例如自动填充提交信息,以帮助开发人员更快地编写提交信息。917,033
1
2
3
4
5
# npm
npm add @commitlint/prompt-cli --save-dev

# pnpm
pnpm add @commitlint/prompt-cli --save-dev

Test prompt-cli

版本管理

Node.js 遵循的版本号命名规范是 语义化版本号(SemVer)规范。很多 Node.js 模块和库的版本号也同样如此。

SemVer 规范定义了一个三位数字的版本号,格式为 MAJOR.MINOR.PATCH,其中:

  • MAJOR:主版本号,表示不兼容的 API 变化或重大功能变化。
  • MINOR:次版本号,表示向后兼容的新功能添加。
  • PATCH:补丁版本号,表示向后兼容的 bug 修复。

除了这三位数字之外,SemVer 规范还可以包含一个预发布版本号和一个构建版本号。预发布版本号以连字符 - 开头,构建版本号以加号 + 开头,例如 1.2.3-beta+build.123 表示预发布版本号为 beta,构建版本号为 build.123

预发布版本号可以使用以下标识符:

  • alpha:表示内部测试版本或仍在开发中的不稳定版本,可能会包含较多的 bug,不建议用于生产环境。

  • beta:表示公开测试版本,已经完成了主要功能的开发,但仍需要进行测试和 bug 修复,建议用于测试环境和开发环境。

  • rc:表示候选版本(Release Candidate),已经完成了所有的功能开发和测试,可以用于生产环境,但仍需要进行最后的测试和验证。

需要注意的是,不同的项目可能会有自己的预发布版本号约定,以上标识符仅是语义化版本号规范中常见的预发布版本号标识符。在实际项目中,可以根据项目的特点和需求,自定义预发布版本号标识符。

SemVer Manage

常用命令

以下是常用的几个命令:

  • 补丁(patch)预发布版本
1
2
3
4
5
6
7
8
9
# npm-version
npm version prepatch --preid <preid-1>
# ~ or ~
npm version prepatch --preid=<preid-1>

# standard-version
npx standard-version --release-as patch --prerelease <preid-1>
# ~ or ~
npx standard-version -r patch -p <preid-1>
  • 次(minor)预发布版本
1
2
3
4
5
# npm-version
npm version preminor --preid=<preid-1>

# standard-version
npx standard-version -r minor -p <preid-1>
  • 主(major)预发布版本
1
2
3
4
5
# npm-version
npm version premajor --preid=<preid-1>

# standard-version
npx standard-version -r major -p <preid-1>
  • 基于当前预发布的 preid 自增预发布版号
1
2
3
4
5
# npm-version
npm version prerelease

# standard-version
npx standard-version -p
  • 切换至下一个阶段的 preid
1
2
3
4
5
# npm-version
npm version prerelease --preid=<preid-next>

# standard-version
npx standard-version -p <preid-next>
  • 正式发布
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 如果最初是以 npm version prepatch 开始
# npm-version
npm version patch
# ~ or ~
# standard-version
npx standard-version -r patch

# 如果最初是以 npm version preminor 开始
# npm-version
npm version minor
# ~ or ~
# standard-version
npx standard-version -r minor

# 如果最初是以 npm version premajor 开始
# npm-version
npm version major
# ~ or ~
# standard-version
npx standard-version -r major

例子

下面以发布补丁的预发布版本为例,假定初始版本是 0.0.1

Step-1:更新补丁的 alpha 预发布版本

1
2
3
4
5
6
7
npm version prepatch --preid=alpha
# output: 0.0.2-alpha.0

# standard-version
npx standard-version --release-as patch --prerelease alpha
# ~ or ~
npx standard-version -r patch -p alpha

Step-2:更新补丁的 alpha 预发布版本版号自增

1
2
3
4
5
npm version prerelease
# output: 0.0.2-alpha.1

# standard-version
npx standard-version -p

Step-3:更新补丁的下一个阶段的预发布版本,beta

1
2
3
4
5
6
# 切换预发布版本至 beta
npm version prerelease --preid=beta
# output: 0.0.2-beta.0

# standard-version
npx standard-version -p beta

Step-4:更新补丁的 beta 预发布版本版号自增

1
2
3
4
5
6
# 在beta上,自增预发布版号
npm version prerelease
# output: 0.0.2-beta.1

# standard-version
npx standard-version -p

Step-5:更新补丁的下一个阶段的预发布版本,rc

1
2
3
4
5
6
# 切换预发布版本至 rc
npm version prerelease --preid=rc
# output: 0.0.2-rc.0

# standard-version
npx standard-version -p rc

Step-6:更新补丁的 rc 预发布版本版号自增

1
2
3
4
5
6
# 在rc上,自增预发布版号
npm version prerelease
# output: 0.0.2-rc.1

# standard-version
npx standard-version -p

Step-7: 发布正式版本

1
2
3
4
5
npm version patch
# output: 0.0.2

# standard-version
npx standard-version -r patch

Example for version manage

Npm-Version生命周期

在介绍 conventional-changelog-cli 使用的章节中,它配合了 package.jsonscripts 脚本使用。

1
2
3
4
5
6
# package.json
{
"scripts": {
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
}
}

通过 npm version <patch | minor | major ...> 命令生成 CHANGELOG。

为什么是 version 脚本?

为什么是 npm version 而不是 npm run version

下面将带着这两个疑问拆解 npm-version 的生命周期。


npm version <cmd> 在执行后,按顺序先后执行以下流程:

  1. 执行 preversion 脚本(如果有定义);

  2. 更新 package.json 文件中的版本号;

  3. 执行 version 脚本(如果有定义);

  4. 提交版本更新;

  5. 创建 Git 标签;

  6. 执行 postversion 脚本(如果有定义);

LifeCycle of npm-version

例如,执行 npm version patch 命令会触发以下操作:

1. 执行 preversion 脚本(如果有定义):在执行版本更新操作之前执行 preversion 脚本。例如,如果在 package.json 文件中定义了以下 preversion 脚本:

1
2
3
4
5
{
"scripts": {
"preversion": "npm run lint"
}
}

则在执行 npm version patch 命令时,会先执行 npm run lint 命令,检查代码是否符合规范。

2. 更新 package.json 文件中的版本号npm version patch 命令会将 package.json 文件中的版本号自动加1,并将新版本号写回 package.json 文件中。

3. 执行 version 脚本(如果有定义):在更新版本号之后执行 version 脚本。例如,如果在 package.json 文件中定义了以下 version 脚本:

1
2
3
4
5
{
"scripts": {
"version": "npm run build"
}
}

则在执行 npm version patch 命令时,会执行 npm run build 命令,自动生成构建文件。

4. 提交版本更新npm version patch 命令会自动执行 git addgit commit 命令,将更新后的 package.json 文件提交到 Git 仓库中。提交信息默认为 "v<new-version>",例如,如果新版本号为 1.0.1,则提交信息为 “v1.0.1”。

5. 创建 Git 标签npm version patch 命令会自动执行 git tag 命令,为当前提交创建一个新的 Git 标签。标签名默认为 "v<new-version>",例如,如果新版本号为 1.0.1,则标签名为 “v1.0.1”。

6. 执行 postversion 脚本(如果有定义):在提交版本更新之后执行 postversion 脚本。例如,如果在 package.json 文件中定义了以下 postversion 脚本:

1
2
3
4
5
{
"scripts": {
"postversion": "npm publish"
}
}

则在执行 npm version patch 命令并成功提交版本更新后,会执行 npm publish 命令,将新版本发布到 npm 仓库中。


上面提到了 standard-versionconventional-changelog-cli,它们都被用于生成 CHANGELOG。

在使用 conventional-changelog-cli 时,生成 CHANGELOG 的命令被设置到了 package.json 中的 scripts.version:

1
2
3
4
5
6
# package.json
{
"scripts": {
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
}
}

小结

为什么是 npm version 而不是 npm run version

从上面可以知道,version 脚本的触发,是 npm-version 生命周期的一部分。所以可以通过 npm-version 命令更新版本的同时触发 version 脚本生成 CHANGELOG。

为什么是 version 脚本?

1
2
conventional-changelog -p angular -i CHANGELOG.md -s \
&& git add CHANGELOG.md

这段命令包含了两部分:

  • 生成 CHANGELOG, conventional-changelog -p angular -i CHANGELOG.md -s;

  • 将新版本对应的 CHANGELOG 变动添加到 Git 仓库的暂存区,git add CHANGELOG.md

version 脚本的触发介乎于 “更新 package.json 文件中的版本号” 与 “提交版本更新” 之间。

生成 CHANGELOG 需要知道 新的版号。version 脚本的触发在 “提交版本更新” 之前,所以只要在 version 触发时将变动添加到Git仓库暂存区,“提交版本更新” 的 commit 就可以包含 CHANGELOG 的变动。

Standard-Version的生命周期

在上一节 Npm-version生命周期 中提到了 conventional-changelog-cli,但是没有提到 standard-version。因为 standard-version 有它自己的生命周期,而且在使用 standard-version 做版本号更新和 CHANGELOG 生成时,并不会触发 npm-version 的脚本(preversionversionpostversion

standard-version 的生命周期:

  1. 更新项目版本号;

  2. 生成 CHANGELOG;

  3. 提交版本 commit(包含 package.json的version 和 changelog的变动);

  4. 创建版本的 git-tag

lifecycle of standard-version

📢 注意上图中的这句命令并没有执行,仅仅是提示!

1
Run `git push --follow-tags origin master && npm publish --tag prerelease` to publish

standard-version 的生命周期中触发的脚本

  • prerelease: 在任何事情发生之前执行。 如果 prerelease 脚本返回非零退出代码(process.exit()),版本控制将中止,但对进程没有其他影响。

  • prebump/postbump: 在版本更新之前和之后执行。 如果 prebump 脚本返回一个版本号,将使用它而不是 standard-version 计算的版本。

  • prechangelog/postchangelog: 在生成 CHANGELOG 之前和之后执行。

  • precommit/postcommit: 在提交版本 commit 之前和之后调用。

  • pretag/posttag: 在添加 git-tag 步骤之前和之后调用。

Lifecycle Scripts
standard-version supports lifecycle scripts. These allow you to execute your own supplementary commands during the release. The following hooks are available and execute in the order documented:

  • prerelease: executed before anything happens. If the prerelease script returns a non-zero exit code, versioning will be aborted, but it has no other effect on the process.

  • prebump/postbump: executed before and after the version is bumped. If the prebump script returns a version #, it will be used rather than the version calculated by standard-version.

  • prechangelog/postchangelog: executes before and after the CHANGELOG is generated.

  • precommit/postcommit: called before and after the commit step.

  • pretag/posttag: called before and after the tagging step.

📢 注意:*standard-version 触发的脚本是 strandard-version.scripts.*,而不是 scripts.*。*

小结

standard-version 并非基于 npm-version 实现,它与 npm-version 相互独立。standard-version 有自己的生命周期,与 npm-version 不重合,在 standard-version 工作过程中不会触发 npm-version 生命周期脚本(preversionversionpostversion)。

standard-version 的生命周期中,包含 4 个工作点

  • 更新项目版本号;

  • 生成 CHANGELOG;

  • 提交版本 commit(包含 package.json的version 和 changelog的变动);

  • 创建版本的 git-tag

包含 9 个钩子脚本

  • prerelease

  • prebump/postbump

  • prechangelog/postchangelog

  • precommit/postcommit

  • pretag/posttag

standard-versionnpm-versionpackage.json 中定义脚本的格式不一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# npm-version
{
"scripts": {
"preversion": ""
}
}

# standard-version
{
"standard-version": {
"scripts": {
"prerelease": ""
}
}
}

CHANGELOG自动化

conventional-changelog-cli

conventional-changelog-cli 是一个命令行工具,用于生成符合规范的 changelog。它可以根据项目的 commit message 格式,自动解析 commit 信息,并将其转换为人类可读的 changelog。

这个工具的基本原理是将符合规范的 commit message 按照类型(type)和 scope 等信息进行分类,然后根据分类的结果生成 changelog。

conventional-changelog-cli 支持使用多种预设(preset)来生成 changelog,包括 angularatomcodemirrorconventionalcommitsembereslintexpressjqueryjshint 等。你也可以使用自定义的配置文件来生成 changelog。

以下是 conventional-changelog-cli 的一些常用命令:

  • conventional-changelog: 生成 changelog,默认使用 Angular 规范。

  • conventional-changelog -p [preset]: 生成指定预设的 changelog。

  • conventional-changelog -i [file]: 将 changelog 写入到指定文件中。

  • conventional-changelog -s: 将 changelog 添加到文件的开头而不是结尾。

  • conventional-changelog --release-count [number]: 指定要包括的版本数量。

  • conventional-changelog --config [file]: 使用自定义的配置文件生成 changelog。

通过 conventional-changelog-cli,你可以方便地生成符合规范的 changelog,并且可以根据自己的需要进行自定义配置和预设,以满足项目的需求。

📢 在默认情况下,conventional-changelog-cli 会匹配 featfix 类型的commits,并根据它们生成CHANGELOG


npm install -g conventional-changelog-cli
  cd my-project
  conventional-changelog -p angular -i CHANGELOG.md -s
  

This will not overwrite any previous changelogs. The above generates a changelog based on commits since the last semver tag that matches the pattern of "Feature", "Fix", "Performance Improvement" or "Breaking Changes".


安装

1
2
3
4
5
# npm
npm install conventional-changelog-cli --save-dev

# pnpm
pnpm add conventional-changelog-cli --save-dev

使用

1
npx conventional-changelog -p conventionalcommits -i CHANGELOG.md -s
  • -p conventionalcommit:指定使用 conventionalcommit 规范生成 CHANGELOG 文件。conventionalcommit 是一种常见的规范,适用于大多数项目。

  • -i CHANGELOG.md:指定将生成的 CHANGELOG 文件输出到名为 CHANGELOG.md 的文件中。如果该文件不存在,则会创建它;如果已存在,则会覆盖它。

  • -s:指定生成的 CHANGELOG 文件中是否应包含当前版本之前的所有版本的变更记录。默认情况下,只会生成当前版本的变更记录。

结合 npm version 使用

1
2
3
4
5
6
7
8
9
# package.json
{
"scripts": {
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
}
}

# cli
npm version <version>

具体来说,当您执行 npm version 命令时,会按照以下顺序执行:

  • 执行 scripts.version 脚本,如果已经定义的话。scripts.version 脚本会返回一个字符串,表示新的版本号,如果没有定义 scripts.version 脚本,则使用默认的 SemVer 规范生成版本号。

  • 将新的版本号更新到 package.json 文件中。

  • 自动化执行 Git 操作,包括添加修改的 package.json 和生成的 changelog 文件、提交代码并打 Git tag。

因此执行 npm version <version>的结果是:1)更新 package.jsonversion 字段;2)更新 CHANGELOG;3)生成包含 1、2 的 commit 和 git-tag。

修改 version-commit

默认的 version-commit 是下面这样的:

1
2
3
4
5
commit 1d37dcf6dc685d0a49319d0c2e0a0a272af8fa7a (tag: v3.3.8)
Author: isaaxite <isaacgun@outlook.com>
Date: Tue Jul 25 05:00:36 2023 +0800

3.3.8

显然这样是不符合规范的。下面有 2 个方法可是使之合乎规范。

手动设置

1
2
3
# %s 是版本号的占位符

npm version patch -m "chore: bump version to %s"

配置文件设置

1
2
3
4
5
# .npmrc

commit-hooks=true
tag-version-prefix=v
message="chore: bump version to %s"

配置

conventional-changelog-cli 的 README 中没有太多关于配置的信息,仅仅是引导去查阅 conventional-changelogconventional-changelog-core

从其他的一些参考资料确实有介绍 conventional-changelog-cli 是基于 conventional-changelog-core 开发的。

To fully customize the tool, please checkout conventional-changelog and conventional-changelog-core docs. You can find more details there. Note: config here can work with preset, which is different than options.config in conventional-changelog.

但是,实际上 conventional-changelog 并没有太多关于配置的信息,仅仅是一个类似一个一级引导页的README!

conventional-changelog-core 相对有用一点,会介绍 API 的参数,但是并没有明确那些参数是可以复用到配置文件上的。

使用 conventional-changelog --help 有看到关于配置相关的描述:

-n, --config A filepath of your config script Example of a config script: https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-cli/test/fixtures/config.js

打开的是一个过于简单的页面,并没有注释介绍参数作用,有用的参考信息约等于没有!

1
2
3
4
5
6
7
'use strict'

module.exports = {
writerOpts: {
mainTemplate: '{{commitGroups.[0].commits.[0].type}}{{testContext}}template'
}
}

综合以上,基本可以认识到一个事实:

conventional-changelog-cli 具备配置的能力,但是缺少配置指引,以致配置体验不友好。基本可以认为这个工具的配置能力约等于“无”


本着研究的态度阅读 conventional-changelog-cli 的源码,探索它的配置详情!

通过阅读 conventional-changelog-cli/cli.js 代码,发现以下5个配置项可以从从配置文件中读取:

  • options

  • templateContext

  • gitRawCommitsOpts

  • parserOpts

  • writerOpts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
try {
if (flags.context) {
| templateContext = require(resolve(process.cwd(), flags.context))
}

if (flags.config) {
| config = require(resolve(process.cwd(), flags.config))
options.config = config

if (config.options) {
| options = {
...options,
...config.options,
pkg: {
...options.pkg,
...config.options.pkg
}
}
}
} else {
config = {}
}
} catch (err) {
console.error('Failed to get file. ' + err)
process.exit(1)
}

const gitRawCommitsOpts = {
| ...config.gitRawCommitsOpts
}

const changelogStream = conventionalChangelog(
options,
templateContext,
gitRawCommitsOpts,
| config.parserOpts,
| config.writerOpts
)

在源码中可以知道, 以上 5 个配置项分别读取自不同的2个文件,它们分别是 context 配置文件 和 config 配置文件。

1
2
3
4
5
// context
templateContext = require(resolve(process.cwd(), flags.context))

// config
config = require(resolve(process.cwd(), flags.config))

context 配置文件:

  • templateContext

config 配置文件:

  • options

  • gitRawCommitsOpts

  • parserOpts

  • writerOpts

npx conventional-changelog --help 中关于 context 配置文件 和 config 配置文件的描述

-c, --context A filepath of a json that is used to define template variables

-n, --config A filepath of your config script. Example of a config script: https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-cli/test/fixtures/config.js

结合 --help的描述和配置文件的引入方式(require),可以推断 context 配置文件 和 config 配置文件的内容和语法。

context 配置文件

支持的配置项及其详情参考:conventional-changelog-writer > context

1
2
3
4
5
6
7
8
9
/*
conventional-changelog.context.js

支持的配置项参考:
https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer#context
*/
module.exports = {
// ...
}

使用context 配置文件:

1
npx conventional-changelog --context conventional-changelog.context.js

config 配置文件

支持的4个配置项及其详情参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// conventional-changelog.config.js

module.exports = {
// 参考:https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/git-raw-commits#gitopts
gitRawCommitsOpts: {
// ...
},

// 参考:https://github.com/conventional-changelog-archived-repos/conventional-commits-parser#conventionalcommitsparseroptions
parserOpts: {
// ...
},

// 参考:https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-writer#options
writerOpts: {
// ...
},

// 参考:https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-core#options
options: {
// ...
}
}

使用config 配置文件:

1
npx conventional-changelog --config conventional-changelog.config.js

preset

Standard Version 是一个命令行工具,可用于自动生成符合语义化版本规范的版本标签和 CHANGELOG。它使用 Git 元数据(如提交消息)来确定下一个版本号,然后生成标签和更新日志。

standard-versionconventional-changelog-cli 都是基于 conventional-changelog 实现的工具。

但是有别于 conventional-changelog-cli, standard-version 是明确支持配置文件,并且有较为详细的指引介绍如何配置(Standard Version > configuration)。

Configuration

You can configure standard-version either by:

Placing a standard-version stanza in your package.json (assuming your project is JavaScript).
Creating a ‘.versionrc’, ‘.versionrc.json’ or ‘.versionrc.js’.
If you are using a .versionrc.js your default export must be a configuration object, or a function returning a configuration object.
Any of the command line parameters accepted by standard-version can instead be provided via configuration. Please refer to the conventional-changelog-config-spec for details on available configuration options.

standard-version 配置文件的包含全部设置项的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .versionrc.js

module.exports = {
header: '# Changelog',
types: [
{ type: 'feat', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'chore', hidden: true },
{ type: 'docs', hidden: true },
{ type: 'style', hidden: true },
{ type: 'refactor', hidden: true },
{ type: 'perf', hidden: true },
{ type: 'test', hidden: true }
],
preMajor: false,
commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}',
compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}',
issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}',
userUrlFormat: '{{host}}/{{user}}',
releaseCommitMessageFormat: 'chore(release): {{currentTag}}',
issuePrefixes: [ '#' ]
}

两者都基于相同上游库开发,但是只有 standard-version 支持配置,而且是有别于上面 conventional-changelog-cli 介绍过的配置方式。这是为什么?

抱着这个疑问阅读 standard-version 相关的代码!

1
2
3
4
5
6
7
// standard-version/lib/lifecycles/changelog.js

const changelogStream = conventionalChangelog({
debug: args.verbose && console.info.bind(console, 'conventional-changelog'),
preset: presetLoader(args),
tagPrefix: args.tagPrefix
}, context, { merges: null, path: args.path })

🔬 通过“打印”的方式确认了是 presetLoader(args) 引入了 .versionrc.js 的配置内容

与上面例子有所区别是,在例子的基础上有增了 name 属性:

1
2
3
4
5
{
// ...
name: '/home/isaac/workspace/temp/node_modules/.pnpm/conventional-changelog-conventionalcommits@4.6.3/node_modules/conventional-changelog-conventionalcommits/index.js',
// ...
}

npx conventional-changelog --help 的描述上看,--preset 是指定 commit 规范。而 --preset 的设置值仅仅一个较短字符串,而不是上面探索到的对象形式的值。

-p, --preset Name of the preset you want to use. Must be one of the following: angular, atom, codemirror, conventionalcommits, ember, eslint, express, jquery or jshint

从上面 standard-version 的源码可知道, preset 是对应到前文 conventional-changelog.config.js 中的 options.preset,基于以上信息,进行下面的尝试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// conventional-changelog.config.js

module.exports = {
// ...
options: {
preset: {
name: '/home/isaac/workspace/temp/node_modules/.pnpm/conventional-changelog-conventionalcommits@4.6.3/node_modules/conventional-changelog-conventionalcommits/index.js',
header: '# Changelog',
types: [
{ type: 'feat', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'chore', hidden: true },
{ type: 'docs', hidden: true },
{ type: 'style', hidden: true },
{ type: 'refactor', hidden: true },
{ type: 'perf', hidden: true },
{ type: 'test', hidden: true }
],
preMajor: false,
commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}',
compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}',
issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}',
userUrlFormat: '{{host}}/{{user}}',
releaseCommitMessageFormat: 'chore(release): {{currentTag}}',
issuePrefixes: [ '#' ]
}
}
};

详细设置项参考:conventional-changelog-config-spec

结论是可以的!

但是,并不是全部属性都有效果!下面是几个尝试后得到的结论:

  • name,必选设置,preset 的设置项生效的前提是们需要设置 name 属性。这是测试出来的结果,没有继续深挖!name 属性在两种设置方式下有效:1)如上面文件的;2)name: 'conventional-changelog-conventionalcommits';

  • header,无效。查阅了 standard-version 的源码。关于 header 的实现,是独立与 conventional-changelog 的,所以不生效也正常。

  • types,正常有效的。

  • 其他,正常有效。

    • preMajor
    • commitUrlFormat
    • compareUrlFormat
    • issueUrlFormat
    • userUrlFormat
    • releaseCommitMessageFormat
    • issuePrefixes

小结

通过 preset 配置 conventional-changelog-cli 是从源码中得到的非正道的知识,在 conventional-changelog 的工具集中并没有相关的资料说明可以使用preset通过对象形式值去配置。所以这是一个不推荐在生产项目下使用的功能,是个不被保证的功能。

Standard Version

Standard Version 和 conventional-changelog-cli 都是用于自动生成版本更新和 CHANGELOG 的命令行工具。它们都是基于 conventional-changelog 事先。

Standard Version 除了能够生成 CHANGELOG 之外,还能够自动创建 Git 标签、增加版本号,以及自动推送标签到 Git 仓库等。conventional-changelog-cli 则只是生成 CHANGELOG 文件。

Standard Version 的社区支持度相对来说更高,有较多的用户和贡献者,开发维护更新也更加频繁。而 conventional-changelog-cli 的社区支持度相对较低,开发维护更新也不如 Standard Version 频繁。

安装

1
2
3
4
5
# npm
npm install standard-version --save-dev

# pnpm
pnpm add standard-version --save-dev

使用

1
2
3
4
5
{
"scripts": {
"release": "standard-version"
}
}

Standard Version 是推荐使用它来代替 npm version 进行版本管理的。

Standard Version 将版本管理与 CHANGELOG 结合在一起,在使用 standard-version 更新版本号时,会自动触发 CHANGELOG 的更新。

1
2
3
4
5
6
7
8
# release
npx standard-version -r 0.0.1

npx standard-version -r 0.0.1-0
npx standard-version -r 0.0.1-1

npx standard-version -r 0.0.1-beta.0
npx standard-version -r 0.0.1-beta.1

配置

默认的配置文件名是:.versionrc, .versionrc.json or .versionrc.js

详细设置项参考:conventional-changelog-config-spec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .versionrc.js

module.exports = {
header: '# Changelog',
types: [
{ type: 'feat', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'chore', hidden: true },
{ type: 'docs', hidden: true },
{ type: 'style', hidden: true },
{ type: 'refactor', hidden: true },
{ type: 'perf', hidden: true },
{ type: 'test', hidden: true }
],
preMajor: false,
commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}',
compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}',
issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}',
userUrlFormat: '{{host}}/{{user}}',
releaseCommitMessageFormat: 'chore(release): {{currentTag}}',
issuePrefixes: [ '#' ]
};

工作流

work flow

1. 创建开发分支

1
2
3
git fetch origin main

git checkout -b feat/xxx origin/main

2. Commit 变动

1
2
3
4
5
6
7
8
9
10
# 全手动commit,让commitlint检测
git add .

git commit -m "feat(scope): add a new feat"


# 半自动辅助编辑commit
git add .

npx commit

3. Push开发分支

1
git push origin feat/xxx

4. 合并开发分支

5. 版本管理

切换到主分支,并更新到最新的commit点

1
2
3
git checkout main

git fetch origin main && git pull origin main

创建版本

1
npx standard-version -r patch -p alpha

6. 发布

推送commit 与 git-tag 到远端git仓库

1
git push origin main && git push --tags

发布到 npm

1
2
3
4
5
# 登录
npm login

# 发布
npm publish --tag alpha

附录

Husky支持的 Git hook

Husky 支持大部分 Git hook,以下是 Husky 支持的 Git hook 列表:

  • applypatch-msg:在 Git 执行 git am 命令时触发
  • pre-applypatch:在 Git 执行 git am 命令前触发
  • post-applypatch:在 Git 执行 git am 命令后触发
  • pre-commit:在 Git 执行 git commit 命令前触发
  • prepare-commit-msg:在 Git 执行 git commit 命令前触发,用于编辑提交信息
  • commit-msg:在 Git 执行 git commit 命令后触发,用于验证提交信息
  • post-commit:在 Git 执行 git commit 命令后触发
  • pre-rebase:在 Git 执行 git rebase 命令前触发
  • post-checkout:在 Git 执行 git checkout 命令后触发
  • post-merge:在 Git 执行 git merge 命令后触发
  • pre-push:在 Git 执行 git push 命令前触发
  • pre-receive:在 Git 执行 git push 命令时,服务端接收到数据之前触发
  • update:在 Git 执行 git push 命令时,服务端接收到数据之后触发
  • post-receive:在 Git 执行 git push 命令后触发
  • post-update:在 Git 执行 git push 命令后触发
  • pre-auto-gc:在 Git 执行自动垃圾回收之前触发
  • post-rewrite:在 Git 执行 git filter-branchgit commit --amend 命令后触发
  • sendemail-validate:在 Git 执行 git send-email 命令前触发

以上 Git hook 具体作用可以参考 Git 的官方文档。Husky 可以通过在 package.json 文件的 husky.hooks 中定义相应的命令,来自动触发这些 Git hook。例如,在 husky.hooks 中定义 pre-commit 命令,就可以在每次执行 git commit 命令时自动触发该命令。

post-merge 钩子触发prompt失败

配置 post-merge 钩子,合并开发分支后触发版本更新逻辑。版本管理选择使用 @isubo-org/version,它是prompt工具,选择的方式设定新版号。

配置 post-merge 钩子

1
npx husky add .husky/post-merge  'npm run post-merge'

配置post-merge脚本

1
2
3
"scripts": {
"post-merge": "npx isubo-version"
}

测试结果是:行不通!

合并后确实可以触发脚本,但是完全跳过选择流程

参考