4

我正在尝试在 TFS 中编写一个构建步骤,该步骤依赖于知道构建代理将 nuget.exe 存储在哪里(标准的 nuget-install 步骤以破坏构建执行的方式混淆了参数的顺序,所以我想使用批处理/shell/ps 步骤之一自己运行 exe)。

使用该路径在构建代理上设置功能似乎是有意义的,但我似乎无法在任何构建步骤中引用该值,并且在 MSDN 上找不到任何有用的东西。

我期望它类似于$(Env.MyUserCapability),但它永远不会解决该值。

是否可以在构建步骤中检索能力值?如果是这样,你怎么做?如果没有,什么是可行的替代方案?

4

2 回答 2

2

用户定义的功能只是元数据。但是您可以设置一个全局环境变量(例如NUGET)并将其设置为 a 的路径nuget.exe,当您重新启动代理时,会发现机器范围的环境作为功能,然后您可以使用它。

如果您正在编写自定义任务,您还可以nuget.exe在将下载到执行代理的任务中添加一个。

于 2017-05-08T14:36:47.937 回答
1

更新:我对此做了一个公共扩展

更新:这适用于 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 不支持值类型方法参数的默认值,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,任务是使用人工用户身份“项目集合构建服务”(而不是代理服务帐户)连接回 TFS。每个集合中都有一个这样的用户,他们是不同的。为了允许在集合中的版本中运行的任务向代理查询用户功能,您需要将 Reader 角色授予相关池(或所有池)到名为“项目集合构建服务 ( TheCollectionName ) 的用户帐户)" 来自该集合。

看起来某些操作还将池上的隐式读者角色授予任务标识。


或者,您可以VssConnection使用 Windows 凭据从头开始构建,并授予代理帐户对池的读取者角色。

于 2018-03-28T16:04:13.810 回答