azure-devopsazure-pipelinesincrementversioningazure-pipelines-yaml

Increment Azure Pipelines version number with commits


I have an Azure DevOps pipeline that references two repos:

The idea is that I should be able to make simple config changes and re-deploy without changing the application's version number (since the code hasn't changed). However, I still want to be able to see in the version number that the config changed between runs.

As a result, I'm thinking of using a version number in the following format:

{major}.{minor}.{codeVersion}.{configVersion}

... with the following constraints:

Note: I understand that running the pipeline twice in quick succession would result in the same version number for both runs. This is acceptable since there were no changes to either repo in between.

As an example, I might expect to see a bunch of pipeline runs with the following names:

I've had a look at the counter function, but it doesn't seem to do what I need. My first attempt was this:

name: '$(Build.DefinitionName)-$(major).$(minor).$(codeVersion).$(configVersion)'

variables:
  - major: 0
  - minor: 1
  - codeVersion:   $[counter(format('{0}.{1}', variables['major'], variables['minor']), 0)]
  - configVersion: $[counter(format('{0}.{1}.{2}', variables['major'], variables['minor'], variables['codeVersion']), 0)]

Unfortunately, with this code the codeVersion value always changed on every run even if I made no commits to the code repo. Then, as a result, the configVersion value was always zero.

I've tried a few variations of the above where I tried referencing the $(Build.SourceVersion) variable to get the git commit ID but I haven't been able to find a working solution yet.

The fundamental issue seems to be that the counter function increments when the supplied values haven't changed, whereas I want it to increment when the commit ID of the code repo has changed.

Edit: Fixed typo


Solution

  • You can configure the pipeline to use the GitVersion tool combining with the counter function to automatically generate the expected version number.

    1. Install the GitTools extension to your Azure DevOps organization. It provides the pipeline tasks to install and execute the GitVersion tool for semantic versioning.

    2. In the root of your application code repository, add the GitVersion.yml file referencing the sample below.

      # GitVersion.yml
      
      mode: mainline
      tag-prefix: '[vV]?'
      assembly-informational-format: '{Major}.{Minor}.{Patch}'
      major-version-bump-message: '\+semver:\s?(major)'
      minor-version-bump-message: '\+semver:\s?(minor)'
      patch-version-bump-message: '\+semver:\s?(code|app)'
      no-bump-message: '\+semver:\s?(none|skip)'
      commit-message-incrementing: Enabled
      update-build-number: false
      
      • The {major} is the {major} in your version number.
      • The {minor} is the {minor} in your version number.
      • The {Patch} is the {codeVersion} in your version number.
    3. In the root of your application code repository, add the pipeline main YAML file referencing the sample below.

      # azure-pipelines.yml
      
      # Set the CI trigger.
      trigger:
        branches:
          include:
          - main
      
      # Set the environment config repository as a repository resource.
      # And enable resource trigger.
      resources:
        repositories:
        - repository: config
          type: git
          name: envConfig
          ref: main
          trigger:
            branches:
              include:
              - main
      
      # Generate the part "{configVersion}" of the app version number.
      variables:
        configVersion: $[ counter(resources.repositories.self.version, 0) ]
      
      steps:
      - checkout: self
        fetchDepth: 0
      
      - task: gitversion/setup@3
        displayName: 'Install GitVersion'
        inputs:
          versionSpec: '5.x'
          preferLatestVersion: true
      
      # Generate the part "{major}.{minor}.{codeVersion}" of the app version number.
      # The task sets the variable "$(GitVersion.FullSemVer)" to pass the generated value.
      - task: gitversion/execute@3
        displayName: 'Generate Version'
      
      # Combine the generated values to get the full app version number.
      # Update the pipeline build/run number with the full app version number.
      - bash: |
          echo "##vso[task.setvariable variable=APP_VERSION;]$(GitVersion.FullSemVer).$(configVersion)"
          echo "##vso[build.updatebuildnumber]$(GitVersion.FullSemVer).$(configVersion)"
        displayName: 'Set App Version'
      
      - bash: |
          echo "APP_VERSION = $(APP_VERSION)"
        displayName: 'Print App Version'
      
      . . .
      
    4. In the application code repository, create the tag "v0.1.0.0" to the latest commit (see "Create tags from the Commits view").

    5. Use above azure-pipelines.yml file to create a pipeline for the application code repository.


    With above configurations:

    enter image description here


    EDIT:

    Try to configure the pipeline like as below.

    trigger:
      branches:
        include:
        - main
    
    resources:
      repositories:
      - repository: config
        type: git
        name: envConfig
        ref: main
        trigger:
          branches:
            include:
            - main
    
    jobs:
    - ${{ if notIn(variables['Build.Reason'], 'Manual') }}:
      - job: build
        variables:
          configVersion: $[ counter(resources.repositories.self.version, 0) ]
        steps:
        - checkout: self
          fetchDepth: 0
    
        - task: gitversion/setup@3
          displayName: 'Install GitVersion'
          inputs:
            versionSpec: '5.x'
            preferLatestVersion: true
    
        - task: gitversion/execute@3
          displayName: 'Generate Version'
    
        - bash: |
            echo "##vso[task.setvariable variable=APP_VERSION;]$(GitVersion.FullSemVer).$(configVersion)"
            echo "##vso[build.updatebuildnumber]$(GitVersion.FullSemVer).$(configVersion)"
          displayName: 'Set App Version'
    
        - bash: |
            echo "APP_VERSION = $(APP_VERSION)"
          displayName: 'Print App Version'
    
        . . .
    
    - ${{ else }}:
      - job: noUpdate
        steps:
        - script: |
            echo "This run is not automatically triggered by any new updates."
            echo "Skip all the build steps. Version number will not be updated."
    

    With above configurations, if the pipeline is triggered by manual (Build.Reason = Manual), the whole build job will not run, the number of configVersion also will not increase, and the noUpdate gets run.

    In the condition expression "${{ if notIn(xxxx) }}", you can add more than one items. For example, "${{ if notIn(variables['Build.Reason'], 'Manual', 'Schedule') }}", the build job will not run when the pipeline is triggered by manual or schedule (Build.Reason = Schedule). See the documentation "Expressions".

    The available values of Build.Reason are listed in the image below. You also can see the documentation "Use predefined variables".

    enter image description here