【问题标题】:How to determine the build definition that triggered a release in TFS?如何确定在 TFS 中触发发布的构建定义?
【发布时间】:2017-09-26 13:53:14
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: tfs tfsbuild release-management tfvc


    【解决方案1】:

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

    【讨论】:

    • 这也是我在筛选环境变量后发现的。我真的不喜欢分析自动生成的描述值的想法,但这似乎是今天唯一的方法。非常感谢您的确认。
    • 这对我来说是一个很好的解决方案,最终帮助解决了在触发源中有多个工件时查看是什么触发了发布的问题。谢谢你
    【解决方案2】:

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

    要了解哪个构建触发了您的发布,您可以参考发布摘要页面

    【讨论】:

    • 好的,但是是否可以在发布定义本身中获取此信息,而不仅仅是在发布发布之后,例如使用预定义的变量等?我的目标是根据实际触发发布的构建更改部署的构建工件的路径。
    • @Powdermountain99 发布环境变量只提供让谁触发发布,不提供哪个构建触发它。 visualstudio.com/en-us/docs/build/concepts/definitions/release/…
    • 对不起,看看我的帖子。您可以找出触发了哪个版本的发布。从我的帖子中获取 PowerShell sn-p 并使用 MS PowerShell 步骤的内联函数执行它。
    【解决方案3】:

    有可能,你可以使用标记的环境变量。

    使用这个 sn-p 你可以获取并打印所有环境变量。截图显示了执行这个 sn-p 的结果。

    # 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
    }
    

    【讨论】:

    • 环境变量 BUILD_BUILDNUMBER 是否与发布管理文档中visualstudio.com/en-us/docs/build/concepts/definitions/release/… 下所述的“主要工件变量”“Build.DefinitionName”不同?是触发的实际构建还是只是主要工件的构建名称?
    • 截图可以看到,变量“BUILD_BUILDNUMBER”的值就是触发的构建定义。
    • 正如我上面提到的,BUILD_BUILDNUMBER 不包含触发构建定义的构建号,而是包含在发布定义的工件列表中标记为“主要”的构建号。
    【解决方案4】:

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

    原因: 这是因为释放是手动触发的。我们不能在这些构建中进行自动部署,必须手动触发部署,因为大多数构建都没有部署。但是,我缺少的一点是,虽然我们不希望构建中的任何 Environments 自动触发,但可以自动创建 Release .

    解决办法: 一旦我理解了这一点,并在发布定义中的每个工件上启用 CI 触发器,但将所有环境触发器保持为“仅限手动”,现在填充 $env:RELEASE_RELEASEDESCRIPTION,并且“stephgou”提出的方法会工作的。

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

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

    #*================================================================================
    #* 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"

    【讨论】:

    • 注意:上面的脚本有一个问题:- 在最后我试图设置的 4 个值中,只有 DROPLOCATION 在阶段执行的下一个脚本中有一个值。未设置 3 个 BUILD_* 变量。我最初没有注意到这一点,因为只有 DROPLOCATION 对下一步至关重要,直到最近 BUILD_BUILDID 变得重要的变化,所以我注意到了这个问题。因此,需要从需要这些值的任何其他脚本中执行此脚本,或者设置自定义变量(例如我的 DROPLOCATION)以传递到下一步。
    • 已更新我的脚本以更正将构建标识值传递回调用方。
    猜你喜欢
    • 1970-01-01
    • 2015-04-24
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 2018-11-20
    • 2015-11-27
    • 1970-01-01
    相关资源
    最近更新 更多