Is it possible to cancel job automatically when specific job is approved?

I have two approval jobs called test-qa and test-develop, and the level of jobs is same. I want to cancel other job when I approved specific job. Is it possible?

For example,

  1. I approved test-qa job → test-develop job is canceled or failed
  2. I approved test-develop job → test-qa job is canceled or failed

If it is possible, how can I apply this feature in config.yml ?

THX!

Hi @baeharam,

Although it isn’t possible to directly cancel an approval-type job, you can however cancel the “on_hold” workflow containing the approval job.

Assuming you have 2 defined jobs (each with their own executor, steps, …etc) in your config.yml, here are suggestions on how to proceed.

Note: You’ll need to create an environment variable containing your personal API token.

 

version: 2.1

jobs:
  job-qa:
    .....
    .....
    .....
    .....
                                                     
  job-develop:
    .....
    .....
    .....
    .....
                                                     
  cancel-other-hold:
    docker:
      - image: circleci/python
    steps:
      - run:
          name: Cancelling the other on_hold workflow
          command: |
              other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg CIRCLE_WORKFLOW_ID "$CIRCLE_WORKFLOW_ID" '.[].items[]|select(.status == "on_hold")|select(.id != $CIRCLE_WORKFLOW_ID)|.id')
                    echo $other_on_hold_id
                    curl -X POST "https://circleci.com/api/v2/workflow/${other_on_hold_id}/cancel" -H "Circle-Token: ${MyToken}"
              
                   
workflows:
  qa:
    jobs:
      - job-qa
      - test-qa:
          type: approval
          requires:
            - job-qa
      - cancel-other-hold:
          requires:
            - test-qa
                
  develop:
    jobs:
      - job-develop
      - test-develop:
          type: approval
          requires:
            - job-develop
      - cancel-other-hold:
          requires:
            - test-develop

 

You could also use a parameterized job:

version: 2.1

jobs:
  job-qa:
    .....
    .....
    .....
    .....
                                                     
  job-develop:
    .....
    .....
    .....
    .....
   
cancel-on-hold: # defines a parameterized job
    description: A job that just cancels a workflow
    parameters:
      other_wf:
        type: string
    docker:
      - image: circleci/python
    steps:
      - run:
          name: Cancelling the other on_hold workflow
          command: |
              other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg parameters.other_wf $parameters.other_wf '.[].items[]|select(.name == "<< parameters.other_wf >>")|.id')
              curl -X POST "https://circleci.com/api/v2/workflow/$other_on_hold_id/cancel" -H "Circle-Token: $MyToken"
              
                   
workflows:
  qa:
    jobs:
      - job-qa
      - test-qa:
          type: approval
          requires:
            - job-qa
      - cancel-on-hold:
          other_wf: develop
          requires:
            - test-qa
                
  develop:
    jobs:
      - job-develop
      - test-develop:
          type: approval
          requires:
            - job-develop
      - cancel-on-hold:
          other_wf: qa
          requires:
            - test-develop

 

Also, depending on the jobs included in your actual config.yml, you could use post-steps, which would eliminate the need for the additional job.
But keep in mind that post-steps do not work if they directly follow an approval-type job.

Here’s an example of post-steps you could add:

          post-steps:
            - run:
                name: Cancelling the other "on_hold" workflow
                command: |
                    other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg CIRCLE_WORKFLOW_ID "$CIRCLE_WORKFLOW_ID" '.[].items[]|select(.status == "on_hold")|select(.id != $CIRCLE_WORKFLOW_ID)|.id')
                    echo $other_on_hold_id
                    curl -X POST "https://circleci.com/api/v2/workflow/${other_on_hold_id}/cancel" -H "Circle-Token: ${MyToken}"
1 Like