DTeam 团队日志

Doer、Delivery、Dream

团队敏捷实践 —— 使用 semantic-release 自动管理发布版本

冯宇 Posted at — May 11, 2020 阅读

前言

在之前的分享中,我们团队已经成功运用了 Gitlab CI(参考耗时三天,我将 Gitlab CI 由 shell executor 平滑迁移 Docker 环境),并且已经结构化提交 git commit 记录(参考规范化 git commit 信息)。我们希望更进一步,给用户交付的时候同时整理出一份完整的更新日志,尽管按照之前规范化 git commit 信息的内容,可以手工生成一份 Release Note 交付给用户,但是我们希望结合 CI 更加自动化,自动管理发布版本,自动生成更新日志,因此我们引入了semantic-release进一步自动化管理我们的发布流程。

semantic-release 概述

有关semantic-release的详细介绍可以阅读官方文档,这里只做一些概述性的总结。和之前在规范化 git commit 信息一文介绍的standard-version相比,semantic-release更适合在 CI 环境中运行,它自带支持各种 git server 的认证支持,如 Github,Gitlab,Bitbucket 等等,此外,还支持插件,以便完成其他后续的流程步骤,比如自动生成 git tag 和 release note 之后再 push 回中央仓库,自动发布 npm 包等等。

semantic-release 会根据规范化的 commit 信息生成发布日志,默认使用 angular 规则。其他规则可以配置插件完成。

semantic-release 大致的工作流如下:

由 CI 自动执行之后的效果就像这样,在 Git tag 页面可以看到 tag 信息,同时包含更新记录:

tag页面

如果启用了@semantic-release/git插件,还会将生成的CHANGELOG.md 反向 push 回中央仓库:

CHANGELOG出现在中央仓库

默认的branches配置如下:

['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]

代表默认情况下 push 到X.Y.x, master, next, next-major, beta, alpha这几个分支才会触发自动发布流程,并且只有 featfix 提交才会触发版本升级,版本号按照语义化版本规则自动生成。即:

第一次使用 semantic-release 发布会生成1.0.0版本,同时,semantic-release 会兼顾到旧的发布版本,如果之前有过 git tag,则会在旧的 tag 基础之上再做语义化版本控制。

这里演示下实际效果:

关于 semantic-release 详细的工作流程,建议阅读官方文档: Workflow configuration

我们的敏捷实践

经过评估之后,我们团队对目前的工作流稍微进行了调整,在不大变动团队原本习惯的开发流程的基础上,做了一下调整,并且 semantic-release 的默认配置也能很好的适配我们目前的分支模型:

同时,为了让 commit 信息尽可能的好看,减少不必要的 Merge from 提交记录,我们使用 rebase 的方式合并代码,参考以下步骤:

最后,在项目工程中添加.releaserc配置如下:

{
  "plugins": [
    [
      "@semantic-release/commit-analyzer",
      {
        "preset": "conventionalcommits"
      }
    ],
    [
      "@semantic-release/release-notes-generator",
      {
        "preset": "conventionalcommits"
      }
    ],
    "@semantic-release/changelog",
    "@semantic-release/gitlab",
    "@semantic-release/git"
  ]
}

完成 .gitlab-ci.yml 配置如下(仅部分关键的配置片段):

# 添加了 lint 过程用于检测 commitlint 结果
# 添加了 release 过程用于自动化产生 git tag 和 CHANGELOG.md
stages:
  - lint
  - build
  - test
  - release
  - deploy

commitlint:
  stage: lint
  image: node:lts
  script: |
    npm install -g @commitlint/cli @commitlint/config-conventional
    if [ "${CI_COMMIT_BEFORE_SHA}" = "0000000000000000000000000000000000000000" ]; then
      echo "commitlint from HEAD^"
      npx commitlint -x @commitlint/config-conventional -f HEAD^
    else
      echo "commitlint from ${CI_COMMIT_BEFORE_SHA}"
      npx commitlint -x @commitlint/config-conventional -f "${CI_COMMIT_BEFORE_SHA}"
    fi
  dependencies: []
  tags:
    - docker

build: ...

test: ...

release:
  stage: release
  image: node:lts
  script:
    - npm install -g semantic-release @semantic-release/gitlab @semantic-release/changelog conventional-changelog-conventionalcommits @semantic-release/git
    - npx semantic-release
  dependencies: []
  # 仅在中央仓库的分支发生提交时才触发 release 流程
  only:
    - branches@upstream_path/upstream_project
  tags:
    - docker

deploy: ...

小结

至此,我们完成了通过 CI 自动管理版本号和发布日志的需求,以后面向用户交付的时候,直接根据CHANGELOG.md的内容整理下就可以了,大大节省了人力,同时,还留下了发布痕迹,方便追溯历史版本。

另外,需要注意的是上述的配置并不会修改源码部分的版本号配置内容(如build.gradlepackage.json等),如果需要自动管理这些地方的版本,与 git tag 版本保持一致,可以引入@semantic-release/exec插件,自己写脚本,通过脚本自动化修改这些地方的版本号。

还需要注意的是 semantic-release 默认产生的 commit 记录为了避免不必要的 CI 流程,会在 commit 记录加上[skip ci](见上面的截图)来跳过 CI,如果你的流水线需要由 git tag 触发,可以配置@semantic-release/git插件,自定义 commit 记录,去掉[skip ci]


相关文章