Azure pipeline, build task names,  .Net Assembly versions and container tags

Azure pipeline, build task names, .Net Assembly versions and container tags

I use Azure DevOps (AD) to manage continuous integration and continuous deployment pipelines. As with all software the way in which features work can change in new releases as it develops and evolves. The build pipelines in AD are now created using YAML files. In my build tasks I like to generate the version number using the standard Major/Minor versions and a incremented build number. I then use this to name the build job and to version the output of the build, I use .Net so this becomes the assembly version. The following solution all stems from an attempt to tag a docker image in the build pipeline for which I kept receiving the following error:

##[error]invalid argument "*/easylab:$(verionNumber)" for "-t, --tag" flag: invalid reference format

This then led to some research and some trail and error to come to the following solution.

The Version

In AD before YAML, the builds where created using a UI and the version was generated using a variable with a template like version = 1.0.0.$(Rev:r). The variable $(version) could then be used elsewhere in the pipeline. Now in YAML the $(Rev:r) variable is only available for the name property of the task and cannot be used to generate a version number in the same way as using the UI. To generate a version number in YAML a counter needs to be used whilst creating variables in the pipeline itself:

variables:
  version.MajorMinor: '1.0.0' 
  version.Revision: $[counter(variables['version.MajorMinor'], 0)]
  versionNumber: '$(version.MajorMinor).$(version.Revision)'

The $(versionNumber) can now be used else where in the pipeline.

Build task names

I like to include the version number in the task name so you can easily identify the version created by the build. In YAML pipeline the name property is set before any variables are calculated, so it isn't possible to set the name using the $(versionNumber). To change the name of the build while it is running a powershell task needs to be added to the pipeline:

    - task: PowerShell@2
      displayName: Name the build
      inputs:
        targetType: 'inline'
        script: |
          [string] $buildName = "$(versionNumber)"
          Write-Host "Setting the name of the build to '$buildName'."
          Write-Host "##vso[build.updatebuildnumber]$buildName"

Assembly Version

To version a .Net assembly the $(versionNumber) needs to be added to the dotnet publish commandline. It is not possible to pass arguments to a Docker task if the command is buildandpush, so the pipeline has to contain separate build and push tasks. In the Docker build task the arguments property includes the version=$(versionNumber):

    - task: Docker@2
      inputs:
        ...
        command: 'build'
        Dockerfile: '$(Build.SourcesDirectory)/Dockerfile'
        arguments: '--build-arg version=$(versionNumber)'

To use the $(versionNumber), to stamp the assembly, the Dockerfile referenced by the task needs to be updated to accept the argument ARG version. This is then included in the RUN dotnet command as the /p:Version=${version} switch:

FROM build AS publish
ARG version  #define the argument
RUN dotnet publish "EasyLab.UI.csproj" -c Release /p:Version=${version} -o /app/publish

Container Tags

The build creates a docker image that will be hosted as a Application Service on Azure. The docker image will be stored in a repository, so it is usual to tag the image with a unique identifier. Of course the $(versionNumber) is ideal for this purpose. The Docker task has been split into separate build and push tasks, so that the push can identify the image the tags need to be set in each Docker task in the pipeline:

    - task: Docker@2
      inputs:
        ...
        command: 'build'
        tags: $(versionNumber)

    - task: Docker@2
      inputs:
        ...
        command: 'push'
        tags: $(versionNumber)

This post builds on this blog post that discusses customer version numbers in Azure by Daniel Schroeder and a StackOverflow post on setting a .Net Core assembly version with AD and a Dockerfile. I hope you find this post useful, I am afraid I can't share the source code at this time as the development is on going.