使用 Azure DevOps 的 semantic release 手动进行版本 bump

发布: (2025年12月29日 GMT+8 05:43)
6 min read
原文: Dev.to

Source: Dev.to

Cover image for Manual version bumps using semantic release with Azure DevOps

Daniel Marques

semantic-release 包(https://github.com/semantic-release/semantic-release)自动化项目的版本管理和发布流程。它根据遵循 Conventional Commits 规范的提交信息来确定下一个版本号,生成发布说明,并自动发布。

然而,一些开发者更倾向于自行控制何时递增主版本号和次版本号。像 JetBrains 这样的公司会使用年份作为主版本号,使用自动递增的整数作为次版本号,如下图所示。

JetBrain versioning

由于 semantic-release 提供了诸如发布说明生成器等多种内置工具,继续使用它并仅更改版本递增逻辑是很有吸引力的。这正是我将在本文中展示的内容。

Source:

Azure DevOps pipeline for Manual bumping

我的做法是创建一个 Azure DevOps pipeline,运行 semantic-release,其步骤如下:

  • pipeline 会提示用户指定 bump 类型(majorminorpatch)以及期望的版本号。
  • 用户确认选择后,如果用户选择了 majorminor,pipeline 将进入审批状态。
  • 获得批准后,pipeline 按所选的 bump 类型递增版本。
  • pipeline 会验证 bump 是否与期望的版本号一致。

下面的代码片段展示了包含上述步骤的 Azure DevOps pipeline YAML。parameters 用于请求用户的 bump 类型(默认 patch)和目标版本。它们的值被设为环境变量,在 semantic‑release 配置中使用。

parameters:
  - name: bumpType
    type: string
    default: "patch"
    values:
      - major
      - minor
      - patch
  - name: bumpNumber
    type: string
    default: "0"

pool:
  vmImage: ubuntu-latest

jobs:
  - job: approval
    pool: server
    steps:
      - task: ManualValidation@1
        # …
        condition: ne('${{ parameters.bumpType }}', 'patch')

  - job: create_tag
    dependsOn: approval
    steps:
      # …
      - script: |
          npx semantic-release
        displayName: Run semantic-release setting ${{ parameters.bumpType }} version to ${{ parameters.bumpNumber }}
        env:
          SEMANTIC_RELEASE_BUMP_TYPE: ${{ parameters.bumpType }}
          SEMANTIC_RELEASE_BUMP_NUMBER: ${{ parameters.bumpNumber }}

就是这样!有了这个设置,你可以手动 bump 项目的版本,而无需担心提交信息。

下面的片段展示了 semantic‑release 的配置文件(release.config.cjs)。对于插件 @semantic-release/commit-analyzer(它通常会根据提交信息 bump 版本),我们将其设置为始终按照用户选择的 bump‑type 进行递增。

// file release.config.cjs
module.exports = {
  // …
  plugins: [
    // …
    [
      '@semantic-release/commit-analyzer',
      {
        releaseRules: [
          { release: process.env.SEMANTIC_RELEASE_BUMP_TYPE }
        ]
      }
    ],
    './verify-release.js'
  ]
};

verify-release.js 插件会验证新版本是否如预期递增。这确保如果 pipeline 使用相同的输入再次执行时,会因 bump 产生不期望的值而失败(例如在 JetBrains 示例中将 major 版本设置为下一年)。下面的代码片段展示了 verify-release.js

// file verify-release.js
module.exports = {
  verifyRelease: async (pluginConfig, context) => {
    const { lastRelease = {}, nextRelease = {}, logger = console } = context;
    const bumpType = process.env.SEMANTIC_RELEASE_BUMP_TYPE;
    const bumpNumber = process.env.SEMANTIC_RELEASE_BUMP_NUMBER;

    logger.log('Verifying expected release.');
    if (!bumpType) {
      logger.log('SEMANTIC_RELEASE_BUMP_TYPE not set — skipping version verification.');
      return;
    }
    if (bumpType == 'patch') {
      logger.log('Bump type set to patch. Nothing to verify.');
      return;
    }

    const actual = nextRelease && nextRelease.version;
    const match = actual.match(/^(\d+)\.(\d+)\.\d+$/);

    if (!match) {
      throw new Error(`Invalid tag format: ${lastRelease}`);
    }

    const actualMajor = Number(match[1]);
    const actualMinor = Number(match[2]);

    if (bumpType == 'major' && actualMajor != bumpNumber) {
      logger.error(`Major version mismatch: expected ${bumpNumber} but will publish ${actualMajor}`);
      throw new Error(`Version verification failed: expected major version ${bumpNumber}, got ${actualMajor}`);
    }
    if (bumpType == 'minor' && actualMinor != bumpNumber) {
      logger.error(`Minor versi
on mismatch: expected ${bumpNumber} but will publish ${actualMinor}`);
      throw new Error(`Version verification failed: expected minor version ${bumpNumber}, got ${actualMinor}`);
    }
  }
};

下图展示了一个将 major 版本提升的流水线执行示例。

Pipeline execution – major version bump

构建新版本

一旦发布准备就绪,您可以开始构建应用程序。此示例使用用 Go 编写的简单 Hello World CLI。

管道的步骤如下:

  1. 检出带标签的代码
  2. 获取当前提交的基于标签的描述 —— 如果提交没有标签,则基于最新标签创建描述性版本。
  3. 将 Azure DevOps 构建号设置为上一步的描述
  4. 生成 CLI 可执行文件 并将其发布为构建产物。

Azure Pipelines YAML

variables:
  appName: hello-world
  buildDir: build

steps:
  - checkout: self
    fetchTags: true
    fetchDepth: 0

  - script: |
      export VERSION=$(git describe --tags)
      echo "##vso[build.updatebuildnumber]${VERSION}"
    displayName: "Set build number"

  - task: GoTool@0
    inputs:
      version: "1.25"

  - script: |
      mkdir -p $(buildDir)
      go build -o $(buildDir)/$(appName) ./cmd
    displayName: "Build Go binary"

  - script: |
      cd $(buildDir)
      zip $(appName)-$(Build.BuildNumber).zip $(appName)
    displayName: "Create ZIP with version"

  - task: PublishBuildArtifacts@1
    inputs:
      PathtoPublish: "$(buildDir)"
      ArtifactName: "release"
      publishLocation: "Container"

以下图片展示了成功的构建。

成功的构建输出

本文使用的代码已在 GitHub 仓库中提供。

Back to Blog

相关文章

阅读更多 »