Azure DevOps와 함께 semantic release를 사용한 수동 버전 bump
Source: Dev.to

semantic-release 패키지(https://github.com/semantic-release/semantic-release)는 프로젝트의 버전 관리와 릴리스 과정을 자동화합니다. Conventional Commits 규격을 따르는 커밋 메시지를 기반으로 다음 버전 번호를 결정하고, 릴리스 노트를 생성하며, 릴리스를 자동으로 배포합니다.
하지만 일부 개발자는 주요 버전과 부 버전을 언제 증가시킬지에 대해 더 많은 제어를 원합니다. JetBrains와 같은 회사는 아래 이미지와 같이 연도를 주요 버전으로, 자동 증가하는 정수를 부 버전으로 사용합니다.

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 버전을 올린 파이프라인 실행 예시를 보여줍니다.

새로운 버전 빌드
릴리스가 준비되면 애플리케이션 빌드를 시작할 수 있습니다. 이 예제에서는 Go로 작성된 간단한 Hello World CLI를 사용합니다.
파이프라인 단계는 다음과 같습니다:
- 태그와 함께 코드 체크아웃
- 현재 커밋에 대한 태그 기반 설명 가져오기 – 커밋에 태그가 없으면 최신 태그를 기반으로 설명 버전을 생성합니다.
- Azure DevOps 빌드 번호 설정 – 이전 단계에서 얻은 설명을 사용합니다.
- 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 저장소에서 확인할 수 있습니다.
