在 VSTS 上仅运行一个构建实例 [英] Run only one instance of a build on VSTS
问题描述
我在 VSTS 中有一个代理队列,其中包含多个代理,并且我有一个分配给该队列的构建.有什么方法可以告诉 VSTS 一次只运行一个构建实例,其他实例(安排在其他代理上)应该等到前一个实例完成?
I have an agent queue in VSTS with several agents and I have a build assigned to this queue. Is there any way of telling VSTS that only one instance of the build should be run at a time, and the other instances (scheduled on other agents) should wait until the previous one finishes?
我需要这个,因为测试会创建一个临时数据库,在该数据库上运行集成测试,如果多个实例针对同一个数据库运行,那么它们会相互干扰.
I need this because the tests create a temp database on which integration tests are run and if multiple instances are running against the same database then they interfere with each other.
推荐答案
我们实施了自定义 VSTS 任务来执行此操作.它工作得很好.这是代码.
We implemented a custom VSTS task to do this. It works swimmingly. Here is the code.
如果创建自定义 VSTS 任务不是您的事 - 您可以去掉 PowerShell.只需将值作为参数传递即可.
If creating a custom VSTS task isn't your thing - you can strip out the PowerShell. Just have to pass the values as parameters instead.
/ Project-Folder
- extension-icon.png
- extension-manifest.json
/ Tasks
/ KeepBuildSynchronous
- icon.png
- task.json
- task.ps1
extension-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 "$PSScriptRootTask.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
我会留下一点神秘感,让您了解如何将其发布到市场并将其安装在您的构建代理上
这篇关于在 VSTS 上仅运行一个构建实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!