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: PowerShell@2 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: PowerShell@2 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.