Запускать задание Azure Pipelines только при изменении определенных файлов

У меня есть репозиторий, содержащий как Dockerfile, так и другой код. Мы хотим выполнить определенные шаги независимо от того, что изменилось, но хотим запустить толькоdocker build работа, когда **/Dockerfile изменено.

Я рассмотрел документацию Условия и документацию Expressions, но неясно мне, как (если это вообще возможно), как объединить эти или иным образом достичь желаемого результата.

Я понимаю, что это возможно в bash (например git rev-list... а также git diff --name-only <previous_commit>..HEAD | grep <pattern>), но это немного громоздко, и в Azure Pipelines все еще отображается, что задание было выполнено, просто произошло короткое замыкание. В идеале это должно было показать (соответственно), что задание было пропущено полностью.

Я также понимаю, что часть Docker и часть кода могут находиться в отдельных репозиториях с отдельными триггерами сборки, но хотел бы, чтобы они были вместе в одном репо, если это возможно.

4 ответа

Решение

Извините, но для каждого задания нет триггера. Триггер для области трубопровода.

В соответствии с вашими требованиями вы можете использовать эту структуру как обходной путь:

jobs: 
  - job: OtherSteps
    steps:
    Your other steps in this job.
    - task: PowerShell@2
      inputs:
        targetType: 'inline'
        script: |
          $changedfiles = git diff ... (Choose right git command depending on your needs.)
          Write-Host $changedfiles
          If ($changedfiles.Contains("Dockerfile"))  {
            echo "##vso[task.setvariable variable=IfRunDockerBuild;isOutput=true]run"
          }
      name: 'DetermineIfRunNextJob'

  - job: DockerBuild
    dependsOn: OtherSteps
    condition: eq(dependencies.OtherSteps.outputs['DetermineIfRunNextJob.IfRunDockerBuild'],'run')
    steps:
    - script: echo Only run this job when IfRunDockerBuild=run instead of Null!

1. Предполагая, что у вас есть job1 и job2(сборка докеров), вам просто нужно добавить одну задачу PS, как указано выше, в конце job1. Затем он выводит одну переменную, которая определяет, нужно ли нам запускать job2 или пропускать его.

2. Задача Powershell может выполняться в Linux, macOS или Windows.

2. Суть этого обходного пути заключается в следующем: использование выходной переменной задания в условии в следующем задании.

Хотя вопрос старый, у меня была такая же проблема, и я думаю, что у меня есть хорошее решение. Задача состоит в том, чтобы гарантировать, что решение работает, даже если несколько коммитов отправляются одновременно, или если сборка завершается сбоем (и, следовательно, не развертывается) или при слиянии PR, когда развертывание происходит только в основной ветке.

Я полностью описал свое решение в этой сути: https://gist.github.com/Myrddraal/f5a84cf3242e3b3804fa727005ed2786 .

Он использует API конвейеров, который может предоставить список всех коммитов с момента последнего успешного выполнения конвейера. Это гарантирует, что он работает даже при одновременном выполнении нескольких коммитов или при сбое сборки с изменением инфраструктуры. API конвейеров выполняет тяжелую работу по определению того, какие коммиты нуждаются в проверке.

Логика в этом powershell:

      [CmdletBinding()]
param (
  $authorisation,
  $pathFilter,
  $collectionUri,
  $project,
  $buildId
)

$changesUrl = "$collectionUri/$project/_apis/build/builds/$buildId/changes?api-version=6.0"
$changesResponse = Invoke-RestMethod -Uri $changesUrl -Headers @{Authorization = $authorisation } -Method Get
$commits = @($changesResponse.value | ForEach-Object { $_.id })

Write-Host "##vso[task.setvariable variable=filesUpdated;isOutput=true]False"
Write-Host "Checking $($commits.Length) commits for changes matching path $pathFilter"
for ($j = 0; $j -lt $commits.Length; $j++) {
  Write-Host "Checking commit: $($commits[$j]) with its parent"
  $files = $(git diff "$($commits[$j])~" $commits[$j] --name-only)
  Write-Host $files
  if ($files -like "*$pathFilter/*") {
    Write-Host "Found file matching path filter in commit $($commits[$j])"
    Write-Host "##vso[task.setvariable variable=filesUpdated;isOutput=true]True"
    break
  }
}

Вызовите его с помощью следующего YAML (в задании сборки после извлечения репозитория):

        - task: PowerShell@2
    inputs:
      filePath: "azure-pipelines/Test-ChangesMadeInPath.ps1"
      arguments: >-
        -authorisation "Bearer $(system.accesstoken)" 
        -pathFilter "azure-pipelines/deployment" 
        -buildId $(Build.BuildId)'
        -collectionUri $(System.CollectionUri)
        -project $(System.TeamProject)
    name: DetermineChangesMadeInDeploymentFolder
    env:
      SYSTEM_ACCESSTOKEN: $(system.accesstoken)

Затем добавьте следующее условие в задание развертывания:

        - deployment: DeployInfrastructure
    condition: eq(stageDependencies.Build.BuildJob.outputs['DetermineChangesMadeInDeploymentFolder.filesUpdated'], 'True')
    displayName: Deploy infrastructure
    environment: "prod"
    strategy:
      runOnce:
        deploy:
          steps:
            - template: deployment/YAML/deploy-infrastructure.yml
              parameters:
                environment: $(Environment.Name)

Примечание. Ответ DaveF работает хорошо, но теперь вам нужно добавить указание предыдущего шага оформления заказа как:

      steps:
- checkout: self
  fetchDepth: 0

Дополнительную информацию см. в неоднозначном аргументе HEAD^ в конвейере Azure DevOps.

Вы можете определить paths/include так же как paths/excludeфильтр по каждому триггеру. Я не смог найти это на обычном сайте документации, но репозиторий YAML четко объясняет это:

Пример:

trigger:
  batch: true
  branches:
    include:
    - features/*
    exclude:
    - features/experimental/*
  paths:
    include:
    - **/Dockerfile

PS: Не совсем уверен, поддерживаются ли подстановочные знаки и какой синтаксис для них использовать.

Другие вопросы по тегам