Run job depending on previous job exit code

I need a way to run a job in the pipeline depending if another job’s result.

Right now I use this simplified CD definition, on gitlab.com:

# Staging branch: just deploy to staging
deploy staging (from staging branch):
  rules:
    - if: $CI_COMMIT_BRANCH == 'staging'
  script:
    - deploy staging

# Main branch: check if staging branch exists
staging branch presence:
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  variables:
    GIT_STRATEGY: none
  script:
    - result=0
    # Exit code 0 = staging branch present; 2 = staging branch absent
    - git ls-remote --exit-code --heads $CI_REPOSITORY_URL staging || result=$?
    # Can only continue if branch is absent
    - test $result -eq 2

# Absent staging branch: deploy staging from main branch; then deploy production
deploy staging (from main branch):
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  needs:
    - staging branch presence
  script:
    - deploy staging

deploy production (after deploy staging):
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  needs:
    - deploy staging (from main branch)
  script:
    - deploy production

# Staging branch exists: just deploy to production directly
deploy production (⚠ without deploying staging):
  rules:
    - if: $CI_COMMIT_BRANCH == 'main'
  needs:
    - staging branch presence
  when: on_failure
  script:
    - deploy production

The intention is:

  1. If there’s a branch called staging, and you run a pipeline:
    • If you run it from the staging branch, just deploy to staging.
    • If you run it from the main branch, just deploy to production.
  2. If there’s no staging branch and you run a pipeline from the main branch:
    1. Deploy to staging.
    2. If successful, deploy to production.

Since there’s no way for a rule to detect the presence of a branch regardless if it’s the one being checked out or not, then there’s the staging branch presence job. This job goes :heavy_check_mark: or :x: depending on that, and other jobs will use when:on_failure to react.

However, since the job can actually fail (expectedly) on some circumstances, the whole pipeline is marked as failed. But it should be successful in any of the 2 cases.

I could set staging branch presence with allow_failure:true, but then the docs say:

on_success (default): Run the job only when all jobs in earlier stages succeed or have allow_failure: true.

So the when:on_failure wouldn’t trigger.

In my mind, the ideal solution would be:

  1. Gitlab fixes allow_failure:exit_codes, currently buggy.
  2. Support for a new when:on_exit_codes option.
  3. I configure staging branch presence with allow_failure:exit_codes = [2].
  4. I configure deploy production (⚠ without deploying staging) with when:on_exit_codes = [2].

Do you think this feature makes sense? Or I should just formulate the pipeline differently?

2 Likes

I have a similar use case: I want to run a deploy job only if the release job has created an artifact.

I’m using artifacts to pass the result. I check it inside the deploy job and do nothing if the condition is not met.
But this has some drawback : the job is always runned, I have no way to tell if the deployment was triggered or skipped except by looking at the log.

Having a way to dynamically set rules based on previous job would be great.

1 Like