如何确定在TFS中触发发布的构建定义?

时间:2017-04-28 12:29:50

标签: tfs tfsbuild release-management tfvc tfs2017

由于在使用TFVC时TFS中不可能有一个单独的构建定义来处理多个分支中的相同代码,因此我们必须为分支维护多个构建定义。

现在我们已经扩展了CI / CD管道以进行自动发布部署。由于我们有多个分支,因此我们还有多个构建定义,现在我们也有多个版本定义。

使用TFS 2017.1,现在可以在版本定义中定义多个持续部署触发器(工件源)。如果成功构建了与这些工件源关联的其中一个构建定义,则可以自动创建和部署新版本。 为了能够摆脱多个版本定义,有必要确定实际触发创建新版本及其部署的构建。

可以在发布定义中使用许多变量,但遗憾的是,似乎无法获得实际触发发布的构建/工件(请参阅https://www.visualstudio.com/en-us/docs/build/concepts/definitions/release/variables#primary-artifact-variables)。

如何确定触发发布的构建定义/工件?

4 个答案:

答案 0 :(得分:2)

我有同样的问题。我希望有一种更直接的方法来查找相应构建的触发“{Artifact alias}”,但我发现确定哪个构建触发了发布的唯一方法是获取以下环境变量: $ env :RELEASE_RELEASEDESCRIPTION 此变量具有以下计算值: “触发”+ {工件别名} + BuildId +“。” 希望这可以帮助 最好的祝福 斯特凡

答案 1 :(得分:1)

在TFS 2017 Update1的发布定义中,如果您将多个构建定义绑定到它,并为发布定义中的每个工件添加持续部署触发器。然后,每次构建成功时都会触发您的发布定义。

要了解哪个版本触发了您的版本,您可以参考版本摘要页

enter image description here

答案 2 :(得分:1)

可以使用标记的环境变量。

enter image description here

使用此片段,您可以获取并打印所有环境变量。屏幕截图显示了执行此代码段的结果。

# Get all release environment variables
$environmentVars = get-childitem -path env:*

# Show each environment variable
foreach($var in $environmentVars){
    $keyname = $var.Key
    $keyvalue = $var.Value 
    Write-Verbose "${keyname}: $keyvalue" -Verbose
}

答案 3 :(得分:0)

我有相同的要求(获取触发构建的工件的路径),但是建议的解决方案对我不起作用-$ env:RELEASE_RELEASEDESCRIPTION为空。

原因: 这是因为发布是手动触发的。我们无法在这些版本中进行自动部署,因为大多数版本未部署,因此必须手动触发部署。但是,我缺少的一点是,虽然我们不希望自动触发构建中的任何 Environments ,但是可以自动创建 Release

解决方案: 一旦理解了这一点,并在Release定义中的每个工件上启用了CI触发器,但将所有Environment触发器都保留为“仅限手动”,则现在填充$ env:RELEASE_RELEASEDESCRIPTION,并且由“ stephgou”提出的方法会起作用。

如果TFS对此有更好的解决方案,那就太好了,因为解析描述绝对不好!最终,我们需要DropLocation,因此也需要将其添加为变量。

这是我的PowerShell脚本,用于从描述中获取DropLocation,这可能对某人有用:

#*================================================================================
#* Summary: This is a workaround for a TFS Limitation.
#*          Determines the Drop Location of a vNext build, as it is NOT provided in a variable for us!
#*
#* Output: values will be available in the following Build Step variables:
#*    $(TriggeringBuildID)
#*    $(TriggeringBuildNumber)
#*    $(TriggeringBuildUri)
#*    $(DropLocation)
#* Or, in a script:
#*    $env:TRIGGERINGBUILDID
#*    $env:TRIGGERINGBUILDNUMBER
#*    $env:TRIGGERINGBUILDURL
#*    $env:DROPLOCATION
#*================================================================================


Param (
    [string] $DeploymentScript = "_internalDeployment\DeployBuild_vNext.ps1"
)


$tfsServer=$env:SYSTEM_TEAMFOUNDATIONSERVERURI
$teamProject = $env:SYSTEM_TEAMPROJECT

# Default these, but as we may have multiple build artifacts associated with the release, need to get the triggering build ID if possible.
$script:buildID = $env:BUILD_BUILDID
$script:buildNumber = $env:BUILD_BUILDNUMBER
$script:buildURI = $env:BUILD_BUILDURI

Write "buildID = $script:buildID"
Write "buildNumber = $script:buildNumber"
Write "buildURI = $script:buildURI"

$ReleaseDescription = $env:RELEASE_RELEASEDESCRIPTION
if( $ReleaseDescription -and $ReleaseDescription.Length -gt 16 )
{
    Write "$ReleaseDescription = [$ReleaseDescription], Determining the Triggering Build."

    # This is a work-around for the fact TFS Release does not have any variables for the triggering build ID\Number (only has the Primary Artifact).
    # Hack is to get it from the Release's description, which is populated with trigger information IF it has CI-Trigger enabled.

    $buildChanged = $false

    # Parse the ReleaseDescription. Expected format: "Triggered by <ArtifactAlias> <BuildNumber>."
    # TODO a better way to do this? ... regex.
    $a,$b,$c,$d = $ReleaseDescription.split(' ')
    $TriggeringBuildNumber = $d.Remove($d.Length-1)
    Write "TriggeringBuildNumber = $TriggeringBuildNumber"

    if( $TriggeringBuildNumber -ne $script:buildNumber )
    {
        # Get the BuildId:
        $uri = "$tfsServer/$teamProject/_apis/build/builds?api-version=4.1&buildNumber=$TriggeringBuildNumber"
        Write "Invoking Method : GET $uri"
        $Build = Invoke-RestMethod -Method Get -UseDefaultCredentials -Uri "$uri"
        if( $Build[0] -and $Build.value -and $Build.value.Count -eq 1 -and $Build.value[0].id -ne 0)
        {
            $script:BuildId = $Build.value[0].id
            $script:buildNumber = $TriggeringBuildNumber    # = $Build.value[0].buildNumber
            $script:buildURI = $Build.value[0].url
            Write  "Build Found - ID is $BuildId."
            $buildChanged = $true
        }
        else
        {
            throw "Build not found"
        }
    }

    if( $buildChanged ) 
    {
        Write "buildID changed to $script:buildID"
        Write "buildNumber changed to $script:buildNumber"
        Write "buildURI changed to $script:buildURI"
    }
}
else
{
    # Allow for manually triggered build (but it has to be the primary artifact for this to work)
    $TriggeringBuildNumber = $script:buildNumber
}


# Determine the DropLocation from the BuildId.
# This is a work-around for the fact TFS Release does not have a variable for the DropLocation.
$BuildId = $script:buildID
Write "Get the DropLocation for buildId = $BuildId"
$DropLocation = ""
$DropLocationRoot = ""

# Get the build's artifacts
$uri = "$tfsServer/$teamProject/_apis/build/builds/$BuildId/artifacts?api-version=4.1"
Write "Invoking Method : GET $uri"
$artifacts = Invoke-RestMethod -Method Get -UseDefaultCredentials -Uri "$uri"

# Find the drop location (filepath)
foreach( $artifact in $artifacts.value )
{
    if( $artifact.name -eq $TriggeringBuildNumber -and $artifact.resource -and $artifact.resource.type -eq "filepath" -and  $artifact.resource.data )
    {
        $DropLocationRoot = $artifact.resource.data
        Write  "Artifact Found - DropLocationRoot is $DropLocationRoot."
        Break
    }
}
if( $DropLocationRoot -eq "" )
{ 
    throw "DropLocation not found."
}

$DropLocation = "$DropLocationRoot\$TriggeringBuildNumber"
Write  "DropLocation = $DropLocation"

if( Test-Path $DropLocation )
{
    Write  "Yay! - Drop folder Found at $DropLocation. :-)"
    $DeploymentScript = "$DropLocation\$DeploymentScript"
    if( Test-Path $DeploymentScript )
    {
        Write  "... and Yay, the Deployment Script was Found at $DeploymentScript. :-)"
    }
    else
    {
        throw "... but whoops! - Deployment Script was NOT Found. :-("
    }
}
else
{
    throw "whoops! - DropLocation [$DropLocation] does not exist. :-("
}


# Pass the values back out via $env vars.

# Note: tried using the below to reset the standard TFS System Variables, but it doesn't seem to take effect:
#Write-Host "##vso[task.setvariable variable=BUILD_BUILDID]$script:buildID"
#Write-Host "##vso[task.setvariable variable=BUILD_BUILDNUMBER]$script:buildNumber"
#Write-Host "##vso[task.setvariable variable=BUILD_BUILDURI]$script:buildURI"

Write-Host "##vso[task.setvariable variable=TRIGGERINGBUILDID]$script:buildID"
Write-Host "##vso[task.setvariable variable=TRIGGERINGBUILDNUMBER]$script:buildNumber"
Write-Host "##vso[task.setvariable variable=TRIGGERINGBUILDURI]$script:buildURI"
Write-Host "##vso[task.setvariable variable=DROPLOCATION]$DropLocation"