Azure DevOps와 함께 semantic release를 사용한 수동 버전 bump

발행: (2025년 12월 29일 오전 06:43 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

Azure DevOps와 함께하는 수동 버전 증가를 위한 semantic release 커버 이미지

Daniel Marques

semantic-release 패키지(https://github.com/semantic-release/semantic-release)는 프로젝트의 버전 관리와 릴리스 과정을 자동화합니다. Conventional Commits 규격을 따르는 커밋 메시지를 기반으로 다음 버전 번호를 결정하고, 릴리스 노트를 생성하며, 릴리스를 자동으로 배포합니다.

하지만 일부 개발자는 주요 버전과 부 버전을 언제 증가시킬지에 대해 더 많은 제어를 원합니다. JetBrains와 같은 회사는 아래 이미지와 같이 연도를 주요 버전으로, 자동 증가하는 정수를 부 버전으로 사용합니다.

JetBrain 버전 관리 방식

semantic-release는 릴리스 노트 생성기와 같은 다양한 내장 도구를 제공하므로, 이를 계속 사용하면서 버전 증가 로직만 변경하는 것이 흥미롭습니다. 바로 이 점을 이번 포스트에서 보여드리겠습니다.

Source:

Azure DevOps 파이프라인을 사용한 수동 버전 올리기

내 접근 방식은 다음 단계로 semantic-release를 실행하는 Azure DevOps 파이프라인을 만드는 것입니다.

  • 파이프라인은 사용자에게 버전 올리기 유형(major, minor, 또는 patch)과 원하는 버전 번호를 지정하도록 요청합니다.
  • 사용자가 선택을 확인하면, 사용자가 major 또는 minor 버전을 선택한 경우 파이프라인은 승인 상태로 전환됩니다.
  • 승인이 이루어지면 파이프라인은 선택한 버전 올리기 유형에 따라 버전을 증가시킵니다.
  • 파이프라인은 올린 버전이 원하는 버전 번호와 일치하는지 검증합니다.

아래 코드 스니펫은 위 단계들을 포함한 Azure DevOps 파이프라인 YAML을 보여줍니다. 파라미터는 사용자의 버전 올리기 유형(기본값은 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 }}

이게 전부입니다! 이 설정을 통해 커밋 메시지를 신경 쓰지 않고도 프로젝트 버전을 수동으로 올릴 수 있습니다.

다음 스니펫은 semantic‑release 구성 파일(release.config.cjs)을 보여줍니다. 일반적으로 커밋 메시지에 따라 버전을 올리는 플러그인 @semantic-release/commit-analyzer에 대해, 사용자가 선택한 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 플러그인은 새로운 버전이 예상대로 증가했는지 검증합니다. 이는 파이프라인을 동일한 입력으로 두 번째 실행했을 때, 버전 올리기가 원하지 않는 값(예: JetBrains 예시에서 메이저 버전을 다음 연도로 설정)으로 인해 실패하도록 보장합니다. 다음 스니펫에서 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```

```javascript
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"

다음 이미지는 성공적인 빌드를 보여줍니다.

Successful build output

이 게시물에 사용된 코드는 GitHub 저장소에서 확인할 수 있습니다.

Back to Blog

관련 글

더 보기 »