Command Palette

Search for a command to run...

Hectal
PHASE 4Intermediate ~14 min· topic 4 of 4

Topic 4.4

Rules, Includes, and Templates

In one line

rules: gives fine-grained control over exactly when a job runs, and include: splits a growing pipeline across multiple files — GitLab's own answers to Phase 1.1's triggers and Phase 2.3's reusable workflows.

0/4 · 0%

Key ideas

  1. 01

    rules: gives fine-grained, CONDITIONAL control over whether a specific job runs at all, beyond just the pipeline-level triggers Phase 1.1 already covered generally — a job can be conditioned on the branch name, whether specific files changed, the pipeline's source (a push versus a merge request versus a schedule), or combinations of these.

  2. 02

    rules: - if: '$CI_COMMIT_BRANCH == "main"' runs a job only on the main branch specifically; rules: - changes: ["src/**/*"] runs a job only if files matching that path actually changed in the triggering commit — genuinely useful for skipping an expensive job (like a full integration test suite) when a change genuinely couldn't have affected the code that job actually tests.

  3. 03

    include: lets one .gitlab-ci.yml pull in configuration DEFINED IN OTHER FILES — either local files within the same repository (splitting one large, unwieldy file into logical, smaller pieces) or, genuinely more powerfully, files from an ENTIRELY DIFFERENT repository, directly the same 'shared, centrally-maintained pipeline logic' benefit as GitHub Actions' reusable workflows (Phase 2.3) or Jenkins' shared libraries (Phase 3.4).

  4. 04

    GitLab also provides CI/CD TEMPLATES — genuinely pre-built, ready-to-include configurations for extremely common tasks (security scanning, deploying to specific cloud providers) maintained by GitLab itself — include: template: Security/SAST.gitlab-ci.yml adds a complete, working static-analysis security scanning job to your pipeline with a SINGLE line, no custom configuration needed to get a genuinely useful baseline running immediately.

  5. 05

    Combining rules: and include: lets an organization define ONE shared, centrally-maintained pipeline template (via include: from a shared repository) while still letting each individual project's own .gitlab-ci.yml apply its own specific rules: conditions on top — genuinely powerful together: shared logic, locally-tunable conditions for exactly when that logic actually applies.

  6. 06

    This is genuinely the same DRY principle woven through every platform this whole phase has covered — GitHub Actions' reusable workflows, Jenkins' shared libraries, and now GitLab's include: and templates all exist to solve the identical real organizational problem: define a genuinely good pipeline pattern once, centrally, and let it be reused (and kept consistently updated) everywhere it's needed, rather than being copy-pasted and left to slowly drift apart across every individual repository.

Code & diagrams

rules-and-includes.ymlmarkdown

Conditional execution and shared, centrally-maintained configuration, in one realistic file.

include:
  - local: '.gitlab/ci/build.yml'                        # split out locally
  - project: 'my-org/shared-pipelines'                    # from another repo
    file: '/templates/standard-java-pipeline.yml'
  - template: 'Security/SAST.gitlab-ci.yml'                # GitLab's own built-in template

integration-tests:
  stage: test
  script:
    - mvn verify -Dtest=IntegrationTests
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'    # only on merge requests
      changes:
        - "src/main/**/*"                                    # AND only if source actually changed
    - if: '$CI_COMMIT_BRANCH == "main"'                       # OR always on main directly

deploy-production:
  stage: deploy
  environment: production
  script:
    - ./deploy.sh production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'                       # only ever from main
      when: manual

Explain it without notes

01

Why would a team configure integration-tests to skip running unless files under src/main/ actually changed, rather than always running it on every single pipeline?

02

How does GitLab's include: mechanism relate to the reusable-configuration problem Phase 2.3 (GitHub Actions) and Phase 3.4 (Jenkins) each solved with their own platform-specific mechanism?

Practice

01

Write a rules: condition for a hypothetical job that should only run on merge requests targeting main, and only if files under a specific path changed.

02

If you have access to a real GitLab project, try including one of GitLab's own built-in CI/CD templates (like the SAST security template) and confirm it adds a working job to your pipeline with minimal configuration.

Trade-offs

  • ↔

    Rich, conditional rules: logic gives genuinely precise control over exactly when expensive jobs run, but a pipeline with many layered, interacting rules can become genuinely hard to reason about — predicting exactly which jobs will run for a given specific commit or event sometimes requires carefully tracing through several rules individually, which is worth weighing against simply always running a job (accepting the extra, sometimes-unnecessary cost) when the conditional logic's own complexity starts to outweigh the compute time it's meant to save.

Done when you can

  • I can write rules: conditions controlling exactly when a job runs, based on branch, source, or changed files.

  • I can use include: to pull in configuration from a local file, another repository, or a GitLab template.

  • I understand GitLab's include:, GitHub's reusable workflows, and Jenkins' shared libraries all solve the same underlying reuse problem.