Skip to content

Matrix Jobs

Goal

Learn how to...

  • run the same script for different inputs

Preparation

Switch back to the branch main.

Task 1: Build binary for multiple platforms

Build the hello binary for multiple target platform. Matrix jobs enable you to reuse the existing code and parameterize it using different inputs.

Improve the template .build-go in go.yaml to build for linux/amd64 and linux/arm64:

  1. Check the official documentation for parallel to create a matrix job
  2. Add one input for GOOS=linux and GOARCH=amd64
  3. Add another input for GOOS=linux and GOARCH=arm64
  4. Modify the build command to write to separate files using hello-${GOOS}-${GOARCH}
  5. Move the artifact definition into the template and include all hello binaries
  6. Fix the smoke test to execute the hello binary for linux/amd64
  7. Fix the job deploy to upload the hello binary for linux/amd64
  8. Fix the job pages to copy the hello binary for linux/amd64

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

Solution (Click if you are stuck)

go.yaml:

.build-go:
  parallel:
    matrix:
    - GOOS: linux
      GOARCH: amd64
    - GOOS: linux
      GOARCH: arm64
  script:
  - |
    go build \
        -ldflags "-X main.Version=${CI_COMMIT_REF_NAME} -X 'main.Author=${AUTHOR}'" \
        -o hello-${GOOS}-${GOARCH} \
        .
  artifacts:
    paths:
    - hello-${GOOS}-${GOARCH}

.gitlab-ci.yml:

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

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

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-linux-amd64 \
        --user seat${SEAT_INDEX}:${PASS}

pages:
  stage: deploy
  extends:
  - .run-on-push-to-default-branch
  image: alpine
  script:
  - cp hello-linux-amd64 public/hello
  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/150_matrix_jobs_demo1 -- '*'

Task 2: Test an alternative to specify the same inputs

Test whether the following syntax for the inputs produces the same results in a pipeline:

.build-go:
  parallel:
    matrix:
    - GOOS: linux
      GOARCH: [ amd64, arm64 ]

Bonus: Check binaries for correct platform

Add another matrix job to check the target platform of the hello binaries:

  1. Add another template called .test-go to go.yaml defining a matrix job using the same inputs as for .build-go
  2. In the new template run file hello-${GOOS}-${GOARCH} to display the target platform
  3. Modify the job test to use the new template

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

Solution (Click if you are stuck)

go.yaml:

.go-targets:
  parallel:
    matrix:
    - GOOS: linux
      GOARCH: amd64
    - GOOS: linux
      GOARCH: arm64

.build-go:
  extends:
  - .go-targets
  script:
  - |
    go build \
        -ldflags "-X main.Version=${CI_COMMIT_REF_NAME} -X 'main.Author=${AUTHOR}'" \
        -o hello-${GOOS}-${GOARCH} \
        .
  artifacts:
    paths:
    - hello-${GOOS}-${GOARCH}

.test-go:
  extends:
  - .go-targets
  before_script:
  - apt-get update
  - apt-get -y install file
  script:
  - |
    file hello-${GOOS}-${GOARCH}

.gitlab-ci.yml:

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

test:
  stage: test
  extends:
  - .run-on-push-and-in-mr
  - .test-go

deploy:
  stage: deploy
  rules:
  - if: '$CI_COMMIT_REF_NAME == "dev" || $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-linux-amd64 \
        --user seat${SEAT_INDEX}:${PASS}

pages:
  stage: deploy
  extends:
  - .run-on-push-to-default-branch
  image: alpine
  script:
  - cp hello-linux-amd64 public/hello
  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/150_matrix_jobs_demo2 -- '*'