在VSTS上仅运行一个构建实例

时间:2018-02-19 06:28:40

标签: azure-devops

我在VSTS中有一个代理队列,有几个代理,我有一个分配给这个队列的构建。有没有办法告诉VSTS一次只能运行一个构建实例,其他实例(在其他代理上安排)应该等到上一个实例完成?

我需要这个,因为测试会创建一个运行集成测试的临时数据库,如果多个实例针对同一个数据库运行,那么它们会相互干扰。

4 个答案:

答案 0 :(得分:2)

我们实施了自定义VSTS任务来执行此操作。它运作良好。这是代码。

如果您不想创建自定义VSTS任务,则可以删除PowerShell。只需将值作为参数传递。

文件结构

/ Project-Folder
    - extension-icon.png
    - extension-manifest.json
    / Tasks
        / KeepBuildSynchronous
            - icon.png
            - task.json
            - task.ps1

伸展的manifest.json

{
    "manifestVersion": 1,
    "id": "your-task-name",
    "name": "your-package-name",
    "version": "0.0.1",
    "publisher": "your-publisher-account",
    "targets": [
        {
            "id": "Microsoft.VisualStudio.Services"
        }
    ],    
    "description": "your-description",
    "categories": [
        "Build and release"
    ],
    "icons": {
        "default": "extension-icon.png"        
    },
    "files": [
        {
            "path": "Tasks/KeepBuildSynchronous"
        }
    ],
    "contributions": [
        {
            "id": "12345678-0000-0000-0000-000000000000", <-- must match task.json id
            "type": "ms.vss-distributed-task.task",
            "targets": [
                "ms.vss-distributed-task.tasks"
            ],
            "properties": {
                "name": "Tasks/KeepBuildSynchronous"
            }
        }
    ]
}

task.json

{
    "id": "12345678-0000-0000-0000-000000000000",
    "name": "keepBuildSynchronous",
    "friendlyName": "Keep Build Synchronous",
    "description": "Only allow one build with the same build definition to run at a time",
    "helpMarkDown": "",
    "category": "Utility",
    "visibility": [
        "Build"
    ],
    "runsOn": [
        "Agent",
        "DeploymentGroup"
    ],
    "author": "-your team-",
    "version": {
        "Major": 1,
        "Minor": 1,
        "Patch": 1
    },
    "releaseNotes": "Initial release",
    "minimumAgentVersion": "1.91.0",
    "inputs": [
        {
            "name": "waitTimeinMinutes",
            "type": "int",
            "label": "How many minutes do you want to wait before cancelling the build",
            "defaultValue": "15",
            "required": true,
            "helpMarkDown": ""
        }
    ],
    "instanceNameFormat": "Keep Build Synchronous",
    "execution": {
        "PowerShell3": {
            "target": "task.ps1"
        }
    }
}

task.ps1

[CmdletBinding()]
Param ()

Trace-VstsEnteringInvocation $MyInvocation
try {
    Import-VstsLocStrings "$PSScriptRoot\Task.json"

    # Get agent/build variables
    [string]$teamFoundationCollectionUri = Get-VstsTaskVariable -Name "system.teamFoundationCollectionUri"
    [string]$teamProjectId = Get-VstsTaskVariable -Name "system.teamProjectId"
    [string]$buildId = Get-VstsTaskVariable -Name "build.buildId"
    [int]$definitionId = Get-VstsTaskVariable -Name "system.definitionId" -AsInt
    [string]$accessToken = Get-VstsTaskVariable -Name "system.accessToken"

    # Get task inputs
    [int]$waitTimeinMinutes = Get-VstsInput -Name waitTimeinMinutes -AsInt

    [Object[]]$global:buildsByDefinition = $null
    [Object[]]$global:runningBuilds = $null

    function Get-Builds-By-Definition([int]$definitionId) {
        $url = "$teamFoundationCollectionUri/$teamProjectId/_apis/build/builds?api-version=2.0&definitions=$definitionId"

        $type = "application/json"
        $headers = @{
            Authorization = "Bearer $accessToken"
        }
        $global:buildsByDefinition = (Invoke-RestMethod -Uri $url -ContentType $type -Method Get -Headers $headers).value
        $global:runningBuilds = $buildsByDefinition | Where-Object -Property "status" -Value "inProgress" -EQ
    }

    [datetime]$startedAt = Get-Date
    [datetime]$waitUntil = $startedAt.AddMinutes($waitTimeinMinutes)

    Get-Builds-By-Definition -definitionId $definitionId

    [string]$buildDefinitionName = $buildsByDefinition[0].definition.name

    Write-Host ""
    Write-Host "Build definition ..... $buildDefinitionName"
    Write-Host "Current build ........ $buildId"
    Write-Host ""
    Write-Host "Started at ........... $startedAt"
    Write-Host "Willing to wait until  $waitUntil"
    Write-Host ""

    while (1 -eq 1) {

        if ((Get-Date) -gt $waitUntil) {
            Write-Host "Waited too long (cancelling)"
            throw "Waited longer than $waitTime minutes to start.  Cancelling."
        }

        if ($global:runningBuilds -eq $null) {
            Write-Host "No build running (weird, but ok...)"
            break
        }

        [int]$firstToGo = ($global:runningBuilds | Sort-Object -Property "Id")[0].Id

        if ($global:runningBuilds.Count -le 1 -or $buildId -le $firstToGo) {
            Write-Host "Your turn to shine"
            break
        } else {
            Write-Host "$($global:runningBuilds.Count) builds running. $firstToGo is next. (checking again)"
            Start-Sleep -Seconds 15
        }

        Get-Builds-By-Definition -definitionId $definitionId

    }
}
finally {
    Trace-VstsLeavingInvocation $MyInvocation
}

创建.vsix文件

tfx extension create --manifest-globs extension-manifest.json --rev-version

我会留下一些神秘感,让您了解如何将其发布到市场并将其安装到您的构建代理上

答案 1 :(得分:1)

我看来这对于手动触发的构建是不可能的(arghh)。 但是,对于CI构建,可以将DevOps配置为在构建运行时捆绑更改。 转到构建定义的“触发器”选项卡。 检查:

  • 启用持续集成
  • 在构建过程中进行批量更改

答案 2 :(得分:0)

您无法在构建级别(You can vote for this feature here)配置此功能,但也许您可以在阶段级别完成所需的操作。

查看每个阶段下的Parallelism选项。您似乎希望将此设置为&#34;无&#34;如果你看到行为相反。 &#34;无&#34;是新版本的默认选项。

Parallelism Options

答案 3 :(得分:0)

不,没有这样的设置来控制它,它由管道控制:Concurrent build and release pipelines in VSTS

您可以禁用其他代理:

  1. Go do Agent Queues管理页面
  2. 选择队列
  3. 取消选中代理以将其停用
  4. 另一方面,您可以创建一个名为include build number的临时数据库,然后它们不会相互干扰。