Post Method - Changing a Nested Value - rest

I am trying to change a value - specifically a variable - of one of my TFS 2017 builds. To my understanding, Patch is not supported at all. I can successfully queue a build with the Post method and I am trying to use the same command change a value as well.
When I run the Get method, I have:
*A bunch of text*
"variables": {
"system.debug": {
"value": "false",
"allowOverride": true
},
"BuildVersion": {
"value": "ValueIWantToChange"
}
},
*A bunch of text*
I need to change the Build Version and everything else will stay the same. My body in Postman looks like:
{
"Variables":
{
"BuildVersion":
{
"value": NewValue
}
}
}
When I run this in Postman, I get this error:
"Value cannot be null.\r\nParameter name: definition.Repository"
Could anyone tell me where I am going wrong or if this is possible using another method?

Seems you want to update the build definition base on you description.
To update the build definition with the REST API you need to use PUT method, please see Definitions - Update Definition for details.
Get the build definition first:
GET http://server:8080/tfs/DefaultCollection/ScrumProject/_apis/build/definitions/6?api-version=3.2
Copy all the json response from the first step as the request body,
then change the value of the specific variable which you want to be
modified.
PUT http://SERVER:8080/tfs/DefaultCollection/ScrumProject/_apis/build/definitions/6?api-version=3.2
Content-Type: application/json
Note that you need to provide the latest revision in request body:
UPDATE:
You can also use PowerShell by calling the REST API to update the specific variable value, just try below sample: (the variable name is lctest in below sample, you just need to replace it with your own variable name.)
Param(
[string]$collectionurl = "http://server:8080/tfs/DefaultCollection",
[string]$project = "ProjectName",
[string]$definitionid = "6",
[string]$user = "username",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#Get build definition
$defurl = "$collectionurl/$project/_apis/build/definitions/$($definitionid)?api-version=3.2"
$definition = Invoke-RestMethod -Uri $defurl -Method Get -UseDefaultCredential -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
#Set new value for the specific variable
$definition.variables.lctest.value = "1.0.0.4"
$json = #($definition) | ConvertTo-Json -Depth 99
#Update the definition
$updatedef = Invoke-RestMethod -Uri $defurl -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host $definition.variables.lctest.value

I figured out my problem awhile back and forgot to update. My initial task was to get the API for octopus so this is the long version. If youre only interested in the REST commands, refer to the last section of code. Just wanted to add the rest in for extra context.
#Create a folder
if(test-Path C:\Test){}
else{
new-item -path "C:\" -name "Test" -ItemType "directory"}
$encodedPAT = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$TFSAPIKeyForAutomatedBuild"))
$GetURI = "$MyURI"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $encodedPAT")
[string]$Global:ChangeVersion = [version]$OctopusParameters["Octopus.Action[Deploy Package].Package.NuGetPackageVersion"]
write-host $ChangeVersion
$GetBuildresponse = Invoke-RestMethod -Method Get -header $headers -ContentType "application/json" -Uri $GetUri
write-host $GetBuildResponse
$y = convertTo-json $GetBuildresponse -depth 99 | Out-file -FilePath "C:\test\FromPostmanCopy.json"
$z = (get-content "C:\test\FromPostmanCopy.json") | select-string -pattern '(?<=value": "2.)(.*)(?=")' | % { $_.Matches} | % { $_.value }
Write-Host $z
$Content = (Get-Content "C:\Test\FromPostmanCopy.json")
$content -replace "2.$z", $changeVersion | out-file "C:\Test\FromPostmanCopy.json"
$Content = (Get-Content "C:\Test\FromPostmanCopy.json")
$Buildresponse = Invoke-RestMethod -URI $GetURI -Method Put -header $headers -Body $content -ContentType application/json

Related

Update Azure Devops Build Pipeline Variable with Rest API

I have an Azure Devops YAML based Build (Not Release) Pipeline. I have defined a variable called Department. My Requirement is that this variable to be updated at the end of the build using the rest API. I'm using this code.
How to modify Azure DevOps release definition variable from a release task?
The API call works fine. But I'm not sure whether this is the correct API to call. The Department will change for each build. According to the output HTTP method put is not supported.
Note: I have actually defined 5 variables including Department, Department being the last one. When the API is called it only outputs first 3 variables only.
$Department = getDepartment.ps1
$url = "https://dev.azure.com/xxx/xxx/_apis/pipelines/$(System.DefinitionId)/runs?api-version=6.0-preview.1"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$pipeline.variables.Department.value = $Department
$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 'Department' is updated to $( $updatedef.variables.Department.value)"
write-host "=========================================================="
The Department will change for each build. According to the output HTTP method put is not supported.
According to the document Pipelines:
It does not provide a method for update pipeline with PUT.
To resolve this issue, you still need use the REST API Build Definitions - Update:
PUT https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=6.0
The code sample:
$url = "https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=6.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$pipeline.variables.Test.value = "$Department"
####****************** 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 'Test' is updated to" $updatedef.variables.Test.value
The test result:
When you start the pipeline using the API, you can add the values of the parameters that should be different from the default values, to the payload of the call. So you're not updating the definition, but just the value of the variables for that instance of the pipeline run.
Payload
$JSON = #"
{
"definition": {
"id":"207"
},
"parameters": "{ \"ENVIRONMENT\":\"$($config.testEnvironmentName)\", \"API_CLIENT_SECRET\":\"$($config.testEnvironmentApiClientSecret)\" }"
}
"#
Note that the 'parameters' property has a value as an escaped json string.
This is the API that I use to start the pipeline.
/_apis/build/builds?api-version=7.1-preview
Use a 'POST' method and send the json as the body of the request (content-type application/json).

Invoke-RestMethod from PowerShellScript doesn't work but work from commandline

I am trying to invoke a rest method from powershell script to get git changes from azure repo. When i run the whole process one by one command it works but when i try to run the whole script by writing a powershell script it doesn't work as expected giving empty output. can anyone tell what could be the problem here
$url = "https://dev.azure.com/<Org_Name>/<Project_Name>/_apis/git/repositories/<RepoID>/commits/$(Build.SourceVersion)/changes?api-version=5.1"
$userName = "Username"
$password = "<PAT>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName,$password)))
$result = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $base64AuthInfo"} -Method GET
Write-Host $result
$changesFolders = $result.changes | Where-Object {$_.item.gitObjectType -eq "tree"} | Select-Object -Property{$_.item.Path}
foreach($path in $changesFolders)
{
Write-Host $path
}
Write-Host $changesFolder
I am not sure how but i tried Invoke-webRequest instead of Invoke-RestMethod and it worked
But I had to make some changes in the header as well otherwise it was hitting the endpoint but still giving 203 status
$headers = #{
Authorization=("Basic" + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$PAT")));
ContentType="application/json"
}
$result = Invoke-webRequest -Uri $url -Headers $header -Method GET
Write-Host $result.StatusCode
Gives result and status code 200 as expected
note: without adding a colon before password/PAT while converting to base64string will throw 203 status
The following example is working. Additionally, you can paste our resulting URL into the browser and check the answer from your org.
$user = ""
$token = "PAT"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "ORG"
$teamProject = "PROJECT"
$repoName = "REPONAME"
$commitId = "COMMITID"
$restApiGetCommit = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/commits/$commitId/changes?api-version=5.1"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
Write-Host "Url" $restApiGetCommit
$commitInfo = InvokeGetRequest $restApiGetCommit
Write-Host "Commit: " $commitInfo.changes
foreach($path in $commitInfo.changes)
{
Write-Host "Path" $path.item.path
}

Set Azure devops Release pipeline variable using REST API

I am able to update the variable in the build pipeline using the below json body
$body = '
{
"definition": {
"id": 25
},
"parameters": "{\"var\":\"value\"}"
}
'
The same json is not working with Release pipeline . Is there any way to pass the variable through same way through release pipeline
Set Azure devops Release pipeline variable using REST API
We could use the REST API Definitions - Get to get all the info about this definition in the body, then we could update the body and use the (Definitions - Update) to update the value of the release definition variable from a release pipeline:
PUT https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=5.0
Following is my test inline powershell scripts:
$url = "https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=5.1"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Method Get -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
# Update an existing variable named TestVar to its new value 2
$pipeline.variables.TestVar.value = "789"
####****************** 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 'TestVar' is updated to" $updatedef.variables.TestVar.value
As test result, the variable TestVar updated to 789:
Update:
But I want to achieve it without updating\changing the definition
The answer is yes. You could use the Releases - Create with request body:
{
"definitionId": Id,
"environments": [
{
"variables": {
"TestVar": {
"value": "xxxx"
},
"TestVar2": {
"value": "xxxx"
}
},
}
],
}
For more information refer the post here.
Hope this helps.
Old topic, but there is a better way now and I believe it deserves a new answer (maybe it was even available since the very beginning, don't know.)
Instead of updating the very definition of the pipeline which only works for future releases, you can now update the currently running release only and that solves your problem.
This is how I set up the tasks in the pipeline:
And here's a snippet from the Powershell task:
(it updates delay_minutes release variable based on deploy_time variable which specifies time in HH:mm format)
if(!"$(deploy_time)") {
Write-Host "deploy_time empty, won't delay deployment"
return
}
$url = "$(System.TeamFoundationServerUri)/$(System.TeamProjectId)/_apis/release/releases/$(Release.ReleaseId)?api-version=5.0"
# Uncomment for debugging
# Write-Host "URL: $url"
$delayMinutes = [int](New-TimeSpan -start (Get-Date) -end "$(deploy_time)").TotalMinutes
if($delayMinutes -lt 0) { $delayMinutes = 0 }
$pipeline = Invoke-RestMethod -Uri $url -Method Get -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
# Uncomment for debugging
# Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$pipeline.variables.delay_minutes.value = $delayMinutes
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
The URL in the snippet uses only always available predefined variables so it should be 100% copy-pastable.
Also make sure to set this on the first agent job:
So that the SYSTEM_TOKEN variable is available in the script.

Create Release on GitLab with PowerShell

I try to create a powershell script which can help us to create a release on our private gitlab server.
I found this tutorial
How to create releases in GitLab?
I'm not able to figure out how I can replace the curl command with the powershell invoke-webrequest command.
I already tried multiple concepts for this. In our case we have some code files and create the package in the same repository. The package is included in the gitignore file. (That's fine for us)
Now I tried to do this
$body = #{'form'='file=#/our awesome app.app'}
Invoke-RestMethod -Headers #{ 'PRIVATE-TOKEN'='<mytoeken>' } -Uri https://scm.domain.net/api/v4/projects/19/uploads -Body $Body
Result:
Invoke-RestMethod : {"error":"file is invalid"}
Does anyone have a script for creating a gitlab release page with download and changelog with powershell.
I also tried release it but I'm not able to configure it for gitlab.
https://www.npmjs.com/package/release-it#gitlab-releases
Below is a collection of some PowerShell snippets I have written or used for this purpose. Maybe this can help some people. Can you not create the $Body in the script also - it looks like it fails create the content from the file?
# Provides code snippets for Windows Powershell to use Gitlabs API to do various tasks
# for example [ Issue management, Release creation etc.]
# https://docs.gitlab.com/ee/api/
# Variables
# modify with you own content
$glUrl = "http://<your-gitlab-url>"
$p = "3" # Project ID
$tag = "1.3" # Modify this to create/delete release ...
$token = "<EDIT_ME>" # Your access token (http://<your-gitlab-url>/profile/personal_access_tokens)
$projectsUrl = "$glUrl/api/v4/projects" # i.e. http://<your-gitlab-url>/api/v4/projects
$pUrl = "$projectsUrl/$p" # i.e. http://<your-gitlab-url>/api/v4/projects/3
$releaseUrl = "$pUrl/releases" # i.e. http://<your-gitlab-url>/api/v4/projects/3/releases
$artifactsUrl = "$pUrl/jobs/artifacts/$tag/download?job=build-standard" # i.e. Build artifacts created for $tag and the relevant job ("build-standard"; can be modified)
# Project List
$r = Invoke-RestMethod -Headers #{ 'PRIVATE-TOKEN'="$token" } -Uri $projectsUrl
$r | Sort-Object -Property id | Format-Table -Property id, name
# Issues List
$r = Invoke-RestMethod -Headers #{ 'PRIVATE-TOKEN'="$token" } -Uri $pUrl/issues
$r | Sort-Object -Property id | Format-Table -Property id, state, title
# New Issue
Invoke-RestMethod -Method Post -Headers #{ 'PRIVATE-TOKEN'="$token" } -Uri "$pUrl/issues?title=Hello from PS&labels=test"
# Comment on the Issue
Invoke-RestMethod -Method Post -Headers #{ 'PRIVATE-TOKEN'="$token" } -Uri "$pUrl/issues/3/notes?body=Hello PowerShell"
function Register-NewIssue {
param(
[string]$title,
[string]$desc = '',
[string]$uri = '$projectUrl/issues'
)
$title = [System.Web.HttpUtility]::UrlEncode($title)
$desc = [System.Web.HttpUtility]::UrlEncode($desc)
$u = "$uri`?title=$title&description=$desc"
$r = Invoke-RestMethod -Method Post -Headers #{ 'PRIVATE-TOKEN'= "$token" } -Uri $u
$r | Format-List -Property iid, state, title, description
}
# Get list of Releases
Invoke-RestMethod -Method Get -Headers #{ 'PRIVATE-TOKEN'="$token" } -Uri $releaseUrl
# Create a Release
$JSON = #"
{
"name": "New release",
"tag_name": $tag,
"ref": "master",
"description": "FromPS",
"assets":{
"links":[
{
"name":"Executables",
"url":"$artifactsUrl"
}
]
}
}
"#
Invoke-RestMethod -Method Post -Headers #{ 'PRIVATE-TOKEN'="$token"; 'Content-Type'='application/json' } -Body $JSON -Uri "$releaseUrl"
Read-Host -Prompt "Press Enter to continue"
# Adds only a link to this Release manually
$JSONLINK = #'
{"name":"awesome-exec",
"url":"$artifactsUrl"
}
'#
Invoke-RestMethod -Method Post -Headers #{ 'PRIVATE-TOKEN'= "$token"; 'Content-Type'='application/json' } -Body $JSONLINK -Uri "$releaseUrl/$tag/assets/links"
# Delete a Release
Invoke-RestMethod -Method Delete -Headers #{ 'PRIVATE-TOKEN'= "$token" } -Uri "$releaseUrl/$tag"

Issue when updating build definition using the REST api of VSTS

I want to update a variable in my build definition but when it tries to run the Invoke-RestMethod I receive the following exception:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"This request expects an object in the request body,
but the supplied data could not be
deserialized.","typeName":"Microsoft.TeamFoundation.Build.WebApi.RequestContentException,
Microsoft.TeamFoundation.Build2.WebApi, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a","typeKey":"RequestContentException","errorCode":0,"eventId":3000}
At D:\a\_temp\231f1be5-edc0-4bd9-a2e4-efd23a8308d1.ps1:42 char:1
+ Invoke-RestMethod -Method Put -Uri "$($projectDef.Url)&api-version=2. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Everything else seems to work, I get the build definition, I can update the variable but when I try to PUT the json back using the Invoke-RestMethod it fails.
Below is the used code which runs in a Powershell inline script:
# This script is intended to be used for PowerShell script tasks in VSTS in "inline mode"
$valueName = 'ProjectBuildNumber'
$token = 'MYTOKENCODE'
$uriRoot = $env:SYSTEM_TEAMFOUNDATIONSERVERURI
$ProjectName = $env:SYSTEM_TEAMPROJECT
$ProjectId = $env:SYSTEM_TEAMPROJECTID
$uri = "$uriRoot$ProjectName/_apis/build/definitions?api-version=2.0"
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "", $token)))
$header = #{Authorization = ("Basic {0}" -f $base64AuthInfo)}
# Get the list of Build Definitions
$buildDefs = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers $header
# Find the build definition for this project
$buildDef = $buildDefs.value | Where-Object { $_.Project.id -eq $ProjectId }
if ($buildDef -eq $null)
{
Write-Error "Unable to find a build definition for Project '$ProjectName'. Check the config values and try again." -ErrorAction Stop
}
# NOTE: ensure we call the v 2.0 api! (both get and put calls need the same api versions!)
# get its details
$projectDef = Invoke-RestMethod -Uri "$($buildDef.Url)?api-version=2.0" -Method Get -ContentType "application/json" -Headers $header
if ($projectDef.variables.$valueName -eq $null)
{
Write-Error "Unable to find a variable called '$valueName' in Project $ProjectName. Please check the config and try again." -ErrorAction Stop
}
# get and increment the variable in $valueName
[int]$counter = [convert]::ToInt32($projectDef.variables.$valueName.Value, 10)
$updatedCounter = $counter + 1
Write-Host "Project Build Number for '$ProjectName' is $counter. Will be updating to $updatedCounter"
# Update the value and update VSTS
$projectDef.variables.$valueName.Value = $updatedCounter.ToString()
$projectDefJson = $projectDef | ConvertTo-Json -Depth 50 -Compress
# when we build the URL need to cater for if the Project Definition URL already has parameters or not.
$separator = "?"
if ($projectDef.Url -like '*?*')
{
$separator = "&"
}
$putUrl = "$($projectDef.Url)$($separator)api-version=2.0"
Write-Host "Updating Project Build number with URL: $putUrl"
Invoke-RestMethod -Method Put -Uri $putUrl -Headers $header -ContentType "application/json" -Body $projectDefJson | Out-Null
UPDATE
When I use postman to test this, I first run a get and then a put, it works...
Ok problem was with the character & which got replaced by \u0026. Added the following which solved this:
([System.Text.Encoding]::UTF8.GetBytes($projectDefJson))
So the last line becomes:
Invoke-RestMethod -Method Put -Uri $putUrl -Headers $header -ContentType "application/json" -Body ([System.Text.Encoding]::UTF8.GetBytes($projectDefJson)) | Out-Null