Skip to content

Instantly share code, notes, and snippets.

@Myrddraal
Last active January 16, 2024 13:24
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Myrddraal/f5a84cf3242e3b3804fa727005ed2786 to your computer and use it in GitHub Desktop.
Save Myrddraal/f5a84cf3242e3b3804fa727005ed2786 to your computer and use it in GitHub Desktop.
Skip infrastructure deployments if there are no changes to deploy (Azure Pipelines)

Skip infrastructure deployments if there are no changes to deploy (Azure Pipelines)

One devops strategy is to keep infrastructure state and code in a single repository, and deploy them together. It ensures your infrastructure is always in the correct state to match the version of your code.

The downside is that infrastructure deployments are slow, and generally don't change as frequently as code.

This gist shows how to skip an infrastructure deployment task if there are no changes in a particular sub-path of the repository.

It takes advantage of the pipelines API, which can provide a list of all commits since the last successful pipeline execution. This ensures that it works even when multiple commits are pushed at once, or when the build with the infrastructure change failed. The pipelines API does the hard work of working out which commits need checking.

Example of skipped infra deployment

resources:
repositories:
- repository: self
type: git
ref: main
stages:
- stage: Build
pool:
vmImage: ubuntu-latest
jobs:
- job: BuildJob
displayName: Build Job
steps:
- checkout: self
clean: true
- 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)
- task: DotNetCoreCLI@2
displayName: Build project
inputs:
projects: "**/*.csproj"
arguments: --output publish_output --configuration Release
- task: PublishBuildArtifacts@1
displayName: "Publish Artifact: drop"
- stage: Deploy
pool:
vmImage: ubuntu-latest
condition: and(succeeded(), eq(variables['build.sourceBranch'], 'refs/heads/main'))
jobs:
- 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)
- deployment: DeployCode
displayName: Deploy code
dependsOn: DeployInfrastructure
condition: in(dependencies.DeployInfrastructure.result, 'Succeeded', 'Skipped')
environment: "prod"
strategy:
runOnce:
deploy:
steps:
- template: deployment/YAML/deploy-code.yml
parameters:
environment: $(Environment.Name)
[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
}
}
@gprestes
Copy link

@Myrddraal
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment