AzureDevOps Build/Release Pipeline - get git commit message (Build title)? - azure-devops

I have a webhook task that runs after a deploy on my release pipeline, currently it just pushes a message to say a new version has been deployed, but I'd like to include the git commit message in this as well to show exactly what has been deployed. I'm not quite sure how to retrieve this, but I'm hoping it's possible as the build is initially triggered from a git push and moreover the Build title is named with this message as per this screenshot:

This is somewhat tricky since the Release Pipeline typically does not
have Git access like the Build Pipeline does. To add to this, it is not
possible to share variables across pipelines, which would have been an
easy solution.
This is how I've done it:
First, Add a Bash script task to your Build Pipeline that exports your
last commit message to a file:
CHANGES=`git log -1 --pretty=%B`
mkdir -p $(Build.artifactStagingDirectory)/exported
echo "$CHANGES" > $(Build.artifactStagingDirectory)/exported/CHANGES
Make sure this folder is published as an artifact in your build using
the Publish build artifacts task:
Path to publish: $(Build.ArtifactStagingDirectory)/exported
Artifact name: exported
Second, add a Bash script task to your Release Pipeline that picks up
these changes from the file and stores them in a variable:
CHANGES=$(cat $(System.DefaultWorkingDirectory)/Development/exported/CHANGES)
echo "##vso[task.setvariable variable=commitComment]$CHANGES"
The last Git change is now available for use in your Build Pipeline as the variable $commitComment.
Note: your exact paths above may vary.

Ok, I've worked out a way, not sure if it's the best way so let me know if it can be done differently...
I've used a Powershell Task in the Release pipeline which queries the Azure REST API and calls into Git, as follows:
$webClient = New-Object Net.WebClient
$token = "Bearer $env:SYSTEM_ACCESSTOKEN"
$headers = #{ Authorization = $token }
$baseUrl = "https://dev.azure.com/<your company>/<your project>/_apis/git/repositories/<your repo Id>/commits"
$request = "$baseUrl/$env:RELEASE_ARTIFACTS_<your repo name>_SOURCEVERSION"
Write-Host "Request: $request"
$response = Invoke-WebRequest -Uri $request -Headers $headers
$json = ($response | ConvertFrom-Json)
$comment = $json.comment
Write-Host "Response: $comment"
Write-Host "##vso[task.setvariable variable=commitComment;]$comment"
To find out the values for the parameters I've tokenised above, follow this guide:
https://learn.microsoft.com/en-us/azure/devops/pipelines/release/variables?view=azure-devops&tabs=powershell#view-the-current-values-of-all-variables
This writes to a custom pipeline variable I've created called "commitComment", which I then use in a marketplace task I found to generate a discord webhook request.
Alternatively, you could just call that directly from Powershell.
Hope this helps anyone wanting to do the same..

Updated version: The json response contains not only the last commit, but a collection of the last 100 commits. You would need to access the first commit in the collection (ordered by date DESC). Also, all <your_custom_values> can be retrieved dynamically, to improve reusability:
$webClient = New-Object Net.WebClient
$token = "Bearer $env:SYSTEM_ACCESSTOKEN"
$headers = #{ Authorization = $token }
$devOpsUrl = "$(System.TeamFoundationCollectionUri)"
$projectName = "$(System.TeamProject)"
$repoId = "$(Build.Repository.Id)"
$repoName = "$(Build.Repository.Name)"
$baseUrl = "$devOpsUrl$projectName/_apis/git/repositories/$repoId/commits"
$request = "$baseUrl/$env:RELEASE_ARTIFACTS_$repoName_SOURCEVERSION"
Write-Host "Request: $request"
$response = Invoke-WebRequest -Uri $request -Headers $headers
$json = ($response | ConvertFrom-Json)
$lastCommit = $json.value[0]
Write-Host "Last Commit: $lastCommit"
$comment = $lastCommit.comment
Write-Host "Comment: $comment"
Write-Host "##vso[task.setvariable variable=CommitMessage;]$comment"

Related

Is it possible to get a release pipeline creation date on Azure Devops/TFS?

I was wondering if it is possible to find the exact creation date as a predefined variable for a Release in Azure Devops. In release pipelines it can be seen as an actual column labeled "Created" (along with "Releases" and "Stages" to the left and right of "Created" respectively) - so I know that the data is stored somewhere.
The only variable I have been able to find is Release.Deployment.StartTime - which is the time the release deployment begins, which can be hours or even days after Release Creation, so not quite what I want.
Is there a way to do this? I attached a screenshot to show what I am trying to get.
What about $(SYSTEM_PIPELINESTARTTIME) ?
I like this task which dumps all the variables for you. I have it at the start of all my dev pipelines: https://marketplace.visualstudio.com/items?itemName=dutchworkz.DisplayAllVariables
You can also do it with powershell if you don't have access to install extensions:
Get-ChildItem Env: | Format-Table -Wrap -AutoSize
If none of the variable work you can also publish your own variable with a Powershell task. It will be about 5-10 seconds later than the real stage execution time:
$DateTime = (Get-Date).ToString("yyyyMMdd_HHmm")
Write-Host "##vso[task.setvariable variable=DateTime;]$DateTime"
You always can run a rest api call to see release details. Here is the example of a stage step with powershell:
$user = ""
$token = "$(System.AccessToken)"
$teamProject = "$(System.TeamProject)"
$releaseId = "$(Release.ReleaseId)"
$orgUrl = "$(System.CollectionUri)"
$orgUrlrel = $orgUrl -replace "dev", "vsrm.dev"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uriGetRelease = "$orgUrlrel/$teamProject/_apis/release/releases/$releaseId"+"?api-version=5.1"
$resultStatus = Invoke-RestMethod -Uri $uriGetRelease -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
Write-Host "Created date:" $resultStatus.createdOn
Additionally, you have to enable access to the token:

Setting Git Tag from Azure Devops Build Pipeline on Complete

I'm trying to set a tag with the current version number determined by GitVersion on the GIT commit at the end of a successful build. Feels like I can't be the first one to be doing this, but I'm struggling to find something that works.
Azure Devops Pipeline has a feature in Get Sources to "Tag sources" On Success. I've set this and set to a variable that is set by one of the Agent Tasks I have (GitVersion)
I can see in the debug logs that this variable is getting set by the GitVersion component that I've added to the pipeline.
2019-12-06T20:54:20.2390794Z ##[debug]Processed: ##vso[task.setvariable variable=GitVersion.MajorMinorPatch;]2.98.0
However if I leave it just as this, I get a tag created as "v$(GitVersion.MajorMinorPatch)" which means that at the time that the tag is being created that that variable no longer exists.
The Tag Format help tooltip says
"Tag format could be a combination of user-defined or pre-defined variables that have a scope of "All". For example: '$(Build.DefinitionName)$(Build.DefinitionVersion)$(Build.BuildId)$(Build.BuildNumber)$(My.Variable)'"
So I guess the problem is that this variable created during the pipeline does not have a scope of All.
I then tried adding a pipeline variable to the pipeline of "GitVersion.MajorMinorPatch" with the hope that this was at the right scope and hoping that when the "task.setvariable" command is run, that this will set the variable value of this higher scoped variable.
However in this case I just got a tag "v" created.
So I am a bit stuck. Somehow I need to be able to dynamically create or set a variable at scope ALL with the value I want to tag here.
I'd be really grateful for any ideas on this.
If you are doing a yaml pipeline, you can add the following steps
- checkout: self
persistCredentials: true
## Rest of pipeline ##
- script: |
git tag $(GitVersion.NugetVersionV2)
git push origin $(GitVersion.NugetVersionV2)
workingDirectory: $(Build.SourcesDirectory)
The persistCredentials allows the token to be automatically passed to other git commands. Note the assignment of workingDirectory, otherwise I had an error that the location was not a git repository.
For an annotated tag rather than lightweight tag, the syntax would look like this...
- script: |
git tag -a <tagname> -m <message>
git push origin <tagname>
To get a user/date against it you need to set the user name/email as well e.g.
- script: |
git config --global user.name "BuildService"
git config --global user.email "autobuild#fabrikam.com"
git tag -a <tagname> -m <message>
git push origin <tagname>
For this to work, the Project Collection Build Server account (not the Project Build Service Accounts group) needs to be allocated the Contribute permission for the Repositories
Expanding on the excellent answer from Paul Hatcher, I'd like to add that for me the account was called Project Collection Build Service in Azure DevOps Server 2019. This also seems to be in line with the current Microsoft documentation.
Sorry for the answer, my reputation does not yet suffice to comment.
I can see in the debug logs that this variable is getting set by the
GitVersion component that I've added to the pipeline.
The variable GitVersion.MajorMinorPatch you saw from the log is a step-level variable, which means its life cycle is only start from the current GitVersion task.
As the definition you are referring, it scope must to all. This means is must be a global variable. For example, the predefined variables that the system default have, and the customized variables which specified in the Variables tab.
Based on the GitVersion task compile and work logic, in fact, the GitVersion.MajorMinorPatch value is generated and stored as current build's build number:
So, the most convenient method for you to tag the GitVersion.MajorMinorPatch value to repos is using $(Build.BuildNumber):
v$(Build.BuildNumber)
And this is my result:
Update:
To add the GitVersion.MajorMinorPatch which generated by the GitVersion task into Variables, please apply below scripts into PowerShell task:
$connectionToken="{PAT Token}"
$urlget = "https://dev.azure.com/{org}/{project}/_apis/build/definitions/$(System.DefinitionId)?api-version=5.1"
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$getdef = Invoke-RestMethod -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET -ContentType application/json -Uri $urlget
Write-Host Pipeline = $($getdef | ConvertTo-Json -Depth 100)
$bvalue=#"
{
"value": "$(GitVersion.MajorMinorPatch)"
}
"#
$getdef.variables | add-member -Name "GitVersion.MajorMinorPatch" -value (Convertfrom-Json $bvalue) -MemberType NoteProperty -Force -PassThru
$getdef = $getdef | ConvertTo-Json -Depth 100
$getdef | clip
$urlput = "https://dev.azure.com/{org}/{project}/_apis/build/definitions/$(System.DefinitionId)?api-version=5.1"
$putdef = Invoke-RestMethod -Uri $urlput -Method PUT -Body $getdef -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
As I mentioned previously, I still don't think it is available to specify $(GitVersion.MajorMinorPatch) in Tag format.
Still strongly suggest you by calling $(Build.BuildNumber) to tag the $(GitVersion.MajorMinorPatch) value
- pwsh: |
# Construct PAT authentication header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "user",$env:SYSTEM_ACCESSTOKEN)))
$headers = #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$url="$(System.CollectionUri)/$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.ID)/annotatedtags?api-version=5.0-preview.1"
$body = #{name = "$(GitVersion.MajorMinorPatch)"
message = "automatically added"
taggedObject = #{
objectId = "$(Build.SourceVersion)"
}
} | ConvertTo-Json
Invoke-RestMethod -Uri $url -Headers $headers -Method Post -ContentType "application/json" -Body ($body)
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: 'Add tag'

Store result of Azure CLI task into release variable

I have a release pipeline with multiple jobs.
On the first agent job there is an Azure CLI task that retrieves the keys of a storage account on azure.
The command it executes is :
az storage account keys list --account-name "$(diagnosticsStorageAccountName)" --resource-group "$(resourceGroup)"
What I want to do is store the result of this command and utilize it in a task that is running under a deployment group job.
I've already looked into these resource :
Set Output Variable in Azure CLI task on VSTS
How to modify Azure DevOps release definition variable from a release task?
I've tried the first one but I didn't get it working.
I didn't bothered with the second because it seems way to hacky.
Is there any way do achieve this that isn't hacky ?
The output values didn't get stored properly.
The output of az storage account keys list --account-name "$(diagnosticsStorageAccountName)" --resource-group "$(resourceGroup)"is spread over multiple lines when you use the following syntax:
echo "##vso[task.setvariable variable=testvar;]%myvar%"
So one of the problems was that only the first line of the JSON array was being stored into the variable.
I solved this problem in the following way:
keys=`az storage account keys list --account-name "$(diagnosticsStorageAccountName)" --resource-group "$(resourceGroup)"`
taskvariable="##vso[task.setvariable variable=_[tempVariable];]"
echo $taskvariable$keys
According to documentation echo "##vso[task.setvariable variable=testvar output=true;]%myvar% should make the variable available for the whole release. Unfortunately I had no luck with this.
I overcame this using a Powershell task under the same Agent Job (Ubuntu 16.0) :
$url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.1"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $(System.AccessToken)"
}
#Parsing JSON string from previous task
$keys = $(#"
$(_tempVariable)
"# | ConvertFrom-Json)
# Assignment of variable value
$pipeline.variables.[variableName].value = $keys[0].value
####****************** update the modified object **************************
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $(System.AccessToken)"}
write-host "=========================================================="
Write-host "The value of Variable '[variableName]' is updated to" $updatedef.variables.[variableName].value
write-host "=========================================================="
Please note that in order to get this working there are a couple of things you need to do.
First you need to allow access to the OAuth token on the Agent Job.
On top of that you need to give the "Project Collection Build Service".
Click on security on the release and click on the "Project Collection Build Service" user.
Change the values for the "Edit release" and "Manage release" to allow and save the changes.

Automatically Export Build and Release definitions using Powershell or DEVOPS tasks

Have a requirement to automatically export specific Azure DEVOPS Build/Release definitions. I know the names of the definitions required. The process would run weekly to capture the information. I know the export can be done manually but want to automate process. Hoping Powershell script can be used.
Thanks
Joe
If you want to export the build/release definition automatically, you'd better use Powershell task with Rest API. But if this, it is not enough for just know the build definition name.
Refer to these docs: get build definition and get release definition. You can see that definitionid is necessary. In fact, this definitionid is very easy to get. Just click the relevant pipeline you want to export, the definitionid will display in URL:
To export the definition, you can use the follow script in powershell:
$headers = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$projectsUrl = "https://dev.azure.com/{org}/{project}/_apis/build/definitions/{build definitionid}?api-version=5.1"
$result = Invoke-RestMethod -Uri $projectsUrl -Method Get -Headers $headers
$filename=$result.name+".json"
$filePath="D:\"
$file=$filePath+$filename
$result | ConvertTo-Json | Out-File -FilePath $file
In this script, I specified the build name as the file name($filename=$result.name+".json"), and also, convert the result content as JSON to make the local file more readable:
Similarly, to get the release definition, just change the url as get release difinition:
$headers = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$projectsUrl = "https://vsrm.dev.azure.com/{org}/{project}/_apis/release/definitions/{definitionId}?api-version=5.1"
$result = Invoke-RestMethod -Uri $projectsUrl -Method Get -Headers $headers
$filename=$result.name+".json"
$filePath="D:\"
$file=$filePath+$filename
$result | ConvertTo-Json | Out-File -FilePath $file
Note: While use #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }, you'd enable Allow scripts to access the OAuth token to make the environment variable available during build pipeline.
In addition, as what you want is capture the information weekly, you can Schedule the pipeline which has these export task:
Now, these export pipeline will run and export the definition weekly.
You'll be looking at the az pipelines release and az pipelines build commands from Azure DevOps CLI
Commands Reference
Extension Reference

How to set the Description of an Azure DevOps Release via script?

In Azure DevOps I'm trying to set the release description via PowerShell / CMD in order to have a dynamic description of my releases based on the input of the artifacts from the build step.
I've tried setting the release variables via powershell like:
Write-Host "##vso[task.setvariable variable=release.releasedescription;]bar"
Write-Host "##vso[task.setvariable variable=RELEASE_RELEASEDESCRIPTION;]bar"
But that didn't work and the description field remains always empty.
Is there any tweak / setting that would help achieve this behavior?
What you tried to do is just to set the environment variable that contains the release description data and not set the "real" release description, so after the release finished the description not changed.
If you want to set the release description during the release you can try to do it with Azure DevOps Rest API - Update Release.
So add a PowerShell task that executes the Rest API with Invoke-RestMethod, get the current release with GET method and then update the release with PUT, in the body change the description to the new one.
You could do this too:
- bash: |
echo "Updating pipeline job Run description"
echo "##vso[build.updatebuildnumber]$(Build.BuildNumber) $(App_Name)"
displayName: "Set pipeline job Run description for Azure DevOps console"
For anyone who simply wants to set the name of an Azure Pipelines run, you can find the description here.
TLDR: Set the top-level name: attribute.
Here is the PowerShell script to set release description in DevOps. Before the stage that need approval, add a PowerShell task to invoke REST API to change the release description. Please use your own orgName, projectName, PAT and modify the release description.
$url = https://vsrm.dev.azure.com/<orgName>/<ProjectName>/_apis/release/releases/$(Release.ReleaseId)?api-version=6.0
$token="PAT"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$head = #{ Authorization =" Basic $base64AuthInfo" }
$pipeline = Invoke-RestMethod -Uri $url -Headers $head -Method Get
$Pipeline.description = "<Modify the release description>"
$body = $Pipeline | ConvertTo-Json -Depth 100
$url2=https://vsrm.dev.azure.com/<orgName>/<ProjectName>/_apis/release/releases/$(Release.ReleaseId)?api-version=6.0
$resp = Invoke-RestMethod -Uri $url2 -Method Put -Headers $head -Body $body -ContentType application/json