Assigning meaningful version numbers to pipeline runs is a critical practice in Continuous Integration (CI) for ensuring smooth traceability. Azure DevOps provides several tokens for use in the ‘name’ field of your pipeline file, enabling customizable versioning. However, for scenarios requiring more intricate versioning logic, the run number can be dynamically updated using the UpdateBuildNumber logging command.
Various versioning strategies exist, and though this isn’t an exhaustive list, it includes some practical snippets. These can be used as is, combined, or tweaked to better fit your workflow, offering a solid starting point for efficient version management.
Default
Default pattern for the name field is $(Date:yyyyMMdd).$(Rev:r), which results in a version like 20240324.1
# name field purposely omitted
steps:
- powershell: Write-Host 'Hello, versioning'
Partial version hardcoded
Major and minor version parts are updated manually, but the patch version increments automatically with every build.
name: 1.2.$(Rev:r)
steps:
- powershell: Write-Host 'Hello, versioning'
$(Rev:r) is a special variable format that only works in the build number field. A new counter is created or reused based on the rest of the version specified.
Example runs:
- 1.2.$(Rev:r) ➞ 1.2.1 (counter for 1.2 created at 1)
- 1.2.$(Rev:r) ➞ 1.2.2 (counter for 1.2 now at 2)
- 3.4.$(Rev:r) ➞ 3.4.1 (counter for 3.4 created at 1)
- 1.2.$(Rev:r) ➞ 1.2.3 (counter for 1.2 now at 3)
Version file contents
Version is taken from a file in the repository, for example version.txt, and used as-is.
steps:
- task: PowerShell@2
displayName: Set run number
inputs:
targetType: inline
script: |
$versionFromFile = Get-Content 'version.txt' -Raw
Write-Host "##vso[build.updatebuildnumber]$versionFromFile"
version.txt file example content:
1.2.3
Commit hash
A counter is created for each commit hash, for example b895c37c91f49b77428a64f6777d8ab6bce59d86 becomes b895c37c.1.
variables:
- name: commitHashCounter
value: $[counter(format('commit-hash-{0}', variables['Build.SourceVersion']), 1)]
steps:
- task: PowerShell@2
displayName: Set run number
inputs:
targetType: inline
script: |
$preferredHashLength = 8
$commitHash = '$(Build.SourceVersion)'
$shortHash = $commitHash.Substring(0, [Math]::Min($commitHash.Length, $preferredHashLength)) # shorten hash to preferred length if possible
Write-Host "##vso[build.updatebuildnumber]$shortHash.$(commitHashCounter)"
Branch name
Each branch gets its own counter and a version-safe name is used as a prefix, for example feat/my-branch becomes feat-my-branch.1.
variables:
- name: branchCounter
value: $[counter(format('branch-{0}', variables['Build.SourceBranch']), 1)]
steps:
- task: PowerShell@2
displayName: Set run number
inputs:
targetType: inline
script: |
$branchName = '$(Build.SourceBranch)'
$safeBranchName = ($branchName -replace '^refs/heads|[^A-Za-z0-9]+', '-').Trim('-')
Write-Host "##vso[build.updatebuildnumber]$safeBranchName.$(branchCounter)"
External pipeline resource
Version is inherited from another pipeline run with an appended counter, for example, other-pipeline-run.1 #2. A unique counter is created for each run number of the referenced pipeline. This approach is beneficial when managing separate build and deploy pipelines, allowing the deploy pipeline to inherit the build pipeline’s version while accounting for multiple deployment attempts of the same build.
resources:
pipelines:
- pipeline: alias-of-my-other-pipeline
source: MyOtherPipelineName
variables:
- name: pipelineResourceCounter
value: $[counter(format('pipeline-resource-{0}', variables['resources.pipeline.alias-of-my-other-pipeline.runname']), 1)]
steps:
- task: PowerShell@2
displayName: Set run number
inputs:
targetType: inline
script: |
$artifactVersion = '$(resources.pipeline.alias-of-my-other-pipeline.runname)'
Write-Host "##vso[build.updatebuildnumber]$artifactVersion #$(pipelineResourceCounter)"
If you have any questions or if you are interested in getting firsthand experience from us, feel free to contact us.