Skip to content

Merge requests

Goal

Learn how to...

  • run pipelines in the context of a merge request using rules
  • use template to avoid repetition when using rules

Task 1: Use rules to run in merge request context

In the last chapter about rules, you learned how to use $CI_PIPELINE_SOURCE to restrict execution to specific events. You will need this now.

On the branch main, add rules to the jobs to specify when to run them:

  1. For the jobs lint, audit, unit_tests, build and test, add rules so that the jobs are executed when...
    1. pushing to the default branch
    2. running in merge request context
  2. Run the job trigger only when pushing to the default branch
  3. Run the job deploy only when on the branches dev and live
  4. Do not modify the existing rules for the job pages

Afterwards check the pipeline in the GitLab UI. You should see a successful pipeline run.

Hint (Click if you are stuck)

$CI_PIPELINE_SOURCE can take the values push and merge_request_event in this context. $CI_COMMIT_REF_NAME contains the name of the Git reference (e.g. branch) the pipeline is running on. $CI_DEFAULT_BRANCH contains the name of the default branch of the repository in the current project. You can use the logical operator && to combine multiple conditions.

Solution (Click if you are stuck)
workflow:
  rules:
  - if: $CI_DEPLOY_FREEZE
    when: never
  - if: $CI_PIPELINE_SOURCE == 'push'
  - if: $CI_PIPELINE_SOURCE == 'web'
  - if: $CI_PIPELINE_SOURCE == 'schedule'
  - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
  - if: $CI_PIPELINE_SOURCE == 'pipeline'
  - if: $CI_PIPELINE_SOURCE == 'api'
    when: never
  - if: $CI_PIPELINE_SOURCE == 'trigger'
    when: never

include:
- local: go.yaml

stages:
- check
- build
- test
- deploy
- trigger

default:
  image: golang:1.19.2

lint:
  stage: check
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
  - go fmt .

audit:
  stage: check
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
  - go vet .

unit_tests:
  stage: check
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
  - go install gotest.tools/gotestsum@latest
  - gotestsum --junitfile report.xml
  artifacts:
    when: always
    reports:
      junit: report.xml

build:
  stage: build
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  extends:
  - .build-go
  artifacts:
    paths:
    - hello

test:
  stage: test
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  image: alpine
  script:
  - ./hello

deploy:
  stage: deploy
  rules:
  - if: $CI_COMMIT_REF_NAME == "dev"
  - if: $CI_COMMIT_REF_NAME == "live"
  environment:
    name: ${CI_COMMIT_REF_NAME}
  before_script:
  - apt-get update
  - apt-get -y install curl ca-certificates
  script:
  - |
    curl https://seat${SEAT_INDEX}.${CI_COMMIT_REF_NAME}.webdav.inmylab.de/ \
        --fail \
        --verbose \
        --upload-file hello \
        --user seat${SEAT_INDEX}:${PASS}

pages:
  stage: deploy
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  image: alpine
  script:
  - cp hello public/
  artifacts:
    paths:
    - public

trigger:
  stage: trigger
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  trigger:
    include: child.yaml

If you want to jump to the solution, execute the following command:

git checkout upstream/160_gitlab_ci/140_merge_requests -- '*'

Task 2: Create a merge request

Now we want to check which jobs are executed in the context of a merge request:

  1. Create a new branch based on main
  2. Create a merge request into main

Afterwards check the pipeline in the GitLab UI. You should see a successful pipeline run.

Bonus: Explore additional predefined variables

On the branch of the merge request, add a job and run printenv to get a list of variables available to the pipeline. Check out additional variables specific to merge request pipelines. See also the official documentation.

Task 3: Avoid repetition using rule templates

In the first task we have implemented the same set of rules for multiple jobs. By combining rules with templates, this repetition can be avoided.

  1. Create an inline template called .run-on-push-to-default with the corresponding rule(s)
  2. Create a second inline template called .run-on-push-and-mr with the corresponding rule(s)
  3. Modify the jobs to use the rule templates

Afterwards check the pipeline in the GitLab UI. You should see a successful pipeline run.

Hint (Click if you are stuck)

Use extends to use the rule template in a job.

Remember that only variables are kumulative. All other keywords overwrite each other in the order of appearance.

Solution (Click if you are stuck)
workflow:
  rules:
  - if: $CI_DEPLOY_FREEZE
    when: never
  - if: $CI_PIPELINE_SOURCE == 'push'
  - if: $CI_PIPELINE_SOURCE == 'web'
  - if: $CI_PIPELINE_SOURCE == 'schedule'
  - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
  - if: $CI_PIPELINE_SOURCE == 'pipeline'
  - if: $CI_PIPELINE_SOURCE == 'api'
    when: never
  - if: $CI_PIPELINE_SOURCE == 'trigger'
    when: never

include:
- local: go.yaml

.run-on-push-to-default-branch:
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'

.run-on-push-and-in-mr:
  rules:
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

stages:
- check
- build
- test
- deploy
- trigger

default:
  image: golang:1.19.2

lint:
  stage: check
  extends:
  - .run-on-push-and-in-mr
  script:
  - go fmt .

audit:
  stage: check
  extends:
  - .run-on-push-and-in-mr
  script:
  - go vet .

unit_tests:
  stage: check
  extends:
  - .run-on-push-and-in-mr
  script:
  - go install gotest.tools/gotestsum@latest
  - gotestsum --junitfile report.xml
  artifacts:
    when: always
    reports:
      junit: report.xml

build:
  stage: build
  extends:
  - .run-on-push-and-in-mr
  - .build-go
  artifacts:
    paths:
    - hello

test:
  stage: test
  extends:
  - .run-on-push-and-in-mr
  image: alpine
  script:
  - ./hello

deploy:
  stage: deploy
  extends:
  - .run-on-push-to-default-branch
  environment:
    name: ${CI_COMMIT_REF_NAME}
  before_script:
  - apt-get update
  - apt-get -y install curl ca-certificates
  script:
  - |
    curl https://seat${SEAT_INDEX}.${CI_COMMIT_REF_NAME}.webdav.inmylab.de/ \
        --fail \
        --verbose \
        --upload-file hello \
        --user seat${SEAT_INDEX}:${PASS}

pages:
  stage: deploy
  extends:
  - .run-on-push-to-default-branch
  image: alpine
  script:
  - cp hello public/
  artifacts:
    paths:
    - public

trigger:
  stage: trigger
  extends:
  - .run-on-push-to-default-branch
  trigger:
    include: child.yaml

If you want to jump to the solution, execute the following command:

git checkout upstream/160_gitlab_ci/140_merge_requests_rule_templates -- '*'