Are TFS Build Agent User Capability Values ​​available as part of build steps?

I am trying to write a build step in TFS that relies on knowing where the nuget.exe build agent is stored (the standard nuget-install step is concatenated with argument order in a way that breaks the build execution, so I want to run the exe myself using one of the batch steps / shell / ps).

It would seem like making the build agent run with this path makes sense, but I can't reference the value in any of my build steps, and I can't find anything useful on MSDN.

I expect it to be something like $(Env.MyUserCapability)

, but it will never be fixed.

Is it possible to get the capability value at the build stage? And if so, how do you do it? And if not, what is a viable alternative?

+4


source to share


2 answers


User experience is just metadata. But you can set a global environment variable (for example NUGET

) and set it to the path to nuget.exe

when you restart the agent, then the system-wide environment will be detected as a possibility and you can use it.



If you are writing a custom task, you can also add nuget.exe

to the task to be loaded to the executing agent.

+2


source


UPDATE: I made a public extension out of this .

UPDATE: This works in Azure DevOps 2019.

The following works in TFS 2018u1:

Import-Module "Microsoft.TeamFoundation.DistributedTask.Task.Common"
Import-Module "Microsoft.TeamFoundation.DistributedTask.Task.Internal"
Add-Type -Assembly "Microsoft.TeamFoundation.DistributedTask.WebApi"

$VSS = Get-VssConnection -TaskContext $distributedTaskContext
$AgentCli = $VSS.GetClient([Microsoft.TeamFoundation.DistributedTask.WebApi.TaskAgentHttpClient])

$AgentConfig = Get-Content "$Env:AGENT_HOMEDIRECTORY\.agent" -Raw | ConvertFrom-Json
$Agent = $AgentCli.GetAgentAsync($AgentConfig.PoolId, $Env:AGENT_ID, $TRUE, $FALSE, $NULL, $NULL, [System.Threading.CancellationToken]::None).GetAwaiter().GetResult()

if($Agent.UserCapabilities.MyCapability)
{
    Write-Host "Got the capability!";
} 

      

The default long string of arguments ending with is CancellationToken::None

intended for compatibility with Powershell 4. PS4 does not support default typed value method parameters, PS5 does.

This snippet does something highly questionable - it depends on the location and structure of the agent config file. This is fragile The problem is that the method GetAgentAsync

requires a pool ID and an agent ID, and the former does not appear in environment variables. A slightly less hackish approach will check all pools and find the correct one by agent ID:

$Pools = $AgentCli.GetAgentPoolsAsync($NULL, $NULL, $NULL, $NULL, $NULL, [System.Threading.CancellationToken]::None).GetAwaiter().GetResult()
$Demands = New-Object 'System.Collections.Generic.List[string]'
foreach($Pool in $Pools)
{
    $Agent = $AgentCli.GetAgentsAsync($Pool.ID, $Env:AGENT_NAME, $TRUE, $FALSE, $NULL, $Demands, $NULL, [System.Threading.CancellationToken]::None).Result
    if($Agent -and $Agent.Id -eq $Env:AGENT_ID)
    {
        Break
    }
}

      



This depends on another undocumented implementation detail, namely that agent IDs are globally unique. This seems to be the case for TFS 2018, but who knows.


When you use $distributedTaskContext

, the job connects back to TFS with an artificial user identity, "Project Collection Build Service" (not with the agent service account). Each collection has one such user, they are different. For tasks that run in editions in the collection to query the agent for user experience, you must grant the Reader role to the appropriate pools (or all pools) of a user account named Project Collection Build Service (TheCollectionName). ) "from this collection.

It also looks like some actions also provide an implicit Reader role in the pool to identify the task.


Alternatively, you can create an agent account in the pool (s) VssConnection

from scratch with Windows credentials and the VssConnection

Reader role.

+1


source







All Articles