How to set a different default TFS agent pool - tfs

We have multiple agent pools in TFS. Is there a way to set the default agent to one of the pools?
Currently, all project builds has a Default agent when creating a build.
Instead of the Default agent to display as the first one on the list, we want to have a different agent as default. Is that possible?

Instead of the Default agent to display as the first one on the list, we want to have diff agent as Default. Is it possible?
I am afraid there is out of box setting to set a different default agent pool.
On the web portal, we could select the different default TFS agent pool in the option Default agent queue in the build Options tab and save it:
This setting is saved. When you queue the build, the default agent pool will be the agent you set above:
And when you next queue your build, the default agent will be the one you set before.
On the other hand, we could add a specify the demands which match the specific agent, like:
Agent.Name -equals AgentNameHere
Then queue build with the REST API and specify the demands:
Param(
[string]$collectionurl = "http://server:8080/tfs/DefaultCollection/",
[string]$projectName = "0323ScrumTFVC",
[string]$keepForever = "true",
[string]$BuildDefinitionId = "1",
[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)))
function CreateJsonBody
{
$value = #"
{
"definition": {
"id": $BuildDefinitionId
},
"sourceBranch": "$/0323ScrumTFVC",
"demands":["Agent.Name -equals AgentNameHere"]
}
}
"#
return $value
}
$json = CreateJsonBody
$uri = "$($collectionurl)/$($projectName)/_apis/build/builds?api-version=2.0"
$result = Invoke-RestMethod -Uri $uri -Method Post -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
Ticket here: Specifying agent at queue build time with TFS 2015.
But, this method is not work for UI.
Check the document Predefined variables and Demands.

Related

How to specify git author/committer for PullRequest merge in Azure DevOps?

I have defined a release pipeline to synchronize code between two git repositories in Azure DevOps. The process requires a PullRequest in the destination repo which is created and completed using the WebAPI.
The pipeline is executed by the build agent running using a Windows domain service account. So, the PullRequest is created and completed on behalf of the service account, which is also mentioned as author, committer, etc. in the git history after merge is completed. (According to our rules the PR must be merged using squash commit.)
I would like see a different user in the git history after (squash) merge.
Can I specify the user (e.g. the user triggering the release pipeline) using WebAPI?
I did not find such option in the API documentation.
Any other recommendation? Maybe convention like adding "co-authored-by" to commit message like github?
When you use Pull Requests-Create rest api to create a pull request, the pull request creator is determined by the creator of the PAT you used for authentication (e.g. I used the PAT of hughl01 user as the authentication to create the pull request, then the creator of the pull request is hughl01).
Test in Postman:
Sample test script in powershell task:
$token = "{User-created PAT}"
$url = "https://dev.azure.com/{org}/{pro}/_apis/git/repositories/{repoId}/pullrequests?api-version=6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #'
{
"sourceRefName": "refs/heads/dev2",
"targetRefName": "refs/heads/master",
"title": "ForTest",
"description": "Adding a new feature"
}
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
You can create a variable group, with the release trigger as the variable name, and the PAT corresponding to the user as the variable value and set the value of the variable to secret. Then get the name of the triggerer through the predefined variable $(Release.RequestedFor) in the script, then obtain the corresponding PAT according to the trigger name to create pull request.

Is it possible to use a variable in the Agent.Name demand for tfs?

I am trying to force the run of a specific agent phase on a specific agent. My variable however does not seems to be picked up. I get the error:
No agent found in pool TEST which satisfies the specified demands:
Agent.Name -equals $(Release.ReleaseName)
vstest
Agent.Version -gtVersion 2.103.0
Is this possible?
I wanted to do something similar. I had 2 "environments" in the TFS release definition. The first one ("MyEnvironment-Setup") did setup like big file copies and database script generation. The second ("MyEnvironment") did the actual deployment. I needed them both to run on the same agent.
What I ended up doing is using the TFS API during "MyEnvironment-Setup" to modify the currently running release instance and set the agent demand for "MyEnvironment".
Several things were necessary to make this happen.
In "MyEnvironment-Setup" > Run on Agent > Additional Options, I enabled "Allow scripts to access the OAuth token"
In the left pane of the release definition screen where it lists all release definitions, I clicked the ellipsis next to "All release definitions" and selected "Security". Then for the "Project Collection Build Service (TEAM FOUNDATION)" user, I set "Edit release definition" and "Manage releases" to "Allow".
I called the following Powershell method in "MyEnvironment-Setup"
function Set-FinalAgent()
{
# Force the "MyEnvironment" step to run on the same agent as the "MyEnvironment-Setup" step
$baseApiUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis"
$apiVersion = "3.1-preview"
$header = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$environmentToModify = $($env:Release_EnvironmentName).Replace("-Setup", "")
$releaseID = $env:Release_ReleaseID
$release = Invoke-RestMethod -Uri "$baseApiUrl/release/releases/$($releaseID)?api-version=$apiVersion" -Method GET -Header $header
($release.environments | where name -eq $environmentToModify).deployPhasesSnapshot[0].deploymentInput.demands += "Agent.Name -equals $($env:Agent_Name)"
# Compression is needed for the body to contain all of the info for larger release definitions when running on older servers
$body = $release | ConvertTo-Json -Depth 100 -Compress
Invoke-RestMethod -Uri "$baseApiUrl/release/releases/$($releaseID)?api-version=$apiVersion" -Method PUT -Header $header -ContentType application/json -Body $body
}
If you want to test and tweak this in Powershell ISE or something where you don't have access to the OAuth token, you can use a personal access token instead. In the top-right of your TFS Web UI, click your profile picture and select "Security" to generate a PAT. Then you can replace the header in the script above with the following:
$header = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))}

How to Login to VSTS programmatically

I have an automatic branching utility that does various operations.
We have upgraded to VSTS and I am having trouble using the Tfs calls with the new server:
//login
NetworkCredential netCred = new NetworkCredential("emailAddress", password");
BasicAuthCredential basicCred = new BasicAuthCredential(netCred);
TfsClientCredentials tfsCred = new TfsClientCredentials(basicCred);
tfsCred.AllowInteractive = false;
TfsTeamProjectCollection tfsServer = new TfsTeamProjectCollection(new Uri("https://myco.visualstudio.com/mycoll"), tfsCred);
// get a local workspace
VersionControlServer sc = server.GetService(typeof(VersionControlServer)) as VersionControlServer;
... other code
and then boom!
"You are not authorized to access https://myco.visualstudio.com/mycoll"
Is there some setting somewhere?
Should I try and use the REST API?
Am I calling something I shouldn't?
I've tried all sorts of formats for the URI, with :8080, with /tfs in the path to no avail!
You can use PAT (Personal Access Token) to access VSTS. Click on your profile in VSTS and go to security menu item. You can define a PAT in there. Keep the PAT saved as it will only be shown once.
Define the scope as per your needs
You can use the PAT to access TFS REST API as shown in following PowerShell sample. Using https://yourAccount.visualstudio.com or https://yourAccount.visualstudio.com/DefaultCollection for ColletionUri parameter is OK.
param(
[Parameter(Mandatory=$true)]
[string] $token,
[Parameter(Mandatory=$true)]
[string] $collectionUri
)
$User=""
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User,$token)));
$header = #{Authorization=("Basic {0}" -f $base64AuthInfo)};
$Uri = $collectionUri + '/_apis/projects?api-version=1.0'
$projects = Invoke-RestMethod -Method Get -ContentType application/json -Uri $Uri -Headers $header
You can find C# code samples here https://www.domstamand.com/accessing-tfs-2017-programmatically/

Setting TFS 2017 builds to Partially succeeded

We have an orchestration build that we would like to set status to partially succeeded if it didn't do certain things. With Xaml builds, we could do it by setting the CompilationStatus and TestStatus of the build.
For Tfs Builds, I can am trying to it by setting calling the TFS Rest API to update the build result.
$query = [uri]::EscapeUriString("$tfsCollection$tfsProject/_apis/build/builds/$buildId`?api-version=2.0")
$request = "{""result"":""$result""}"
try {
$result = Invoke-RestMethod -Method PATCH -UseDefaultCredentials -ContentType "application/json" -Uri $query -Body $request
}
catch{
Write-Output "StatusCode:" + $_.Exception.Response.StatusCode.value__ +
"`r`nStatusDescription:" + $_.Exception.Response.StatusDescription
}
After the call, I can see that the ribbon of the build changes to orange indicating that is partially succeeded. However, it gets changed to succeeded when the Finalize Build step of build is run.
What should I do that the end build finishes with a status partially succeeded.
You can add a task with its control options set to "Continue on Error". Whenever this tasks fails, your build will be partially succeeded.

TFS 2015 Queue new build using REST Api - Set Demands

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.
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
}
Try to set the depth:
$bodyjson = $json | ConvertTo-Json -Depth 3
$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
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.

Resources