Search code examples
terraformgitlab-ci

How do I skip the next jobs in GitLab CI if the first job was not added to the pipeline?


I am trying to create a CI for Terraform code.

The first job is a linter, which should run only if Terraform files have been changed.

test_lint:
  stage: lint
  script:
    - |
        cd xxx
        terraform init
        terraform fmt -check -recursive -diff
        terraform validate
  rules:
    - if: '$CI_COMMIT_BRANCH'
      changes:
        compare_to: 'refs/heads/main'
        paths:
          - 'projects/xxx/*'
          - 'xxx/*'
    - if: $CI_PIPELINE_SOURCE != "merge_request_event"
      when: never

If the files have not been changed, I do not need to run the second job with terraform plan and the third job with terraform apply.

test_plan:
  stage: plan
  script:
    - |
        cd xxx
        terraform init
        terraform plan -out=$PLAN -parallelism=30
        terraform show --json $PLAN | convert_report > $PLAN_JSON
  artifacts:
    paths:
      - xxx/$PLAN
    reports:
      terraform: xxx/$PLAN_JSON
  resource_group: terraform-state


test_apply:
  stage: apply
  script:
    - |
        cd xxx
        terraform apply $PLAN
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"' ### Apply only after merging
  resource_group: terraform-state

How can I skip the plan and apply jobs if the first job was not added to the pipeline? My MR settings does not allow merging if no pipelines have passed, so I need an additional dummy job that starts only when these three jobs are skipped, or not added to pipeline at all? after MR i don't need to run dummy job

I tried to use rules like in plan job for example

rules:
  - if: '$CI_JOB_STATUS == "success" && $CI_JOB_STAGE == "lint"' # here i mean previous job
  when: never

but it's not works

Maybe i just need to take names of previous job and add it to rule in next job with "when: never"

Like a

rules:
 - if: $PREVIOUS JOB (or STAGE) = not created
   when: never

Solution

  • Based on your comment and your request to a solution that does not duplicate code I would suggest you use a template for the needed rule:

    .only_on_changes: &only_on_changes
      if: '$CI_COMMIT_BRANCH'
      changes:
        compare_to: 'refs/heads/main'
        paths:
          - 'projects/xxx/*'
          - 'xxx/*'
    
    test_lint:
      stage: lint
      script:
        - |
            cd xxx
            terraform init
            terraform fmt -check -recursive -diff
            terraform validate
      rules:
        - *only_on_changes
        - if: $CI_PIPELINE_SOURCE != "merge_request_event"
          when: never
    
    test_plan:
      stage: plan
      script:
        - |
            cd xxx
            terraform init
            terraform plan -out=$PLAN -parallelism=30
            terraform show --json $PLAN | convert_report > $PLAN_JSON
      artifacts:
        paths:
          - xxx/$PLAN
        reports:
          terraform: xxx/$PLAN_JSON
      rules:
        - *only_on_changes
      resource_group: terraform-state
    
    
    test_apply:
      stage: apply
      script:
        - |
            cd xxx
            terraform apply $PLAN
      rules:
        - *only_on_changes
        - if: '$CI_COMMIT_REF_NAME == "main"' ### Apply only after merging
      resource_group: terraform-state
    

    If you want another job that only runs whenever the previous rule does not apply you could negate it and add it to your dummy job:

    .only_on_no_changes: &only_on_no_changes
      if: '$CI_COMMIT_BRANCH'
      changes:
        compare_to: 'refs/heads/main'
        paths:
          - 'projects/xxx/*'
          - 'xxx/*'
      when: never
    
    dummy_job:
      stage: apply
      script:
        - echo "Dummy Job"
      rules:
        - *only_on_no_changes
        - when: always