| `api` | For pipelines triggered by the [pipelines API](../../api/pipelines.md#create-a-new-pipeline). |
| `chat` | For pipelines created by using a [GitLab ChatOps](../chatops/index.md) command. |
| `external` | When you use CI services other than GitLab. |
| `external_pull_request_event` | When an external pull request on GitHub is created or updated. See [Pipelines for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). |
| `merge_request_event` | For pipelines created when a merge request is created or updated. Required to enable [merge request pipelines](../merge_request_pipelines/index.md), [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md), and [merge trains](../merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md). |
| `parent_pipeline` | For pipelines triggered by a [parent/child pipeline](../parent_child_pipelines.md) with `rules`. Use this pipeline source in the child pipeline configuration so that it can be triggered by the parent pipeline. |
| `pipeline` | For [multi-project pipelines](../multi_project_pipelines.md) created by [using the API with `CI_JOB_TOKEN`](../multi_project_pipelines.md#triggering-multi-project-pipelines-through-api), or the [`trigger`](../yaml/README.md#trigger) keyword. |
| `push` | For pipelines triggered by a `git push` event, including for branches and tags. |
| `schedule` | For [scheduled pipelines](../pipelines/schedules.md). |
| `trigger` | For pipelines created by using a [trigger token](../triggers/README.md#trigger-token). |
| `web` | For pipelines created by using **Run pipeline** button in the GitLab UI, from the project's **CI/CD > Pipelines** section. |
| `webide` | For pipelines created by using the [WebIDE](../../user/project/web_ide/index.md). |
The following example runs the job as a manual job in scheduled pipelines or in push
pipelines (to branches or tags), with `when: on_success` (default). It does not
add the job to any other pipeline type.
```yaml
job:
script:echo "Hello, Rules!"
rules:
-if:'$CI_PIPELINE_SOURCE=="schedule"'
when:manual
allow_failure:true
-if:'$CI_PIPELINE_SOURCE=="push"'
```
The following example runs the job as a `when: on_success` job in [merge request pipelines](../merge_request_pipelines/index.md)
and scheduled pipelines. It does not run in any other pipeline type.
```yaml
job:
script:echo "Hello, Rules!"
rules:
-if:'$CI_PIPELINE_SOURCE=="merge_request_event"'
-if:'$CI_PIPELINE_SOURCE=="schedule"'
```
Other commonly used variables for `if` clauses:
-`if: $CI_COMMIT_TAG`: If changes are pushed for a tag.
-`if: $CI_COMMIT_BRANCH`: If changes are pushed to any branch.
-`if: '$CI_COMMIT_BRANCH == "main"'`: If changes are pushed to `main`.
-`if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'`: If changes are pushed to the default
branch. Use when you want to have the same configuration in multiple
projects with different default branches.
-`if: '$CI_COMMIT_BRANCH =~ /regex-expression/'`: If the commit branch matches a regular expression.
-`if: '$CUSTOM_VARIABLE !~ /regex-expression/'`: If the [custom variable](../variables/README.md#custom-cicd-variables)
`CUSTOM_VARIABLE` does **not** match a regular expression.
-`if: '$CUSTOM_VARIABLE == "value1"'`: If the custom variable `CUSTOM_VARIABLE` is
exactly `value1`.
### Variables in `rules:changes`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34272) in GitLab 13.6.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/267192) in GitLab 13.7.
You can use CI/CD variables in `rules:changes` expressions to determine when
| [`if`](#rulesif) | Add or exclude jobs from a pipeline by evaluating an `if` statement. Similar to [`only:variables`](#onlyvariables--exceptvariables). |
| [`changes`](#ruleschanges) | Add or exclude jobs from a pipeline based on what files are changed. Same as [`only:changes`](#onlychanges--exceptchanges). |
| [`exists`](#rulesexists) | Add or exclude jobs from a pipeline based on the presence of specific files. |
Rules are evaluated in order until a match is found. If a match is found, the attributes
are checked to see if the job should be added to the pipeline. If no attributes are defined,
the defaults are:
-`if`
-`changes`
-`exists`
-`allow_failure`
-`variables`
-`when`
-`when: on_success`
-`allow_failure: false`
You can combine multiple keywords together for [complex rules](../jobs/job_control.md#complex-rules).
The job is added to the pipeline:
- If a rule matches and has `when: on_success`, `when: delayed` or `when: always`.
- If no rules match, but the last clause is `when: on_success`, `when: delayed`
or `when: always` (with no rule).
- If an `if`, `changes`, or `exists` rule matches and also has `when: on_success` (default),
`when: delayed`, or `when: always`.
- If a rule is reached that is only `when: on_success`, `when: delayed`, or `when: always`.
The job is not added to the pipeline:
- If no rules match, and there is no standalone `when: on_success`, `when: delayed` or
`when: always`.
- If a rule matches, and has `when: never` as the attribute.
The following example uses `if` to strictly limit when jobs run:
```yaml
job:
script:echo "Hello, Rules!"
rules:
-if:'$CI_PIPELINE_SOURCE=="merge_request_event"'
when:manual
allow_failure:true
-if:'$CI_PIPELINE_SOURCE=="schedule"'
```
- If the pipeline is for a merge request, the first rule matches, and the job
is added to the [merge request pipeline](../merge_request_pipelines/index.md)
with attributes of:
-`when: manual` (manual job)
-`allow_failure: true` (the pipeline continues running even if the manual job is not run)
- If the pipeline is **not** for a merge request, the first rule doesn't match, and the
second rule is evaluated.
- If the pipeline is a scheduled pipeline, the second rule matches, and the job
is added to the scheduled pipeline. No attributes were defined, so it is added
with:
-`when: on_success` (default)
-`allow_failure: false` (default)
- In **all other cases**, no rules match, so the job is **not** added to any other pipeline.
Alternatively, you can define a set of rules to exclude jobs in a few cases, but
run them in all other cases:
```yaml
job:
script:echo "Hello, Rules!"
rules:
-if:'$CI_PIPELINE_SOURCE=="merge_request_event"'
when:never
-if:'$CI_PIPELINE_SOURCE=="schedule"'
when:never
-when:on_success
```
- If the pipeline is for a merge request, the job is **not** added to the pipeline.
- If the pipeline is a scheduled pipeline, the job is **not** added to the pipeline.
- In **all other cases**, the job is added to the pipeline, with `when: on_success`.
WARNING:
If you use a `when:` clause as the final rule (not including `when: never`), two
simultaneous pipelines may start. Both push pipelines and merge request pipelines can
be triggered by the same event (a push to the source branch for an open merge request).
See how to [prevent duplicate pipelines](#avoid-duplicate-pipelines)
for more details.
#### Avoid duplicate pipelines
If a job uses `rules`, a single action, like pushing a commit to a branch, can trigger
multiple pipelines. You don't have to explicitly configure rules for multiple types
of pipeline to trigger them accidentally.
Some configurations that have the potential to cause duplicate pipelines cause a
[pipeline warning](../troubleshooting.md#pipeline-warnings) to be displayed.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219431) in GitLab 13.3.
For example:
```yaml
job:
script:echo "This job creates double pipelines!"
rules:
-if:'$CUSTOM_VARIABLE=="false"'
when:never
-when:always
```
This job does not run when `$CUSTOM_VARIABLE` is false, but it *does* run in **all**
other pipelines, including **both** push (branch) and merge request pipelines. With
this configuration, every push to an open merge request's source branch
causes duplicated pipelines.
To avoid duplicate pipelines, you can:
- Use the `CI_OPEN_MERGE_REQUESTS` CI/CD variable in [`workflow:rules`](#workflow) to
[switch between branch and merge request pipelines](#switch-between-branch-pipelines-and-merge-request-pipelines)
without duplication. You can also use this variable in individual job rules.
- Use [`workflow`](#workflow) to specify that only branch pipelines or only merge request
pipelines should run.
- Rewrite the rules to run the job only in very specific cases,
and avoid a final `when:` rule:
```yaml
job:
script:echo "This job does NOT create double pipelines!"
| `api` | For pipelines triggered by the [pipelines API](../../api/pipelines.md#create-a-new-pipeline). |
| `chat` | For pipelines created by using a [GitLab ChatOps](../chatops/index.md) command. |
| `external` | When you use CI services other than GitLab. |
| `external_pull_request_event` | When an external pull request on GitHub is created or updated. See [Pipelines for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). |
| `merge_request_event` | For pipelines created when a merge request is created or updated. Required to enable [merge request pipelines](../merge_request_pipelines/index.md), [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md), and [merge trains](../merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md). |
| `parent_pipeline` | For pipelines triggered by a [parent/child pipeline](../parent_child_pipelines.md) with `rules`. Use this pipeline source in the child pipeline configuration so that it can be triggered by the parent pipeline. |
| `pipeline` | For [multi-project pipelines](../multi_project_pipelines.md) created by [using the API with `CI_JOB_TOKEN`](../multi_project_pipelines.md#triggering-multi-project-pipelines-through-api), or the [`trigger`](#trigger) keyword. |
| `push` | For pipelines triggered by a `git push` event, including for branches and tags. |
| `schedule` | For [scheduled pipelines](../pipelines/schedules.md). |
| `trigger` | For pipelines created by using a [trigger token](../triggers/README.md#trigger-token). |
| `web` | For pipelines created by using **Run pipeline** button in the GitLab UI, from the project's **CI/CD > Pipelines** section. |
| `webide` | For pipelines created by using the [WebIDE](../../user/project/web_ide/index.md). |
The following example runs the job as a manual job in scheduled pipelines or in push
pipelines (to branches or tags), with `when: on_success` (default). It does not
add the job to any other pipeline type.
```yaml
job:
script:echo "Hello, Rules!"
rules:
-if:'$CI_PIPELINE_SOURCE=="schedule"'
when:manual
allow_failure:true
-if:'$CI_PIPELINE_SOURCE=="push"'
```
**Related topics**:
The following example runs the job as a `when: on_success` job in [merge request pipelines](../merge_request_pipelines/index.md)
and scheduled pipelines. It does not run in any other pipeline type.
-[Common `if` expressions for `rules`](../jobs/job_control.md#common-if-clauses-for-rules).
You can use the `$` character for both variables and paths. For example, if the
`$DOCKERFILES_DIR` variable exists, its value is used. If it does not exist, the
`$` is interpreted as being part of a path.
-`rules: changes` works the same way as [`only: changes` and `except: changes`](#onlychanges--exceptchanges).
- You can use `when: never` to implement a rule similar to [`except:changes`](#onlychanges--exceptchanges).
#### `rules:exists`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24021) in GitLab 12.4.
Use `exists` to run a job when certain files exist in the repository.
You can use an array of paths.
In the following example, `job` runs if a `Dockerfile` exists anywhere in the repository:
**Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: An array of file paths. Paths are relative to the project directory (`$CI_PROJECT_DIR`)
and can't directly link outside it. File paths can use glob patterns.
**Example of `rules:exists`**:
```yaml
job:
...
...
@@ -1501,37 +1246,34 @@ job:
-Dockerfile
```
Paths are relative to the project directory (`$CI_PROJECT_DIR`) and can't directly link outside it.
You can use [glob](https://en.wikipedia.org/wiki/Glob_(programming))
patterns to match multiple files in any directory
in the repository:
```yaml
job:
script:bundle exec rspec
rules:
-exists:
-spec/**.rb
```
`job` runs if a `Dockerfile` exists anywhere in the repository.
Glob patterns are interpreted with Ruby [`File.fnmatch`](https://docs.ruby-lang.org/en/2.7.0/File.html#method-c-fnmatch)
with the flags `File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB`.
**Additional details**:
For performance reasons, GitLab matches a maximum of 10,000 `exists` patterns or file paths. After the 10,000th check, rules with patterned globs always match.
In other words, the `exists` rule always assumes a match in projects with more than 10,000 files.
- Glob patterns are interpreted with Ruby [`File.fnmatch`](https://docs.ruby-lang.org/en/2.7.0/File.html#method-c-fnmatch)
with the flags `File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB`.
- For performance reasons, GitLab matches a maximum of 10,000 `exists` patterns or
file paths. After the 10,000th check, rules with patterned globs always match.
In other words, the `exists` rule always assumes a match in projects with more
than 10,000 files.
#### `rules:allow_failure`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30235) in GitLab 12.8.
You can use [`allow_failure: true`](#allow_failure) in `rules:` to allow a job to fail, or a manual job to
wait for action, without stopping the pipeline itself. All jobs that use `rules:` default to `allow_failure: false`
if you do not define `allow_failure:`.
Use [`allow_failure: true`](#allow_failure) in `rules:` to allow a job to fail
without stopping the pipeline.
The rule-level `rules:allow_failure` option overrides the job-level
[`allow_failure`](#allow_failure) option, and is only applied when
the particular rule triggers the job.
You can also use `allow_failure: true` with a manual job. The pipeline continues
running without waiting for the result of the manual job. `allow_failure: false`
combined with `when: manual` in rules causes the pipeline to wait for the manual
job to run before continuing.
**Keyword type**: Job keyword. You can use it only as part of a job.
**Possible inputs**: `true` or `false`. Defaults to `false` if not defined.
**Example of `rules:allow_failure`**:
```yaml
job:
...
...
@@ -1542,7 +1284,12 @@ job:
allow_failure:true
```
In this example, if the first rule matches, then the job has `when: manual` and `allow_failure: true`.
If the rule matches, then the job is a manual job with `allow_failure: true`.
**Additional details**:
- The rule-level `rules:allow_failure` overrides the job-level [`allow_failure`](#allow_failure),
and only applies when the specific rule triggers the job.
#### `rules:variables`
...
...
@@ -1551,7 +1298,11 @@ In this example, if the first rule matches, then the job has `when: manual` and
Use [`variables`](#variables) in `rules:` to define variables for specific conditions.
For example:
**Keyword type**: Job-specific. You can use it only as part of a job.
**Possible inputs**: A hash of variables in the format `VARIABLE-NAME: value`.
**Example of `rules:variables`**:
```yaml
job:
...
...
@@ -1569,50 +1320,6 @@ job:
-echo "Run another script if $IS_A_FEATURE exists"
```
#### Complex rule clauses
To conjoin `if`, `changes`, and `exists` clauses with an `AND`, use them in the
same rule.
In the following example:
- If the `Dockerfile` file or any file in `/docker/scripts` has changed, and `$VAR` == "string value",
then the job runs manually
- Otherwise, the job isn't included in the pipeline.
changes:# Include the job and set to when:manual if any of the follow paths match a modified file.
-Dockerfile
-docker/scripts/*
when:manual
# - "when: never" would be redundant here. It is implied any time rules are listed.
```
Keywords such as `branches` or `refs` that are available for
`only`/`except` are not available in `rules`. They are being individually
considered for their usage and behavior in this context. Future keyword improvements
are being discussed in our [epic for improving `rules`](https://gitlab.com/groups/gitlab-org/-/epics/2783),
where anyone can add suggestions or requests.
You can use [parentheses](../jobs/job_control.md#group-variable-expressions-together-with-parentheses) with `&&` and `||` to build more complicated variable expressions.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230938) in GitLab 13.3: