Azure DevOps 파이프 라인의 조건부 단계 실행

Dec 09 2020

이전 단계에서 설정된 변수의 내용에 따라 Azure DevOps 파이프 라인의 단계가 실행되기를 원합니다.

내 파이프 라인은 다음과 같습니다.

stages:
  - stage: plan_dev
    jobs:
    - job: terraform_plan_dev
      steps:
      - bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
        name: terraform_plan

  - stage: apply_dev
    dependsOn: plan_dev
    condition: eq(stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'], '2')
    jobs:
    - deployment: "apply_dev"
      ...

아이디어는 apply_dev무대에 plan_dev변화가 없으면 무대 를 건너 뛰는 것입니다 . 배경은 승인 plan_dev할 변경 사항이없는 경우 건너 뛰려 는 단계 에서 배포에 대한 수동 승인이 있다는 것 입니다.

불행히도 이것은 작동하지 않는 것 같습니다. 변수 terraform_plan_exitcode가 예상 값 (2)으로 설정 되었는지 여부에 관계없이 apply_dev스테이지를 건너 뜁니다.

구문에 대해서는 다음과 같은 문서를 따랐습니다 .

stageDependencies.StageName.JobName.outputs['StepName.VariableName']

답변

1 MariusSolbakkenMellum Dec 09 2020 at 22:00

나는이 같은 문제를 보았다. stageDependencies 대신 종속성 변수를 사용해야합니다.

stages:
- stage: plan_dev
jobs:
- job: terraform_plan_dev
  steps:
  - bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
    name: terraform_plan

- stage: apply_dev
dependsOn: plan_dev
condition: eq(dependencies.plan_dev.outputs['terraform_plan_dev.terraform_plan.terraform_plan_exitcode'], '2')
jobs:
- deployment: "apply_dev"

다음은 Terraform Plan + 조건부 적용으로 작업 한 것의보다 완전한 예입니다.


stages: 
  - stage: Build_zip_plan
    displayName: Build portal, zip files and terraform plan
    jobs:
    - job: Build_portal_zip_files_terraform_plan
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - task: Cache@2
          displayName: 'Register TF cache'
          inputs:
            key: terraform | $(Agent.OS) | $(Build.BuildNumber) | $(Build.BuildId) | $(Build.SourceVersion) | $(prefix) path: ${{ parameters.tfExecutionDir }}

        - task: TerraformInstaller@0
          displayName: 'Install Terraform'
          inputs:
            terraformVersion: ${{ parameters.tfVersion }} - task: TerraformTaskV1@0 displayName: 'Terraform Init' inputs: provider: 'azurerm' command: 'init' workingDirectory: ${{ parameters.tfExecutionDir }}
            backendServiceArm: ${{ parameters.tfStateServiceConnection }} backendAzureRmResourceGroupName: ${{ parameters.tfStateResourceGroup }}
            backendAzureRmStorageAccountName: ${{ parameters.tfStateStorageAccount }} backendAzureRmContainerName: ${{ parameters.tfStateStorageContainer }}
            backendAzureRmKey: '$(prefix)-$(environment).tfstate'

        - task: TerraformTaskV1@0
          displayName: 'Terraform Plan'
          inputs:
            provider: 'azurerm'
            command: 'plan'
            commandOptions: '-input=false -out=deployment.tfplan -var="environment=$(environment)" -var="prefix=$(prefix)" -var="tenant=$(tenant)" -var="servicenow={username=\"$(servicenowusername)\",instance=\"$(servicenowinstance)\",password=\"$(servicenowpassword)\",assignmentgroup=\"$(servicenowassignmentgroup)\",company=\"$(servicenowcompany)\"}" -var="clientid=$(clientid)" -var="username=$(username)" -var="password=$(password)" -var="clientsecret=$(clientsecret)" -var="mcasapitoken=$(mcasapitoken)" -var="portaltenantid=$(portaltenantid)" -var="portalclientid=$(portalclientid)" -var="customerdisplayname=$(customerdisplayname)" -var="reportonlymode=$(reportonlymode)"' workingDirectory: ${{ parameters.tfExecutionDir }}
            environmentServiceNameAzureRM: ${{ parameters.tfServiceConnection }} - task: PowerShell@2 displayName: 'Check Terraform plan' name: "Check_Terraform_Plan" inputs: filePath: '$(Build.SourcesDirectory)/Pipelines/Invoke-CheckTerraformPlan.ps1'
            arguments: '-TfPlan ''${{ parameters.tfExecutionDir }}/deployment.tfplan''' pwsh: true - stage: dependsOn: Build_zip_plan displayName: Terraform apply condition: eq(dependencies.Build_zip_plan.outputs['Build_portal_zip_files_terraform_plan.Check_Terraform_Plan.TFChangesPending'], 'yes') jobs: - deployment: DeployHub displayName: Apply pool: vmImage: 'ubuntu-latest' environment: '$(prefix)'
      strategy:
        runOnce:
          deploy:
            steps:
            - checkout: self

            - task: Cache@2
              displayName: 'Get Cache for TF Artifact'
              inputs:
                key: terraform | $(Agent.OS) | $(Build.BuildNumber) | $(Build.BuildId) | $(Build.SourceVersion) | $(prefix) path: ${{ parameters.tfExecutionDir }}
                
            - task: TerraformInstaller@0
              displayName: 'Install Terraform'
              inputs:
                terraformVersion: ${{ parameters.tfVersion }} - task: TerraformTaskV1@0 displayName: 'Terraform Apply' inputs: provider: 'azurerm' command: 'apply' commandOptions: 'deployment.tfplan' workingDirectory: ${{ parameters.tfExecutionDir }}
                environmentServiceNameAzureRM: ${{ parameters.tfServiceConnection }}
1 KrzysztofMadej Dec 09 2020 at 22:32

@Marius가 맞습니다. 그래서 이것은 작동합니다

stages:
  - stage: plan_dev
    jobs:
    - job: terraform_plan_dev
      steps:
      - bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
        name: terraform_plan

  - stage: apply_dev
    dependsOn: plan_dev
    variables:
      varFromA: $[ stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'] ] condition: eq(dependencies.plan_dev.outputs['terraform_plan_dev.terraform_plan.terraform_plan_exitcode'], 2) jobs: - job: apply_dev steps: - bash: echo 'apply $(varFromA)'
        name: terraform_apply

스테이지에서 스테이지 종속성 을 참조 할 때 다른 구문이 있습니다.

"dependencies": {
  "<STAGE_NAME>" : {
    "result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
    "outputs": {
        "jobName.stepName.variableName": "value"
    }
  },
  "...": {
    // another stage
  }
}

그리고 단계에서 작업을 참조 할 때 다른 구문을 사용합니다.

"stageDependencies": {
  "<STAGE_NAME>" : {
    "<JOB_NAME>": {
      "result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
      "outputs": {
          "stepName.variableName": "value"
      }
    },
    "...": {
      // another job
    }
  },
  "...": {
    // another stage
  }
}

한 단계에서 일할 때 재밌는 점은 우리는 dependecies구문을 다시 사용 합니다.

"dependencies": {
  "<JOB_NAME>": {
    "result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
    "outputs": {
      "stepName.variableName": "value1"
    }
  },
  "...": {
    // another job
  }
}

이것은 약간 혼란스럽고 이것을 다음과 같이 고려하십시오.

  • 당신이 어떤 수준의 단계에있을 때, 직업과 직업에서 직업으로 또는 단계에서 단계로 같은 수준을 참조하면 dependencies구문 이 있습니다.
  • 직업에서 단계까지와 같이 더 깊은 수준에서 참조하고 싶을 때 사용해야합니다. stageDependencies

재미있는 것은 위의 예에서 나는 이것을 무대 수준에서 사용했습니다.

variables:
      varFromA: $[ stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'] ]

그러나 이것은 런타임에 평가되고 작업에서 평가되므로 정확하고 올바르게 평가됩니다.

나는 그것이 이전 답변에 가치를 더하기를 바랍니다.