11

为了自动化我们的部署,我想根据给定的 ChangeSetId 重建一个应用程序。构建完成后,我想获取构建的工件(.exe),以便我们部署它们。为了这个问题,我将重点放在“从构建中获取工件”部分。

出于 DevOps 的目的,我想使用 PowerShell,因为它应该能够访问 TFS API 库并且因为 MS 建议使用它。

环境

我已经在我们的 On Premise TFS 2015 服务器(运行良好)中设置了构建 - 并在此构建之后添加了一个VSO 任务“发布工件”。到目前为止,一切都很好。发布的工件将存储在服务器上,这基本上意味着我必须下载连接到构建的工件 - 每个现有构建都将链接其工件 - 这比我书中的 UNC 下降更好。

不,我的挑战来了;如何以编程方式访问这些工件,步骤 3?

  1. 获取 ChangeSetId 的来源
  2. 具有给定配置的 MSBuild 应用程序
  3. 使用 PowerShell 获取构建工件
  4. 使用发布管理(也包括 Powershell)部署到环境
4

2 回答 2

10

TFS 2015 带有新的 REST API,它包括获取特定构建工件的方法。我将通过以下方式应对您的挑战:

  • 在“发布工件”步骤之后添加“PowerShell 脚本”构建步骤
  • 在那个 PowerShell 脚本中:
    • 获取当前构建的 ID。TFS 公开了许多预定义的变量,并且构建 ID 在那里。所有这些变量最终都成为环境变量,这篇文章可以帮助您从 PowerShell 脚本中读取适当的变量
    • 接下来,发出 Web 请求以获取构建工件。从 API 描述中可以看出,您只需提供构建 ID
    • 然后,解析 JSON 响应 - 该downloadUrl属性包含用于下载压缩为单个存档的构建的所有工件的链接
    • 最后,提取存档并获取您需要的那些工件。也许,您也想在此步骤中将其部署到您的测试环境中

希望这可以帮助。

于 2015-09-14T08:19:47.450 回答
7

好吧,就像 Yan Sklyarenko 所说,TFS 2015(和 2013,经过一些更新)具有出色的 REST API。

我创建了一个非常非常粗略的基本 PowerShell 脚本,它可以满足我的需求。我不能足够强调这段代码需要重构多少——我真的只是需要它作为概念证明,我们将针对不同的需求开发多个脚本,但是对于来这里获取代码示例的人,你会发现在这里。

  1. 连接到 TFS 的构建系统
  2. 列出构建定义项目(对于我自己,Poc)
  3. 搜索一些字符串并获取构建 ID
  4. 使用硬编码的 ID 7 开始构建(因为我知道这会起作用,因此我的工作已经完成)
  5. 获取工件(我在其中合并了 VSO 构建任务“发布工件服务器”)
  6. Extract 说收到的Artifacts,因为 TFS 压缩它们。

从那时起,我将把这些脚本和输出合并到 MS 发布管理服务中 - 并准备好在为本地 TFS 2015 发布时迁移到 VSO Release vNext!

    $projectId ='{ProjectIdGuid}'
    $buildNr = '3945' 
    $username =  'username'
    $password  =  'password' 
    $zipDestination = 'C:\temp\unzip\temp.zip'
    $workingFolder = ('C:\temp\unzip\' + [System.DateTime]::Now.ToString("yyyyMMddhhmmss"))  #temp because of file already exist warnings... after completion we should delete the working directory content
    $tfsURL = 'http://myTFS:8080/tfs/MyCollection/'+ $projectId 

    $cred = New-Object System.Management.Automation.PSCredential($username, (ConvertTo-SecureString -String $password -AsPlainText -Force))

    #write list of build definitions (to be used later)
    $allbuildDefs = (Invoke-RestMethod -Uri ($tfsURL + '/_apis/build/definitions?api-version=2.0') -Method GET -Credential $cred).value | Where-Object {$_.name -like '*buildName*'} | Out-Default | select name
    Write-Host($allbuildDefs)


    $buildDefs = ConvertFrom-Json($allbuildDefs) 
    $buildId = ($buildDefs.value).id;


    #Get build Definition for what you want to build
    $buildDefinitionURI = $tfsURL + '/_apis/build/requests?api-version=1.0'


    #kick off build 
    $body = '{ "definition": { "id": '+ 7 + '}, reason: "Manual", priority: "Normal"}'
    $BuildReqBodyJson =  $body | ConvertTo-Json
    $buildOutput = Invoke-RestMethod -Method Post -Uri $buildDefinitionURI -Credential $cred -ContentType 'application/json' -Body $body

    #get buildNr


    #build URI for buildNr
    $BuildURI = $tfsURL + '/_apis/build/builds/' + $buildNr + '/artifacts'

    #get artifact downloadPath
    $downloadURL = (Invoke-RestMethod -Uri $BuildURI -Credential $cred).Value.Resource.downloadUrl

    #download ZIP
    Invoke-WebRequest -uri $downloadURL -Credential  $cred -OutFile $zipDestination

    #unzip
    Add-Type -assembly 'system.io.compression.filesystem'
    [io.compression.zipfile]::ExtractToDirectory($zipDestination, $workingFolder)
于 2015-09-14T17:56:42.960 回答