How do you add a manual intervention step into a multi-stage Azure Devops YAML pipeline?
In jenkins you can do some thing like:
stage ('approve-prod') {
steps {
input "Approve deployment to production?"
}
}
I am looking for the equivalent in Azure Devops YAML.
Note: this is for the newly released multi-stage Azure Devops pipelines, not the old style release pipelines. Related announcement here https://devblogs.microsoft.com/devops/whats-new-with-azure-pipelines/
In Azure DevOps Server 2019, pools can only be specified at job level. This version of TFS doesn't support YAML pipelines. To add a stage to your release pipeline, select the release pipeline in Releases page, select the action to Edit it, and then select the Pipeline tab.
Edit a YAML pipeline Sign in to your organization ( https://dev.azure.com/{yourorganization} ). Select your project, choose Pipelines > Pipelines, and then select the pipeline you want to edit. Choose Edit. Make edits to your pipeline using Intellisense keyboard shortcuts and the task assistant for guidance.
Microsoft have now made available a brand new official Manual Validation task that allows for manual intervention to be added into a YAML pipeline.
Quick example of how to use this task is as follows:
jobs:
- job: waitForValidation
displayName: Wait for external validation
pool: server
timeoutInMinutes: 4320 # job times out in 3 days
steps:
- task: ManualValidation@0
timeoutInMinutes: 1440 # task times out in 1 day
inputs:
notifyUsers: |
[email protected]
[email protected]
instructions: 'Please validate the build configuration and resume'
onTimeout: 'resume'
Some key constraints to be aware of:
This doesn't appear to be available yet, but there is a GitHub Issue tracking this: https://github.com/MicrosoftDocs/vsts-docs/issues/4241
From the issue:
So what I heard from the product team is that this "approval per stage" policy isn't available yet but is on their backlog.
There is also a Roadmap work item tracking it: https://dev.azure.com/mseng/AzureDevOpsRoadmap/_workitems/edit/1510336/
Azure DevOps/Pipelines now has a feature called Environments which supports approvals. https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments?view=azure-devops#approvals
We are using them as a workaround. Basically we have specified two environments ApprovalNotRequired and ApprovalRequired in Azure DevOps. On the latter we have specified who can approve deployments. Then in the pipeline we reference the environment like this.
- stage: 'Approval not required'
jobs:
- deployment: 'MyDeployment'
displayName: MyDeployment
environment: 'ApprovalNotRequired'
strategy:
runOnce:
deploy:
# whatever
- stage: 'Approval required'
jobs:
- deployment: 'MyDeployment2'
displayName: MyDeployment2
environment: 'ApprovalRequired'
strategy:
runOnce:
deploy:
# whatever
The first stage will run without interference and the second will pause until it's approved.
Because there's a long time since Microsoft is ignoring this, and because this is a critical missing functionality , I will add an workaround here (for the moment, it's working only to ignore the entire step for all machines in case of a multi stage YAML but I think this can be solved also, but I am not looking into it for the moment).
Unfortunately, there is a task that needs to be added before each task. This can be solved also by iterative insertion (https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops).
Shortly, in order to be able to ignore a specific task:
For adding tags, I am using the API because there is no task to do it yet. For request details, F21 in Chrome and check what it sent to server after you will add a tag, and export the request to power shell.
Below you have the YAML:
trigger: none
jobs:
- deployment: Dev
environment:
name: Dev
resourceType: virtualMachine
tags: online
strategy:
runOnce:
deploy:
steps:
- task: PowerShell@2
displayName: CheckIfWeShouldIgnoreStep
name: CheckIfWeShouldIgnoreStep
inputs:
targetType: 'inline'
script: |
$user = "user"
$pass= "pass"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
$response = Invoke-RestMethod -Uri "https://server/tfs/collection/projectId/_apis/build/builds/$(Build.BuildId)/tags" `
-Method "GET" `
-Headers @{
"accept"="application/json;api-version=6.0;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
} `
-ContentType "application/json" `
-Credential $credential -UseBasicParsing
Write-Host "##vso[task.setvariable variable=IgnoreStep]false"
Write-Host "Tags: $response"
foreach($tag in $response)
{
if($tag -eq "IgnoreStep")
{
Write-Host "##vso[task.setvariable variable=IgnoreStep]true"
Invoke-RestMethod -Uri "https://server/tfs/collection/projectId/_apis/build/builds/$(Build.BuildId)/tags/IgnoreStep" `
-Method "DELETE" `
-Headers @{
"accept"="application/json;api-version=6.0;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
}`
-Credential $credential -UseBasicParsing
}
}
- task: PowerShell@2
displayName: Throw Error
condition: eq (variables.IgnoreStep, false)
inputs:
targetType: 'inline'
script: |
throw "Error"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With