Does anyone know here how to update an Artifact's properties? We've had a project assigned to us to move all of our artifact drops from one location to another - This is because our file server is about to die (We use On-Prem Azure DevOps Services)
I've wrote a PowerShell script already that updates what's needed for builds/releases and that works great.
So I wrote another PowerShell script to update what's needed within the Artifacts properties and then uses an "PUT" call to replace the info but there's an issue....
Invoke-RestMethod : {"count":1,"value":{"Message":"The requested resource does not support http method 'PUT'."}}
Does anyone know if this is possible/knows how to do it?
Here's my script;
Example of an endpoint;
https://dev.azure.com/{organization}/{project}/_apis/build/builds/{buildId}/artifacts?api-version=5.1
$artefacts = Get-Content ".\artefacts.txt"
$oldDataURL = "\\rdtstore01.main.rdt.co.uk\Horizon\Drops"
$newDataURL = "\\main.rdt.co.uk\shares\Horizon\Drops"
foreach ($line in $artefacts)
{
$var = Invoke-RestMethod -Uri $line -UseDefaultCredentials -Method Get
### Updte Data line ###
$data = $var.value.resource.data
$dataNew = $data -replace [RegEx]::Escape($oldDataURL), $newDataURL
$var.value.resource.data = #{}
$var.value.resource.data += #{"value" = $dataNew}
$result = Invoke-RestMethod -Uri $line -Method Put -ContentType "application/json" -UseDefaultCredentials -Body (ConvertTo-Json $var -Depth 10)
}
Use Rest API to update Artifacts properties is not support right now. We only provide below methods for working with artifacts produced by builds.
Sorry, there is not any workaround, you may have to use build task to publish artifacts again.
Related
How do you manage building from branches when using Azure DevOps Classic Build Pipelines and TFVC?
I believe that the only viable option is to copy the build pipeline with a new name and update the source code mapping to point to the new TFVC branch.
I see the ADO web UI provides the option to clone an individual build definition, yet as I have over 200+ build pipelines to clone whenever I branch is there a more efficient way to do this? Or is the only option to write a custom tool to leverage the ADO REST Api?
Since you need to clone pipelines in batches, using scripts to run the Rest API will be a reasonable method. As far as I know, there is no easy way out of the box other than this.
You could try the following PowerShell Script Sample:
$DefinitionIds = "PipelineIDs" #InPut All Pipelineids(e.g. "324,323,xxx" )
$DefinitionId = $DefinitionIds.split(",");
$token = "PAT Token"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
foreach ($i in $DefinitionId)
{
echo $i
$url="https://dev.azure.com/{OrganizationName}/{ProjectName}/_apis/build/definitions/$($i)?api-version=6.0"
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Get -ContentType application/json
Write-Host "$($response | ConvertTo-Json -Depth 100)"
$response.repository.properties.tfvcMapping= '{"mappings":[{"serverPath":"$/TFVCBranchName","mappingType":"map","localPath":"\\"}]}' # ServerPath is the Branch name
$response.repository.name = "TFVCRepoName" #Repo Source Name
$response.name = "Pipeline $i Clone" # Cloned PipelineName
echo $response.name
$url1= "https://dev.azure.com/{OrganizationName}/{ProjectName}/_apis/build/definitions?api-version=6.0"
$json = #($response) | ConvertTo-Json -Depth 100
$response1 = Invoke-RestMethod -Uri $url1 -Headers #{Authorization = "Basic $token"} -Method Post -Body $json -ContentType application/json
}
Here are the Two Rest APIs used in the Script:
Definitions - Get
Definitions - Create
Result:
The cloned Pipeline will be set to the new TFVC branch and Build definition name.
I have a simple pipeline, in which gatling load script executes:
My pipeline
After the script is completed, we see the script execution time:
Execution time
My first question is: how can I extract value of execution time and compare it with previous execution (my script executes every night), and if execution time in last time is more than in previous time, I want to get notification.
Also, after execution generates report: Report
And my next question is: how can I open the generated report directly in Azure (or at least send it by mail as an attachment to a standard notification from Azure)?
You can use Build timeline API to get the execution time of a specific task.
I add a few more lines of scripts to my previous answer. Please check below scripts.
I added script $result.records | where {$_.name -eq "MyTaskName"} to filter the task records by its name. Note: You need to define a unique Display name for your powershell task.
$url = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.TriggeredBy.BuildId)/timeline?api-version=5.1"
echo $url
$result = Invoke-RestMethod -Uri $url -Headers #{authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} -ContentType "application/json" -Method get
# filter the task's records by name
$taskResult = $result.records | where {$_.name -eq "MyTaskName"}
# calculate the totaltime of the newest build
$time = [datetime]$taskResult.finishTime - [datetime]$taskResult.startTime
$thisTaskTime= $time.TotalMinutes
# get the last build's Id
$lasturl = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds?definitions=$(Build.TriggeredBy.DefinitionId)&resultFilter=succeeded&`$top=2&api-version=5.1"
$buildResult =Invoke-RestMethod -Uri $lasturl -Headers #{authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} -ContentType "application/json" -Method get
#extract last buildId
$lastBuildId = $buildResult.value[1].id
#get the timeline of the last build
$timeUrl = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds/$($lastBuildId)/timeline?api-version=5.1"
$lastResult =Invoke-RestMethod -Uri $timeUrl -Headers #{authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} -ContentType "application/json" -Method get
#Caculate the totaltime of the last build task
# filter the task's records by name
$lastTaskResult = $lastResult.records | where {$_.name -eq "TaskName"}
$LastTime = [datetime]$lastTaskResult.finishTime - [datetime]$lastTaskResult.startTime
$lastTaskTime= $LastTime.TotalMinutes
#Store the result to varialbe isLonger
if($thisTaskTime -ge $lastTaskTime){ echo "##vso[task.setvariable variable=isLonger]True" }
If you want to use the azure default notification when the task execution time is greater then previous time. You can add another script task to the end of your pipeline to purposely fail your pipeline, if the time is greater. And then set up a build fails notification for your project.
if($(isLonger) -eq "True")
{
exit 1
}
For your second question, I am afraid you cannot view the report directly in azure devops.
You can use copy files task to copy out the generated report and use publish build artifacts task to upload the report to azure devops server, where you can download directly from your build history.
Copy Files task
Publish build artifact task
Then you can download the report file from the build UI.
Go to Builds under Pipelines--> Select your pipeline--> Click lastest build from the History
There are other ways to upload the report file to the build besides Publish build artifact task by using statement ##vso[task.addattachment]value, ##vso[task.uploadfile]local file path. For example run below statement in a script task to add the report file to the build.
##vso[task.addattachment type=myattachmenttype;name=myattachmentname;]$(System.DefaultWorkingDirectory)\reportTempFolder\index.html
Please check here for more information.
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
Requirements
My requirement is that for my Azure devops release pipeline I want to tag a specific commit with an annotated tag which contains the build number and the date (which is auto-set on an annotated tag).
Proposed solution
My solution to this is to use a the Azure Powershell pipeline task, the one shown here:
The task (ignore what's in the script box right now) will use the Azure Subscription that I have set in order to authenticate towards the Azure DevOps REST API. I have successfully been able to perform the task I want using a personal access token (PAT) but this is not stable long-term for a whole team and I want to use our Azure Subscription.
The problem
My problem is that I'm not sure how to use the authentication of the Azure Subscription correctly. I seem to get some data using Get-AzureRmContext (see current code below) and then I found a GitHub issue which seems to do sort of the same thing. The code gets some kind of OAuth token but using the code below, Azure still returns to me that I need to sign in, so I assume it's not the correct token. I don't understand how things hatch into each other.
Note that my subscription should have all the permissions it needs to do what I want.
Code so far:
Function Get-AccessToken($tenantId) {
$cache = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared
$cacheItem = $cache.ReadItems() | Where-Object { $_.TenantId -eq $tenantId } | Select-Object -First 1
return $cacheItem.AccessToken
}
$context = Get-AzureRmContext
$uri = "https://dev.azure.com/<my_org>/<my_area>/_apis/git/repositories/<project_sha>/annotatedtags?api-version=5.0-preview.1"
$token = Get-AccessToken $context.tenantID
$body = #"
{
"taggedObject": {
"objectId": "$(BUILD.SOURCEVERSION)"
},
"name": "D-$(Build.BuildNumber)",
"message": "dummy"
}
"#
$header = #{"Authorization" = "Bearer" + $token}
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body -Headers $header
Any help is greatly appreciated!
There is the example for the build tasks: Use a PowerShell script to customize your build pipeline
You have to enable access to token (option Allow Scripts to Access OAuth Token)
Then use it in your script. Script from the example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
What is the easiest way to get key rotation to work for azure storage accounts from a AzureDevOps relase task? The current plan is to re-generate the old key after release to invalidate it, and have a fresh key that can be used on next deployment. But to get that to work it seems like I at least need to store the name of the key to use in a release variable.
I had a look at he logging tasks (https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md), but that only changes the value in the current release and does not modify the release definition.
You can use the REST API (Definitions - Update) to update the value of the release definition variable from a release task.
Go to the Agent Phase and select Allow Scripts to Access OAuth Token. See Use the OAuth token to access the REST API
Grant Project Collection Build Service (xxx) account the edit
release pipeline permission. (Select the release pipeline --> ... --> Security --> Edit release definition set to Allow)
Add a PowerShell task in your release pipeline
Run inline script: (Update the value of variable v1030 in below sample)
$url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
# Update an existing variable named v1030 to its new value 1035
$pipeline.variables.v1030.value = "1035"
####****************** 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 $env:SYSTEM_ACCESSTOKEN"}
write-host "=========================================================="
Write-host "The value of Varialbe 'v1030' is updated to" $updatedef.variables.v1030.value
write-host "=========================================================="
Here is a much cleaner and better solution that also allows for multiple builds being triggered simultaneously.
https://tsuyoshiushio.medium.com/how-to-pass-variables-with-pipeline-trigger-in-azure-pipeline-5771c5f18f91
Essentially your triggering build produces artifacts that your triggered build reads and turns into variables.
Still not at all great, but better than nothing and better than REST calls setting static global variable groups.
The other answer above talks about how to update Release pipelines.
If you would like to update a Build Pipeline's variables, here is how you do that:
Edit build pipeline
Go to the Agent Phase and select Allow Scripts to Access OAuth Token. See Use the OAuth token to access the REST API
Go to Manage Security -> Users -> Select Project Collection Build Service (YOUR TEAM NAME HERE)
Change "Edit Build Definitions" to Allow
Now add a powershell stage - 2.x - inline script called Update variables.
Script inline contents:
$api_version='5.0-preview.6'
$url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$(System.DefinitionId)?api-version=${api_version}"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
# Update variables as desired here:
$pipeline.variables.mavenBuildVersionPatch.value = "2401"
####****************** 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 $env:SYSTEM_ACCESSTOKEN"}
write-host "=========================================================="
Write-host "The value of Variable mavenBuildVersionPatch is updated to" $updatedef.variables.mavenBuildVersionPatch.value
write-host "=========================================================="
Take note of the API version in this script is 5.0-preview.6.
If your version of Azure Devops is newer, you may need to update this in the future.
Save build pipeline.
Now when you run job, after the job completes this powershell stage, this variable will be set.
Important: If you want to update a variable then make the updated variable for other pipeline stages, then you do it with a powershell stage with the following inline script:
$mavenBuildVersionPatch = [int]"$(mavenBuildVersionPatch)"
$mavenBuildVersionPatch = $mavenBuildVersionPatch + 1
Write-Host "##vso[task.setvariable variable=mavenBuildVersionPatch;]$mavenBuildVersionPatch"
This example would take our existing patch number and increment it by 1.
This does not save the variable at the end of the job, you still need to do that with another powershell script if desired.