Conditional build on GitLab

Conditional build on GitLab

Regular readers of this blog know that I'm using Jekyll to generate the static site. I'm using GitLab: when I push on the master branch, it triggers the generation job.

However, Jekyll is Ruby-based and requires a couple of Gem dependencies. I've also added a few plugins. For this reason, I've created a Docker image with all required dependencies. Regularly, I update the versions in the Gemfile.lock via Bundler. Afterward, I need to rebuild the Docker image.

Hence, two jobs are necessary:

  1. After a push containing a change that influences the Docker image, build it
  2. After any push, generate the site.

For the first, the trigger condition is whether any of the following files have been changed: Gemfile.lock, Dockerfile and .gitlab-ci.yml.

The problem is how to run a build only if the condition is met, as it's an expensive and time-consuming operation. GitLab's build file configuration offers a solution for this. In a job, you can configure an only clause to run only if a condition is met. The condition can be:

  • A reference, e.g., a branch, or a tag
  • A trigger, e.g., a push, the web UI or an API call
  • The value of a variable
  • A change on a specific file
  • A couple of others

The next to last option is the answer to our problem. We can configure a set of files, and if any of them has been changed, the build should run. Otherwise, do nothing.

It translates into the following structure:

stages:
  - image                                        # 1
  - deploy                                       # 1

build:                                           # 2
  stage: image                                   # 2
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script: # Build the Docker image
  only:
    refs:
      - master                                   # 4
    changes:
      - Gemfile.lock                             # 5
      - Dockerfile                               # 5
      - .gitlab-ci.yml                           # 5

pages:                                           # 3
  stage: deploy                                  # 3
  image:
    name: registry.gitlab.com/nfrankel/nfrankel.gitlab.io:latest
  script: # Generate the site
  only:
    refs:
      - master
  1. Define the two stages
  2. Define the build job in the image stage. The job creates the Docker image (via Kaniko)
  3. Define the pages job in the deploy stage. The job generates the site via Jekyll
  4. Build the master branch only
  5. Only build the image if any of these files have changed

At this point, each change triggers the build: the image building job runs before the site generation, but GitLab skips the former if the image hasn't changed.

To go further:

Originally published at A Java Geek on May 8th, 2022