continuous-integrationyamlcirclecicircleci-workflows

How to make a conditional manual approval in CircleCI 2.0 workflows


I have a simple use case where I want to make a manual approval only for a specific branch and/or tag.

The workflow job with type:approval has filters like all other jobs but the job foo that requires a manual approval (or not) will use something like requires: ['approve'] and then is strongly linked to it.

That means that foo will never happen at all if the approval step doesn't match the filter.

So.. any clean workaround, without many duplicates in yaml file?

Edit: Same question on CircleCI Discuss


Solution

  • Using YAML alias map

    This is kind of a hack but with YAML alias map you reuse your steps and make two separate workflow paths with different filters: One with approval and another one without.

    Here is a full example:

    version: 2.0
    
    # Run job (defined in a YAML alias map, see http://yaml.org/type/merge.html)
    run-core: &run-core
        docker:
          - image: circleci/node:8
        steps:
          - checkout
          - restore_cache: { key: 'xxxxx' }
          - run: npm install
          - save_cache: { key: 'xxxxx', paths: ['xxxx'] }
          - run: npm run build
          - run: npm run validate
          - deploy: ./scripts/deploy.sh
    
    # Jobs (duplicate the same job, but with different names)
    jobs:
      run:
        <<: *run-core
      run-with-approval:
        <<: *run-core
    
    # This will allow manual approval and context
    # See https://circleci.com/docs/2.0/workflows/#git-tag-job-execution
    workflows:
      version: 2
      run:
        jobs:
          # Without approval (for all branches except staging)
          - run:
              context: org-global
              filters:
                branches: { ignore: 'staging' } # All branches except staging
                tags: { ignore: '/.*/' }        # Ignore all tags
          # With approval (only for tags and staging branch)
          - run-with-approval:
              context: org-global
              filters:
                tags: { only: '/.*/' }          # All branches and all tags
              requires: ['approve']             # But requires approval (which is filtering)
          - approve:
              type: approval
              filters:
                branches: { only: 'staging' }   # Ignore all branches except staging
                tags: { only: '/.*/' }          # All tags
    

    I hope this will helps