Commit 1fbaad6d authored by Suzanne Selhorn's avatar Suzanne Selhorn

Merge branch 'docs-move-rules-to-job-control' into 'master'

Revamp rules docs to new style

See merge request gitlab-org/gitlab!63494
parents dfd8ba53 c5df841e
......@@ -19,6 +19,277 @@ To configure a job to be included or excluded from certain pipelines, you can us
Use [`needs`](../yaml/README.md#needs) to configure a job to run as soon as the
earlier jobs it depends on finish running.
## Specify when jobs run with `rules`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27863) in GitLab 12.3.
Use [`rules`](../yaml/README.md#rules) to include or exclude jobs in pipelines.
Rules are evaluated in order until the first match. When a match is found, the job
is either included or excluded from the pipeline, depending on the configuration.
See the [`rules`](../yaml/README.md#rules) reference for more details.
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.
### `rules` examples
The following example uses `if` to define that the job runs in only two specific cases:
```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.
### Complex rules
You can use all `rules` keywords, like `if`, `changes`, and `exists`, in the same
rule. The rule evaluates to true only when all included keywords evaluate to true.
For example:
```yaml
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$VAR == "string value"'
changes: # Include the job and set to when:manual if any of the follow paths match a modified file.
- Dockerfile
- docker/scripts/*
when: manual
allow_failure: true
```
If the `Dockerfile` file or any file in `/docker/scripts` has changed **and** `$VAR` == "string value",
then the job runs manually and is allowed to fail.
You can use [parentheses](#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:
```yaml
job1:
script:
- echo This rule uses parentheses.
rules:
if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE
```
WARNING:
[Before GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/230938),
rules that use both `||` and `&&` may evaluate with an unexpected order of operations.
### 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 [`workflow`](../yaml/README.md#workflow) to specify which types of pipelines
can 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!"
rules:
- if: '$CUSTOM_VARIABLE == "true" && $CI_PIPELINE_SOURCE == "merge_request_event"'
```
You can also avoid duplicate pipelines by changing the job rules to avoid either push (branch)
pipelines or merge request pipelines. However, if you use a `- when: always` rule without
`workflow: rules`, GitLab still displays a [pipeline warning](../troubleshooting.md#pipeline-warnings).
For example, the following does not trigger double pipelines, but is not recommended
without `workflow: rules`:
```yaml
job:
script: echo "This job does NOT create double pipelines!"
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
when: never
- when: always
```
You should not include both push and merge request pipelines in the same job without
[`workflow:rules` that prevent duplicate pipelines](../yaml/README.md#switch-between-branch-pipelines-and-merge-request-pipelines):
```yaml
job:
script: echo "This job creates double pipelines!"
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
Also, do not mix `only/except` jobs with `rules` jobs in the same pipeline.
It may not cause YAML errors, but the different default behaviors of `only/except`
and `rules` can cause issues that are difficult to troubleshoot:
```yaml
job-with-no-rules:
script: echo "This job runs in branch pipelines."
job-with-rules:
script: echo "This job runs in merge request pipelines."
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
For every change pushed to the branch, duplicate pipelines run. One
branch pipeline runs a single job (`job-with-no-rules`), and one merge request pipeline
runs the other job (`job-with-rules`). Jobs with no rules default
to [`except: merge_requests`](../yaml/README.md#only--except), so `job-with-no-rules`
runs in all cases except merge requests.
### Common `if` clauses for `rules`
For behavior similar to the [`only`/`except` keywords](../yaml/README.md#only--except), you can
check the value of the `$CI_PIPELINE_SOURCE` variable:
| Value | Description |
|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `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
to add jobs to a pipeline:
```yaml
docker build:
variables:
DOCKERFILES_DIR: 'path/to/files/'
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- changes:
- $DOCKERFILES_DIR/*
```
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.
## Specify when jobs run with `only` and `except`
You can use [`only`](../yaml/README.md#only--except) and [`except`](../yaml/README.md#only--except)
......
......@@ -219,7 +219,7 @@ The variable names begin with the `CI_MERGE_REQUEST_` prefix.
### Two pipelines created when pushing to a merge request
If you are experiencing duplicated pipelines when using `rules`, take a look at
the [important differences between `rules` and `only`/`except`](../yaml/README.md#avoid-duplicate-pipelines),
the [important differences between `rules` and `only`/`except`](../jobs/job_control.md#avoid-duplicate-pipelines),
which helps you get your starting configuration correct.
If you are seeing two pipelines when using `only/except`, please see the caveats
......
......@@ -109,7 +109,7 @@ the [`rules` configuration details](yaml/README.md#rules) carefully. The behavio
of `only/except` and `rules` is different and can cause unexpected behavior when migrating
between the two.
The [common `if` clauses for `rules`](yaml/README.md#common-if-clauses-for-rules)
The [common `if` clauses for `rules`](jobs/job_control.md#common-if-clauses-for-rules)
can be very helpful for examples of how to write rules that behave the way you expect.
#### Two pipelines run at the same time
......@@ -119,7 +119,7 @@ associated with it. Usually one pipeline is a merge request pipeline, and the ot
is a branch pipeline.
This is usually caused by the `rules` configuration, and there are several ways to
[prevent duplicate pipelines](yaml/README.md#avoid-duplicate-pipelines).
[prevent duplicate pipelines](jobs/job_control.md#avoid-duplicate-pipelines).
#### A job is not in the pipeline
......@@ -258,7 +258,7 @@ When you use [`rules`](yaml/README.md#rules) with a `when:` clause without an `i
clause, multiple pipelines may run. Usually this occurs when you push a commit to
a branch that has an open merge request associated with it.
To [prevent duplicate pipelines](yaml/README.md#avoid-duplicate-pipelines), use
To [prevent duplicate pipelines](jobs/job_control.md#avoid-duplicate-pipelines), use
[`workflow: rules`](yaml/README.md#workflow) or rewrite your rules to control
which pipelines can run.
......
......@@ -192,7 +192,7 @@ Some example `if` clauses for `workflow: rules`:
| `if: $CI_COMMIT_TAG` | Control when tag pipelines run. |
| `if: $CI_COMMIT_BRANCH` | Control when branch pipelines run. |
See the [common `if` clauses for `rules`](#common-if-clauses-for-rules) for more examples.
See the [common `if` clauses for `rules`](../jobs/job_control.md#common-if-clauses-for-rules) for more examples.
In the following example, pipelines run for all `push` events (changes to
branches and new tags). Pipelines for push events with `-draft` in the commit message
......@@ -228,7 +228,7 @@ The final `when: always` rule runs all other pipeline types, **including** merge
request pipelines.
If your rules match both branch pipelines and merge request pipelines,
[duplicate pipelines](#avoid-duplicate-pipelines) can occur.
[duplicate pipelines](../jobs/job_control.md#avoid-duplicate-pipelines) can occur.
#### `workflow:rules:variables`
......@@ -356,7 +356,7 @@ include:
To make the pipeline switch from branch pipelines to merge request pipelines after
a merge request is created, add a `workflow: rules` section to your `.gitlab-ci.yml` file.
If you use both pipeline types at the same time, [duplicate pipelines](#avoid-duplicate-pipelines)
If you use both pipeline types at the same time, [duplicate pipelines](../jobs/job_control.md#avoid-duplicate-pipelines)
might run at the same time. To prevent duplicate pipelines, use the
[`CI_OPEN_MERGE_REQUESTS` variable](../variables/predefined_variables.md).
......@@ -1113,205 +1113,32 @@ Use `rules` to include or exclude jobs in pipelines.
Rules are evaluated *in order* until the first match. When a match is found, the job
is either included or excluded from the pipeline, depending on the configuration.
The job can also have [certain attributes](#rules-attributes)
added to it.
`rules` replaces [`only/except`](#only--except) and they can't be used together
in the same job. If you configure one job to use both keywords, the linter returns a
`key may not be used with rules` error.
in the same job. If you configure one job to use both keywords, the GitLab returns
a `key may not be used with rules` error.
#### Rules attributes
`rules` accepts an array of rules defined with:
The job attributes you can use with `rules` are:
- [`when`](#when): If not defined, defaults to `when: on_success`.
- If used as `when: delayed`, `start_in` is also required.
- [`allow_failure`](#allow_failure): If not defined, defaults to `allow_failure: false`.
- [`variables`](#rulesvariables): If not defined, uses the [variables defined elsewhere](#variables).
If a rule evaluates to true, and `when` has any value except `never`, the job is included in the pipeline.
For example:
```yaml
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: delayed
start_in: '3 hours'
allow_failure: true
```
#### Rules clauses
Available rule clauses are:
| Clause | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| [`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!"
rules:
- if: '$CUSTOM_VARIABLE == "true" && $CI_PIPELINE_SOURCE == "merge_request_event"'
```
You can also avoid duplicate pipelines by changing the job rules to avoid either push (branch)
pipelines or merge request pipelines. However, if you use a `- when: always` rule without
`workflow: rules`, GitLab still displays a [pipeline warning](../troubleshooting.md#pipeline-warnings).
For example, the following does not trigger double pipelines, but is not recommended
without `workflow: rules`:
```yaml
job:
script: echo "This job does NOT create double pipelines!"
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
when: never
- when: always
```
You should not include both push and merge request pipelines in the same job without
[`workflow:rules` that prevent duplicate pipelines](#switch-between-branch-pipelines-and-merge-request-pipelines):
```yaml
job:
script: echo "This job creates double pipelines!"
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
Also, do not mix `only/except` jobs with `rules` jobs in the same pipeline.
It may not cause YAML errors, but the different default behaviors of `only/except`
and `rules` can cause issues that are difficult to troubleshoot:
```yaml
job-with-no-rules:
script: echo "This job runs in branch pipelines."
job-with-rules:
script: echo "This job runs in merge request pipelines."
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
```
For every change pushed to the branch, duplicate pipelines run. One
branch pipeline runs a single job (`job-with-no-rules`), and one merge request pipeline
runs the other job (`job-with-rules`). Jobs with no rules default
to [`except: merge_requests`](#only--except), so `job-with-no-rules`
runs in all cases except merge requests.
- If no rules match.
- If a rule matches and has `when: never`.
#### `rules:if`
......@@ -1321,110 +1148,61 @@ Use `rules:if` clauses to specify when to add a job to a pipeline:
- If an `if` statement is true, but it's combined with `when: never`, do not add the job to the pipeline.
- If no `if` statements are true, do not add the job to the pipeline.
`rules:if` differs slightly from `only:variables` by accepting only a single
expression string per rule, rather than an array of them. Any set of expressions to be
evaluated can be [conjoined into a single expression](../jobs/job_control.md#join-variable-expressions-together-with--or-)
by using `&&` or `||`, and the [variable matching operators (`==`, `!=`, `=~` and `!~`)](../jobs/job_control.md#cicd-variable-expressions).
Unlike variables in [`script`](../variables/README.md#use-cicd-variables-in-job-scripts)
sections, variables in rules expressions are always formatted as `$VARIABLE`.
`if:` clauses are evaluated based on the values of [predefined CI/CD variables](../variables/predefined_variables.md)
or [custom CI/CD variables](../variables/README.md#custom-cicd-variables).
For example:
**Keyword type**: Job-specific and pipeline-specific. You can use it as part of a job
to configure the job behavior, or with [`workflow`](#workflow) to configure the pipeline behavior.
**Possible inputs**: A [CI/CD variable expression](../jobs/job_control.md#cicd-variable-expressions).
**Example of `rules:if`**:
```yaml
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
when: always
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature/'
when: manual
allow_failure: true
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' # Checking for the presence of a variable is possible
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME'
```
Some details regarding the logic that determines the `when` for the job:
**Additional details**:
- If none of the provided rules match, the job is set to `when: never` and is
not included in the pipeline.
- A rule without any conditional clause, such as a `when` or `allow_failure`
rule without `if` or `changes`, always matches, and is always used if reached.
- If a rule matches and has no `when` defined, the rule uses the `when`
defined for the job, which defaults to `on_success` if not defined.
- You can define `when` once per rule, or once at the job-level, which applies to
all rules. You can't mix `when` at the job-level with `when` in rules.
- Unlike variables in [`script`](../variables/README.md#use-cicd-variables-in-job-scripts)
sections, variables in rules expressions are always formatted as `$VARIABLE`.
##### Common `if` clauses for `rules`
For behavior similar to the [`only`/`except` keywords](#only--except), you can
check the value of the `$CI_PIPELINE_SOURCE` variable:
| Value | Description |
|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `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).
- [Avoid duplicate pipelines](../jobs/job_control.md#avoid-duplicate-pipelines).
```yaml
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
```
#### `rules:changes`
Other commonly used variables for `if` clauses:
Use `rules:changes` to specify when to add a job to a pipeline by checking for changes
to specific files.
- `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`.
WARNING:
You should use `rules: changes` only with **branch pipelines** or **merge request pipelines**.
You can use `rules: changes` with other pipeline types, but `rules: changes` always
evaluates to true when there is no Git `push` event. Tag pipelines, scheduled pipelines,
and so on do **not** have a Git `push` event associated with them. A `rules: changes` job
is **always** added to those pipelines if there is no `if:` that limits the job to
branch or merge request pipelines.
#### `rules:changes`
**Keyword type**: Job keyword. You can use it only as part of a job.
Use `rules:changes` to specify when to add a job to a pipeline by checking for
changes to specific files.
**Possible inputs**: An array of file paths. In GitLab 13.6 and later,
[file paths can include variables](../jobs/job_control.md#variables-in-ruleschanges).
`rules: changes` works the same way as [`only: changes` and `except: changes`](#onlychanges--exceptchanges).
It accepts an array of paths. You should use `rules: changes` only with branch
pipelines or merge request pipelines. For example, it's common to use `rules: changes`
with merge request pipelines:
**Example of `rules:changes`**:
```yaml
docker build:
......@@ -1437,61 +1215,28 @@ docker build:
allow_failure: true
```
In this example:
- If the pipeline is a merge request pipeline, check `Dockerfile` for changes.
- If `Dockerfile` has changed, add the job to the pipeline as a manual job, and the pipeline
continues running even if the job is not triggered (`allow_failure: true`).
- If `Dockerfile` has not changed, do not add job to any pipeline (same as `when: never`).
To use `rules: changes` with branch pipelines instead of merge request pipelines,
change the `if:` clause in the previous example to:
```yaml
rules:
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
```
To implement a rule similar to [`except:changes`](#onlychanges--exceptchanges),
use `when: never`.
WARNING:
You can use `rules: changes` with other pipeline types, but it is not recommended
because `rules: changes` always evaluates to true when there is no Git `push` event.
Tag pipelines, scheduled pipelines, and so on do **not** have a Git `push` event
associated with them. A `rules: changes` job is **always** added to those pipeline
if there is no `if:` statement that limits the job to branch or merge request pipelines.
##### 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
to add jobs to a pipeline:
```yaml
docker build:
variables:
DOCKERFILES_DIR: 'path/to/files/'
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- changes:
- $DOCKERFILES_DIR/*
```
**Additional details**:
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.
```yaml
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$VAR == "string value"'
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:
```yaml
job1:
script:
- echo This rule uses parentheses.
rules:
if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE
```
WARNING:
[Before GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/230938),
rules that use both `||` and `&&` may evaluate with an unexpected order of operations.
### `only` / `except`
NOTE:
......
......@@ -94,7 +94,7 @@ merge-request-pipeline-job:
```
You should avoid configuration like this, and only use branch (`push`) pipelines
or merge request pipelines, when possible. See [`rules` documentation](../../../ci/yaml/README.md#avoid-duplicate-pipelines)
or merge request pipelines, when possible. See [`rules` documentation](../../../ci/jobs/job_control.md#avoid-duplicate-pipelines)
for details on avoiding two pipelines for a single merge request.
### Skipped pipelines
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment