Choose when components run
Use GitLab rules to decide whether a CI Tools component is included in a pipeline and when its jobs run. Keep those decisions near the component in .gitlab-ci.yml so a reader can see what a change, schedule, or tag will build.
Start with a repository layout
For a project with one image, put the build context in its own directory:
.
├── .gitlab-ci.yml
└── container/
└── rocky-bootc/
└── Containerfile
The container component's path is the build context, while containerfile-path identifies the build file. Paths are relative to the repository root. Include common first and use the same CI Tools version for both components. Use stable for a maintained project; use main only to test unreleased component changes.
This minimal .gitlab-ci.yml includes the image build when its context changes:
include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/common@stable
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/container@stable
inputs:
name: rocky-bootc
path: container/rocky-bootc
containerfile-path: container/rocky-bootc/Containerfile
rules:
- changes:
- container/rocky-bootc/**/*
when: always
- when: never
Commit a change below container/rocky-bootc/ and inspect the pipeline. GitLab should include build:rocky-bootc (and its configured scan job). For an ordinary merge request, a change outside that directory omits the component. GitLab treats rules:changes as matching on a new branch pipeline without a push comparison; schedules and tags also need explicit rules. Keep other required jobs in the pipeline: omitting every include can leave a pipeline with no jobs.
Choose the rule level
| Rule location | Effect | Use it when |
|---|---|---|
rules beside an include | GitLab decides whether to add the whole component to the pipeline. | A component is relevant only for certain paths or pipeline sources. |
inputs.rules inside an included component | The component is included, but its jobs follow the supplied job rules. | You need to override the component's default branch, schedule, or tag behavior. |
workflow:rules | GitLab decides whether to create a pipeline at all. | You need project-wide pipeline policy; see the workflow components. |
Rules are checked in order; the first matching rule wins. End an opt-in list with - when: never so unlisted cases do not run. An include:rules condition does not replace a component's job rules. Conversely, inputs.rules does not prevent the include from being parsed.
Build several contexts only when relevant
Keep independent contexts in separate directories and include the component once per image. Give each include a unique name. If an image also depends on a shared collection, list both paths:
include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/common@stable
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/container@stable
inputs:
name: rocky-bootc
path: container/rocky-bootc
containerfile-path: container/rocky-bootc/Containerfile
rules:
- changes:
- collections/ansible_collections/xrow/bootc/**/*
- container/rocky-bootc/**/*
when: always
- when: never
Add another container include for a second image rather than making one rule build every image. If shared files such as .gitlab-ci.yml affect the build, add them to each relevant changes list. Use a broader path such as container/**/* only when changes anywhere below container/ really should rebuild this image.
Handle schedules explicitly
A schedule has no new push to compare. Do not rely on a changes rule to select scheduled work. To rebuild an image on a schedule, add a pipeline-source rule before the path rule:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: always
- changes:
- container/rocky-bootc/**/*
when: always
- when: never
This is an include rule: it adds the component to scheduled pipelines. The container component's default inputs.rules skips schedules, so opt its jobs in as well when the scheduled pipeline must actually build:
inputs:
name: rocky-bootc
path: container/rocky-bootc
containerfile-path: container/rocky-bootc/Containerfile
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: on_success
- when: on_success
Keep both blocks under the same container include. GitLab schedules must target a branch and have an owner with permission to run the pipeline. If you need a path comparison in a scheduled pipeline, use GitLab's rules:changes:compare_to with a deliberate reference instead of assuming a push diff exists.
Handle tags and releases
A tag pipeline has CI_COMMIT_TAG; it does not have CI_COMMIT_BRANCH. A path-only include rule may not select the intended release build, so add a tag rule before changes when the image should be built for tags:
rules:
- if: '$CI_COMMIT_TAG'
when: always
- changes:
- container/rocky-bootc/**/*
when: always
- when: never
The container component's default job rules allow non-scheduled tag pipelines. For semantic version releases, include semantic-release separately; its default job rules run on the default branch and skip schedules, not on tag pipelines. The release job creates tags from eligible commits, while a tag pipeline can publish the tagged image. See getting started for the resulting image tags.
Check the result before merging
- Use GitLab's CI Lint or
glab ci lint .gitlab-ci.ymlto check syntax and expanded configuration. - Test a merge request that changes a matching path and one that does not. Check that only the intended component jobs appear.
- Run a schedule or tag in a non-production test project before relying on that source in a release pipeline. Confirm both include selection and job rules; CI Lint alone does not prove runtime behavior.
GitLab documents the exact evaluation rules for conditional includes and job rules. Check those references when using if, changes, and compare_to together.