Powershell TFS 2015不再在构建完成时将构建编号添加到全局列表中?

Powershell TFS 2015不再在构建完成时将构建编号添加到全局列表中?,powershell,tfs,tfsbuild,tfs-2015,azure-pipelines,Powershell,Tfs,Tfsbuild,Tfs 2015,Azure Pipelines,在TFS 2015新构建系统中,构建完成后自动将构建编号添加到全局列表(构建-项目名称)的功能是否已删除 我是否需要编写自定义PowerShell任务来完成此任务 注意:XAML版本仍然像以前一样将版本号添加到全局列表中。[免责声明-我在新的版本系统上工作] workitem上的全局列表是一种机制,可以追溯到TFS的原始版本。这是一种在那个时代(夜间构建、CI前和CD敏捷性的日子)起作用的方法。它开始崩溃,在TFS中没有显示为正确的关系。当时我致力于智慧,我们需要一个可质疑的机制,这就是我们所拥

在TFS 2015新构建系统中,构建完成后自动将构建编号添加到全局列表(构建-项目名称)的功能是否已删除

我是否需要编写自定义PowerShell任务来完成此任务


注意:XAML版本仍然像以前一样将版本号添加到全局列表中。

[免责声明-我在新的版本系统上工作]

workitem上的全局列表是一种机制,可以追溯到TFS的原始版本。这是一种在那个时代(夜间构建、CI前和CD敏捷性的日子)起作用的方法。它开始崩溃,在TFS中没有显示为正确的关系。当时我致力于智慧,我们需要一个可质疑的机制,这就是我们所拥有的(怪我:)

所以,当我们开始一个新的构建系统时,我们不想重建东西,重复同样的错误。我们正试图采取一种敏捷、渐进的方法来构建一个更好的构建系统

在下一个sprint(88)中,我们开始研究构建和工作项之间的适当链接,WIT团队也在努力使它们更一流。你将看到的第一件事是WIT表单上的链接,希望它也能成为QU1(至少是其中的一部分)

我们意识到这确实留下了一些差距,但我们正在努力弥补这些差距(另外两个是封闭和标签来源),并希望以更好的方式获得更好的长期产品


就解决方案而言,应该可以通过powershell和我们的客户机实现自动化,但我们没有任何现成的东西供其他人使用。

由于vNext构建系统中仍然缺少许多功能,因此我制作了一个powershell脚本来完成这项工作。 在不久的将来,我计划更新此脚本以支持IntegratedIn字段填充,并将脚本转换为自定义构建任务

[CmdletBinding(SupportsShouldProcess=$false)]
param()

function Update-GlobalListXml
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param(
         [xml]$globalListsDoc,
         [parameter(Mandatory=$true)][string][ValidateNotNullOrEmpty()]$glName,
         [parameter(Mandatory=$true)][string][ValidateNotNullOrEmpty()]$buildNumber
    )

    Write-Verbose "Checking whether '$glName' exists"
    $buildList = $globalListsDoc.GLOBALLISTS.GLOBALLIST | Where-Object { $_.name -eq $glName }
    if ($buildList -eq $null)
    {
        Write-Host "GlobalList '$glName' does not exist and will be created"
        $globalLists = $globalListsDoc.GLOBALLISTS
        if($globalLists.OuterXml -eq $null)
        {
            $newDoc = [xml]"<gl:GLOBALLISTS xmlns:gl="""http://schemas.microsoft.com/VisualStudio/2005/workitemtracking/globallists"""></gl:GLOBALLISTS>"
            $globalLists = $newDoc.GLOBALLISTS
        }
        $globalList = $globalLists.OwnerDocument.CreateElement("GLOBALLIST")
        $globalList.SetAttribute("name", $glName)
        $buildList = $globalLists.AppendChild($globalList)
    }
    if(($buildList.LISTITEM | where-object { $_.value -eq $buildNumber }) -ne $null)
    {
        throw "The LISTITEM value: '$buildNumber' already exists in the GLOBALLIST: '$glName'"
    }

    Write-Host "Adding '$buildNumber' as a new LISTITEM in '$glName'"
    $build = $buildList.OwnerDocument.CreateElement("LISTITEM")
    $build.SetAttribute("value", $buildNumber)
    $buildList.AppendChild($build) | out-null

    return $buildList.OwnerDocument
}

function Invoke-GlobalListAPI()
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param(
        [parameter(Mandatory=$true)][Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]$wiStore,
        [parameter(Mandatory=$true,ParameterSetName="Import")][switch]$import,
        [parameter(Mandatory=$true,ParameterSetName="Import")][xml]$globalLists,
        [parameter(ParameterSetName="Export")][switch]$export
    )

    try {
        if($import)
        {
            $wiStore.ImportGlobalLists($globalLists.OuterXml) # Account must be explicitly in the Project Administrator Group
        }
        if($export)
        {
            return [xml]$wiStore.ExportGlobalLists()
        }
    }
    catch [Microsoft.TeamFoundation.TeamFoundationServerException] {
        Write-Error "An error has occured while exporting or importing GlobalList"
        throw $_
    }
}

function Get-WorkItemStore()
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param(
        [parameter(Mandatory=$true)][string][ValidateNotNullOrEmpty()]$tpcUri,
        [parameter(Mandatory=$true)][string][ValidateNotNullOrEmpty()]$agentWorker
    )

    # Loads client API binaries from agent folder
    $clientDll = Join-Path $agentWorker "Microsoft.TeamFoundation.Client.dll"
    $wiTDll = Join-Path $agentWorker "Microsoft.TeamFoundation.WorkItemTracking.Client.dll"
    [System.Reflection.Assembly]::LoadFrom($clientDll) | Write-Verbose
    [System.Reflection.Assembly]::LoadFrom($wiTDll) | Write-Verbose

    try {
        Write-Host "Connecting to $tpcUri"
        $tfsTpc = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tpcUri)
        return $tfsTpc.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore])
    }
    catch [Microsoft.TeamFoundation.TeamFoundationServerException] {
        Write-Error "An error has occured while retrieving WorkItemStore"
        throw $_
    }
}

function Get-WITDataStore64
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param()

    if($env:VS140COMNTOOLS -eq $null)
    {
        throw New-Object System.InvalidOperationException "Visual Studio 2015 must be installed on the build agent" # TODO: Change it by checking agent capabilities
    }

    $idePath = Join-Path (Split-Path -Parent $env:VS140COMNTOOLS) "IDE"
    return Get-ChildItem -Recurse -Path $idePath -Filter "Microsoft.WITDataStore64.dll" | Select-Object -First 1 -ExpandProperty FullName
}

function Update-GlobalList
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param()

    # Get environment variables
    $tpcUri = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI
    Write-Verbose "Team Project Collection Url: '$tpcUri'"
    $teamProjectName = $env:SYSTEM_TEAMPROJECT
    Write-Verbose "Team Project: '$teamProjectName'"
    $buildNumber = $env:BUILD_BUILDNUMBER
    Write-Verbose "Build Number: '$buildNumber'"
    $agentHome = $env:AGENT_HOMEDIRECTORY
    Write-Verbose "Agent home direrctory: '$agentHome'"
    $globalListName = "Builds - $teamProjectName"
    Write-Verbose "GlobalList name: '$teamProjectName'"

    # Copy 'Microsoft.WITDataStore64.dll' from Visual Studio directory to AgentBin directory if it does not exist
    $agentWorker = Join-Path $agentHome "agent\Worker"
    $targetPath = Join-Path $agentWorker "Microsoft.WITDataStore64.dll" # Only compatible with x64 process #TODO use constant instead
    if(-not (Test-Path $targetPath))
    {
        $wITDataStore64FilePath = Get-WITDataStore64
        Write-Host "Copying $wITDataStore64FilePath to $targetPath"
        Copy-Item $wITDataStore64FilePath $targetPath | Write-Verbose
    }

    $wiStore = Get-WorkItemStore -tpcUri $tpcUri -agentWorker $agentWorker

    # Retrive GLOBALLISTS
    $xmlDoc = Invoke-GlobalListAPI -export -wiStore $wiStore
    $gls2 = Update-GlobalListXml -globalListsDoc $xmlDoc -glName $globalListName -buildNumber $buildNumber

    Invoke-GlobalListAPI -import -globalLists $gls2 -wiStore $wiStore
}

Update-GlobalList
[CmdletBinding(SupportsShouldProcess=$false)]
param()
函数更新GlobalListXml
{
[CmdletBinding(SupportsShouldProcess=$false)]
param(
[xml]$GlobalListDoc,
[参数(必需=$true)][string][ValidateNotNullOrEmpty()]$glName,
[参数(必需=$true)][string][ValidateNotNullOrEmpty()]$buildNumber
)
编写详细的“检查“$glName”是否存在”
$buildList=$globalListsDoc.GLOBALLISTS.GLOBALLIST |其中对象{$\u0.name-eq$glName}
如果($buildList-eq$null)
{
写入主机“GlobalList'$glName'不存在,将创建”
$globalLists=$globalListsDoc.globalLists
if($globalLists.OuterXml-eq$null)
{
$newDoc=[xml]“”
$globalLists=$newDoc.globalLists
}
$globalList=$globalList.OwnerDocument.CreateElement(“globalList”)
$globalList.SetAttribute(“名称”,$glName)
$buildList=$globalLists.AppendChild($globalList)
}
if($buildList.LISTITEM | where对象{$\ value-eq$buildNumber})-ne$null)
{
throw“GLOBALLIST:'$glName'中已存在LISTITEM值:'$buildNumber'”
}
写入主机“将“$buildNumber”添加为“$glName”中的新列表项”
$build=$buildList.OwnerDocument.CreateElement(“LISTITEM”)
$build.SetAttribute(“值”、$buildNumber)
$buildList.AppendChild($build)| out null
返回$buildList.OwnerDocument
}
函数调用-GlobalListAPI()
{
[CmdletBinding(SupportsShouldProcess=$false)]
param(
[参数(必需=$true)][Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]$wiStore,
[参数(必需=$true,参数setname=“Import”)][开关]$Import,
[参数(必需=$true,ParameterSetName=“Import”)][xml]$globalLists,
[参数(ParameterSetName=“Export”)][switch]$Export
)
试一试{
如果(进口)
{
$wiStore.ImportGlobalLists($globalLists.OuterXml)#帐户必须显式位于项目管理员组中
}
如果(出口)
{
返回[xml]$wiStore.ExportGlobalLists()
}
}
捕获[Microsoft.TeamFoundation.TeamFoundationServerException]{
写入错误“导出或导入GlobalList时发生错误”
扔$_
}
}
函数Get-WorkItemStore()
{
[CmdletBinding(SupportsShouldProcess=$false)]
param(
[参数(必需=$true)][string][ValidateNotNullOrEmpty()]$tpcUri,
[参数(必需=$true)][string][ValidateNotNullOrEmpty()]$agentWorker
)
#从代理文件夹加载客户端API二进制文件
$clientDll=加入路径$agentWorker“Microsoft.TeamFoundation.Client.dll”
$wiTDll=加入路径$agentWorker“Microsoft.TeamFoundation.WorkItemTracking.Client.dll”
[System.Reflection.Assembly]::LoadFrom($clientDll)|编写详细信息
[System.Reflection.Assembly]::LoadFrom($wiTDll)|编写详细信息
试一试{
写入主机“连接到$tpcUri”
$tfsTpc=[Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tpcUri)
返回$tfsTpc.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore])
}
捕获[Microsoft.TeamFoundation.TeamFoundationServerException]{
写入错误“检索WorkItemStore时发生错误”
扔$_
}
}
函数Get-WITDataStore64
{
[CmdletBinding(SupportsShouldProcess=$false)]
param()
如果($env:VS140COMNTOOLS-eq$null)
{
抛出新对象System.InvalidOperationException“必须在生成代理上安装Visual Studio 2015”#TODO:通过检查代理功能进行更改
}
$idePath=连接路径(拆分路径-父$env:VS140COMNTOOLS)“IDE”
return Get ChildItem-Recurse-Path$idePath-Filter“Microsoft.WITDataStore64.dll”| Select Object-First 1-ExpandProperty FullName
}
函数更新全局列表
{
[CmdletBinding(SupportsShouldProcess=$false)]
param()
#获取环境变量
$tpcUri=$env:SYSTEM\u TEAMFOUNDATIONCOLLECTIONURI
长篇大论