Azure DevOps Pipelines: Manual Tagging

In this week’s post, we are going to cover manually tagging instead of using the tagging feature built into Azure DevOps. This post will be using a sample Azure DevOps project built over the last few weeks of posts. If you want to see how this project has gotten to this point see the following posts.

Getting Started with Azure DevOps
Pipeline Creation in Azure DevOps
Azure DevOps Publish Artifacts for ASP.NET Core
Azure DevOps Pipelines: Multiple Jobs in YAML
Azure DevOps Pipelines: Reusable YAML
Azure DevOps Pipelines: Use YAML Across Repos
Azure DevOps Pipelines: Conditionals in YAML
Azure DevOps Pipelines: Naming and Tagging

 

 

Why?

Tags give you information about the state of your repo when an event happens, a build for our case. This can be super useful especially when you need a place to branch for a hotfix, for example. The automatic tagging covered in my Azure DevOps Pipelines: Naming and Tagging post is the way to go if it works and it has for about 95% of my projects. I have a couple of projects where the automatic tagging would not work for some reason. Since I couldn’t work out why Azure DevOps wouldn’t tag I ended up having to add a job to the Pipeline to perform the tagging.

Permissions

To perform this manual tagging the account used in our Pipeline will need to be giving contribute permission to our repo so that it will be able to push the tag. Use the gear in the lower left to open the Project Setting page.

Select the Repositories option and then click on the specific repo you would like to change the settings for, Playground is the repo we are using in the example. Note that this setting can also be changed using the top-level Git repositories option if you want to change the permission for all of your repos.

On the Security tab under Users looks for the user than has Build Service in the name and select it. When the user is selected it will show their permissions to the right of the users. Find the Contribute option and change its value to Allow.

YAML Changes

As a quick reminder, the YAML for this project currently has 3 jobs. Two web application builds (WebApp1, WebApp2) and the third job is there to show how to use job dependencies (DependentJob). I’m going to skip showing the YAML for these existing jobs, but that if you need the full existing YAML it can be found in posts linked at the top.

Since we already have multiple jobs in our Pipeline we are going to add the tagging code as a new job. This will easily allow us to only tag when all the other jobs have run successfully. The following is the full YAML for the new job.

- job: TagSources
  displayName: 'Tag Sources'
  pool:
    vmImage: 'ubuntu-latest'

  dependsOn:
  - WebApp1
  - WebApp2
  - DependentJob
 
  steps:
  - checkout: self
    persistCredentials: true
    clean: true
    fetchDepth: 1

  - task: [email protected]
    inputs:
      targetType: 'inline'
      script: |
        $env:GIT_REDIRECT_STDERR` = '2>&1'
        $tag = "manual_$(Build.BuildNumber)".replace(' ', '_')
        git tag $tag
        Write-Host "Successfully created tag $tag" 

        git push --tags
         Write-Host "Successfully pushed tag $tag"     

      failOnStderr: false

First off you see that this job depends on our existing three jobs to complete successfully before this new job will run.

dependsOn: 
- WebApp1 
- WebApp2 
- DependentJob

Starting in the Steps section you will see a checkout step that is normally handled automatically by the job, but in this case, we need to use the persistCredential option so the job will still be authed and allow us to push to our git repo. The self option is used to signify the current repo/branch. See the official Checkout docs for more information.

- checkout: self
  persistCredentials: true
  clean: true
  fetchDepth: 1

The final bit of the job is the PowerShell task that performs the actual tagging and push. I found most of this on stackoverflow and/or in a GitHub issue, but it has been a while so I don’t have the links handy. The StdErr stuff was to work around some git output that didn’t affect the tagging but was causing the job to be marked as failed. Other than that it is using the standard git commands to tag and push.

- task: [email protected]
  inputs:
    targetType: 'inline'
    script: |
      $env:GIT_REDIRECT_STDERR` = '2>&1'
      $tag = "manual_$(Build.BuildNumber)".replace(' ', '_')
      git tag $tag
      Write-Host "Successfully created tag $tag" 

      git push --tags
       Write-Host "Successfully pushed tag $tag"     

    failOnStderr: false

Wrapping Up

I honestly hope none of you have to use this. It was a huge pain to work out. It is also to work around some sort of issue with Azure DevOps built-in tagging support. To be fair I can see where in more complex Pipelines you might need a level of flexibility that the built-in tagging couldn’t provide and this would be your only option.


Also published on Medium.

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.