Search code examples
yamlazure-pipelinesdryazure-pipelines-yaml

How to simplify Azure pipeline and avoid to much repeating


I have this pipeline (non relevant parts removed):

stages:
  - stage: 'PreSteps'
    displayName: 'Preparation Steps'
    jobs:
    - job: 'Check_changes'
      steps:
        - task: Bash@3
          name: 'bash_script1'
          inputs:
            targetType: 'inline'
            script: |
              # do some stuff
              
              echo "##vso[task.setvariable variable=SomeVariable_1;isOutput=True]SomeValue_1"
              echo "##vso[task.setvariable variable=SomeVariable_2;isOutput=True]SomeValue_2"
              echo "##vso[task.setvariable variable=SomeVariable_3;isOutput=True]SomeValue_3"
              echo "##vso[task.setvariable variable=SomeVariable_4;isOutput=True]SomeValue_4"
              echo "##vso[task.setvariable variable=Changes;isOutput=True]4"

  - stage: 'S_Build'
    dependsOn: 'PreSteps'
    condition: gt(dependencies.PreSteps.outputs['Check_changes.bash_script1.Changes'], 0)
    displayName: 'Build and Publish Changed Projects'
    variables:
      Project_1: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_1'] ]
      Project_2: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_2'] ]
      Project_3: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_3'] ]
      Project_4: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_4'] ]
    jobs:
    - template: build.yml
      parameters:
        Projects:
        - $(Project_1)
        - $(Project_2)
        - $(Project_3)
        - $(Project_4)

  - stage: 'D_Release'
    dependsOn:
      - 'S_Build'
      - 'PreSteps'
    condition: eq(stageDependencies.S_Build.result, 'Succeeded')
    displayName: 'Release Changed Projects to DEV'
    variables:
      Project_1: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_1'] ]
      Project_2: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_2'] ]
      Project_3: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_3'] ]
      Project_4: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_4'] ]
    jobs:
    - template: release.yml
      parameters:
        Projects:
        - $(Project_1)
        - $(Project_2)
        - $(Project_3)
        - $(Project_4)

  - stage: 'P_Release'
    dependsOn:
      - 'D_Release'
      - 'PreSteps'
    condition: eq(stageDependencies.D_Release.result, 'Succeeded')
    displayName: 'Release Changed Projects to PROD'
    variables:
      Project_1: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_1'] ]
      Project_2: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_2'] ]
      Project_3: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_3'] ]
      Project_4: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_4'] ]
    jobs:
    - template: release.yml
      parameters:
        Projects:
        - $(Project_1)
        - $(Project_2)
        - $(Project_3)
        - $(Project_4)

Basically I'm generating some values in bash_script1 which I need to use across all the stages. Is there a way to avoid repeating the variables in each stage? I can't use the syntax $[ ] directly in the parameters as they don't get expanded in the template.


Solution

  • You can use runtime parameters to simplify above yaml pipeline. Please check out below steps:

    1, Define the stage name and template in the runtime parameters section:

    parameters:
    - name: Stages
      type: object
      default:
      - StageName: S_Build
        Template: build.yml 
        Depends: PreSteps
      - StageName: D_Release
        Template: release.yml
        Depends: S_Build
      - StageName: P_Release
        Template: release.yml
        Depends: D_Release
    

    2, Using ${{...}} expression to loop through the Stages parameters: See below full example:

    parameters:
    - name: Stages
      type: object
      default:
      - StageName: S_Build
        Template: build.yml 
        Depends: PreSteps
      - StageName: D_Release
        Template: release.yml
        Depends: S_Build
      - StageName: P_Release
        Template: release.yml
        Depends: D_Release
    
    trigger: none
    #
    stages:
    - stage: PreSteps
      jobs: 
      - job: Check_changes
        steps:
        - task: Bash@3
          name: 'bash_script1'
          inputs:
            targetType: 'inline'
            script: |
              # do some stuff
              
              echo "##vso[task.setvariable variable=SomeVariable_1;isOutput=True]SomeValue_1"
              echo "##vso[task.setvariable variable=SomeVariable_2;isOutput=True]SomeValue_2"
              echo "##vso[task.setvariable variable=SomeVariable_3;isOutput=True]SomeValue_3"
              echo "##vso[task.setvariable variable=SomeVariable_4;isOutput=True]SomeValue_4"
              echo "##vso[task.setvariable variable=Changes;isOutput=True]4"
    
    - ${{each stage in parameters.Stages}}:    
      - stage: ${{stage.StageName}}
        variables:
          Project_1: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_1'] ]
          Project_2: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_2'] ]
          Project_3: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_3'] ]
          Project_4: $[ stageDependencies.PreSteps.Check_changes.outputs['bash_script1.SomeVariable_4'] ]
        dependsOn: 
        - ${{stage.Depends}}
        ${{ if eq(stage.StageName, 'S_Build') }}: 
          condition: gt(dependencies.PreSteps.outputs['Check_changes.bash_script1.Changes'], 0)
        ${{ if ne(stage.StageName, 'S_Build') }}:
          condition: succeeded('${{stage.Depends}}')
        jobs:
        - template: ${{stage.Template}}
          parameters:
            Projects:
            - $(Project_1)
            - $(Project_2)
            - $(Project_3)
            - $(Project_4)