1

Im trying to queue a new build using the TFS 2015.3 REST API, i have followed many articles but cannot get it to work.

I am executing this in PowerShell, a standard queue new build call works when passing only the Definition ID, but passing anything else in addition to the id doesn't seem to work.

my code:

$buildDef = Invoke-RestMethod -Method Get -UseDefaultCredentials -Uri "$($tfsRoot)/_apis/build/definitions?api-version=2.0&name=$buildDefintionName" $detailedResults = Invoke-RestMethod -Uri $buildDef.Value[0].Url -Method Get -ContentType "application/json" -UseDefaultCredentials if ($buildDef.Value[0].Id) { $agentDemandString = "Agent.Name -equals $agent" $demands = $detailedResults.Demands $json = "definition: { id:$($buildDef.Value[0].Id) }, demands: $demands" $bodyjson = $json | ConvertTo-Json Write-Host "Queuing build $buildDefintionName on agent $agent with parameters $json" $build = Invoke-RestMethod -Method Post -UseDefaultCredentials -ContentType application/json -Uri "$($tfsRoot)/_apis/build/builds?api-version=2.0" -Body $bodyjson } 

I have tried many different variations of passing the demands, but it looks like it is not even getting to that point as its complaining about the "build" parameter.

Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: build","typeName":"System.ArgumentNullException, mscorlib, Version=4.0.0.0, Culture=neutral

If im right the build parameter contains the build steps to execute. Which makes me think that the queued build is dropping all existing configuration and tries to rely only on what has been passed in the JsonBody, this is ofcourse not what i want.

What and how should i pass in order to queue a new build but with updated/additional demands.

4 Answers 4

2

I finaly got it working with some help. The Demands property is accepted. Looks like it was not working because of the powerShell code with Json conversion. If i use below and dont convert it to Json, it works !

Function queuebuild{ $uri="$($tfsRoot)/_apis/build/builds?api-version=2.0" $body='{ "definition": { "id": 1061 }, "sourceBranch": "$/Project/Branch", "demands":["Demand1", "Agent.Name -equals Computer2-E-A2"] }'; $result=Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -UseDefaultCredentials -Body $body 

}

Sign up to request clarification or add additional context in comments.

Comments

0

Try to set the depth:

$bodyjson = $json | ConvertTo-Json -Depth 3

1 Comment

Thanks, but that doesn't fix it. i dont think the Depth is the issue as the settings i create dont go that deep.
0

$json = "definition: { id:$($buildDef.Value[0].Id) }, demands: $demands" is not going to be valid JSON -- it wouldn't be wrapped in curly braces, for example.

I recommend creating an associative array that will properly convert to valid JSON. The example JSON provided in the documentation is:

{ "definition": { "id": 25 }, "sourceBranch": "refs/heads/master", "parameters": "{\"system.debug\":\"true\",\"BuildConfiguration\":\"debug\",\"BuildPlatform\":\"x64\"}" } 

So this would generate an appropriate JSON object:

$body = @{ definition = @{ id=25 } sourceBranch = 'refs/heads/master' parameters = '{\"system.debug\":\"true\",\"BuildConfiguration\":\"debug\",\"BuildPlatform\":\"x64\"}' } $body | convertto-json 

Or if you wanted to be extra fancy and eliminate the inner JSON-as-a-string bit:

$body = @{ definition = @{ id=25 } sourceBranch = 'refs/heads/master' parameters = (@{'system.debug' = $true; BuildConfiguration='debug'; BuildPlatform='x64'}) | convertto-json -Compress } $body | convertto-json 

1 Comment

Thanks Daniel, i have tried various ways of writing the json, i guess a wrong one got in the last version. But also with your version i still get the same error. Value cannot be null.\r\nParameter name: build
0

Based on my test, we cannot Set Demands directly with the Queue build REST Api.

The build will still use the agent which was set in definition even though we specified other agents with the "Demands" set when queue the build. You can check this with the REST API, below screenshot for your reference.

And with the REST API to get a build eg:

GET http://SERVER:8080/tfs/CollectionLC/6debd6ea-fa97-4ea2-b0c0-3cbbc4afa802/_apis/build/Builds/1071/ 

You can see that, the "Demands" is not included in the response. It only appears in build definition response.

Actually, the "Demands" is set in build definition,it's against the build definition only. When queue a build with REST API, it just trigger the build definition. So, if you want to trigger build with the specific agent using REST API, you need to update the definition (set demands )first, then trigger the build definition.

To update the definition use the REST API : See Update a build definition

PUT https://{instance}/DefaultCollection/{project}/_apis/build/definitions/{definitionId}?api-version={version} 

So, you can write the script to update build definition fist, then trigger the build with build definition ID.

enter image description here

6 Comments

and after the change you need to undo the update i guess ? or is there a way to queue the build with an alternative configuration 1 time ? We want to be able to queue a (re)build on 10 agents at the same time and ensure it has run on all those agents, the only way to ensure this is to limit the agent filter by its name. I we can queue a build with a temporary config that could work, but saving and rolling back the change would be a pain. Are we able to achieve this better with the C# API ?
@Nico I think the best way is creating 10 build definitions separately set the agent for each of them, then write script to trigger them.
No that wont work because they will then run in their own workspace. We need the rebuild to run in the original workspace in each agent to ensure the workspace is rebuild and clean. How does TFS do it itself, through the webUI you can add a demand when queuing the build..
@Nico Each Agent will run in it's own workspace, the agent will get the source from TFS to local agent server first. You can check the build log for this. So, unless you build with the same agent, if you want to build with other agents, they will get source individually and run in their own workspace. Whatever the webUI or REST API. So, you just need to clone the build definition 10 times, and change the demands to specify the specific agent for each of them.
No thats not what i mean. We have 1 build definition that can run on 10 different agents, all in their own workspace obviously. All these builds are incremental and running tests. At some point, we need to clean the workspaces, run a clean build because something in the workspace went wrong. To do this we want to queue a build for that definition on all the agents and ensure it has run there. The only way to do this is for force each of the 10 queued builds to run on a different agent. so we need the normal build definition with the Agent.Name -equals demand.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.