是否可以在构建步骤中获取 TFS 构建代理用户功能的值?
Are TFS Build Agent User Capabilities' Values Obtainable Within Build Steps?
我正在尝试在 TFS 中编写一个构建步骤,该步骤依赖于了解构建代理 nuget.exe 的存储位置(标准的 nuget-install 步骤以一种破坏参数顺序的方式处理构建执行,所以我想 运行 使用 batch/shell/ps 步骤之一自己执行 exe。
似乎使用该路径在构建代理上设置功能是有意义的,但我似乎无法在我的任何构建步骤中引用该值,而且我在 MSDN 上找不到任何有用的信息。
我希望它类似于 $(Env.MyUserCapability)
,但它永远不会解析为值。
是否可以在构建步骤中检索功能值?如果是这样,你是怎么做到的?如果没有,什么是可行的替代方案?
用户定义的功能只是元数据。但是你可以设置一个全局环境变量(例如 NUGET
)并将其设置为 nuget.exe
的路径,当你重新启动代理时,机器范围的环境就会被发现作为能力,然后你可以使用它。
如果您正在编写自定义任务,您还可以将 nuget.exe
添加到将下载到执行代理的任务中。
更新:I made a public extension out of this.
更新:这适用于 Azure DevOps 2019。
在 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!";
}
以 CancellationToken::None
结尾的一长串默认参数是为了与 Powershell 4 兼容。PS4 不支持 value-typed 方法参数的默认值,PS5
这个片段做了一些非常有问题的事情——它依赖于代理配置文件的位置和结构。这是脆弱的。问题在于 GetAgentAsync
方法同时需要池 ID 和代理 ID,而前者未暴露在环境变量中。一种稍微不那么骇人听闻的方法是检查所有池并通过代理 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
}
}
这依赖于另一个未记录的实施细节,特别是代理 ID 是全局唯一的。这似乎一直持续到 TFS 2018,但谁知道呢。
当您使用 $distributedTaskContext
时,任务是使用人工用户身份 "Project Collection Build Service"(不使用代理服务帐户)连接回 TFS。每个集合中都有一个这样的用户,他们是不同的。为了允许集合中版本中的任务 运行 查询代理的用户功能,您需要将 Reader 角色授予用户帐户的相关池(或所有池)从该集合中调用 "Project Collection Build Service (TheCollectionName)"。
看起来有些操作还向任务标识授予池上的隐式 Reader 角色。
或者,您可以使用 Windows 凭据从头构建一个 VssConnection
,并授予代理帐户 Reader 池中的角色。
我正在尝试在 TFS 中编写一个构建步骤,该步骤依赖于了解构建代理 nuget.exe 的存储位置(标准的 nuget-install 步骤以一种破坏参数顺序的方式处理构建执行,所以我想 运行 使用 batch/shell/ps 步骤之一自己执行 exe。
似乎使用该路径在构建代理上设置功能是有意义的,但我似乎无法在我的任何构建步骤中引用该值,而且我在 MSDN 上找不到任何有用的信息。
我希望它类似于 $(Env.MyUserCapability)
,但它永远不会解析为值。
是否可以在构建步骤中检索功能值?如果是这样,你是怎么做到的?如果没有,什么是可行的替代方案?
用户定义的功能只是元数据。但是你可以设置一个全局环境变量(例如 NUGET
)并将其设置为 nuget.exe
的路径,当你重新启动代理时,机器范围的环境就会被发现作为能力,然后你可以使用它。
如果您正在编写自定义任务,您还可以将 nuget.exe
添加到将下载到执行代理的任务中。
更新:I made a public extension out of this.
更新:这适用于 Azure DevOps 2019。
在 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!";
}
以 CancellationToken::None
结尾的一长串默认参数是为了与 Powershell 4 兼容。PS4 不支持 value-typed 方法参数的默认值,PS5
这个片段做了一些非常有问题的事情——它依赖于代理配置文件的位置和结构。这是脆弱的。问题在于 GetAgentAsync
方法同时需要池 ID 和代理 ID,而前者未暴露在环境变量中。一种稍微不那么骇人听闻的方法是检查所有池并通过代理 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
}
}
这依赖于另一个未记录的实施细节,特别是代理 ID 是全局唯一的。这似乎一直持续到 TFS 2018,但谁知道呢。
当您使用 $distributedTaskContext
时,任务是使用人工用户身份 "Project Collection Build Service"(不使用代理服务帐户)连接回 TFS。每个集合中都有一个这样的用户,他们是不同的。为了允许集合中版本中的任务 运行 查询代理的用户功能,您需要将 Reader 角色授予用户帐户的相关池(或所有池)从该集合中调用 "Project Collection Build Service (TheCollectionName)"。
看起来有些操作还向任务标识授予池上的隐式 Reader 角色。
或者,您可以使用 Windows 凭据从头构建一个 VssConnection
,并授予代理帐户 Reader 池中的角色。