Conditions Reference#
With Conditions DSL, you can specify conditional execution of CI/CD commands in Semaphore 2.0.
Using Conditions, you can perform a full or regular expression matches and combine them with boolean operations. For example:
branch = 'master' OR tag =~ '^v1\.'
Currently, you can use the Conditions DSL to configure the following features:
- Auto-cancel previous pipelines on a new push
- Auto-promote the next pipeline in the workflow
- Fail-fast - Stop everything as soon as a failure is detected
- Skip block execution
- Conditionally run a block
Formal language definition#
Formal language definition in extended Backus-Naur Form (EBNF) notation is shown below:
expression = expression bool_operator term
| term
term = "(" expression ")"
| keyword operator string
| string operator keyword
| basic_val
| fun
| fun operator term
basic_val = string
| boolean
| integer
| float
| list
| map
list = "[" "]"
| "[" params "]"
params = basic_val
| basic_val "," params
map = "{" "}"
| "{" map_vals "}"
map_vals = key_val
| key_val "," map_vals
key_val = map_key basic_val
fun = identifier "(" ")"
| identifier "(" params ")"
bool_operator = "and" | "AND" | "or" | "OR"
keyword = "branch" | "BRANCH" | "tag" | "TAG" | "pull_request" | "PULL_REQUEST" |
"result" | "RESULT" | "result_reason" | "RESULT_REASON"
operator = "=" | "!=" | "=~" | "!~"
boolean = "true" | "TRUE" | "false" | "FALSE"
string = ? all characters between two single quotes, e.g. 'master' ?
integer = ? any integer value, e. g. 123, -789, 42 etc. ?
float = ? any float value, e.g. 0.123, -78.9012, 42.0 etc. ?
map_key = ? string that matches [a-zA-Z][a-zA-Z0-9_\-]*: regex, e.g. first-name_1: ?
identifier = ? string that matches [a-zA-Z][a-zA-Z0-9_\-]* regex, e.g. foo-bar_1 ?
Each keyword
in a passed expression is replaced with the actual value of that
attribute for the current pipeline when the expression is evaluated, after which operations
identified by one of the above operators
are executed with the given values.
KEYWORD | ATTRIBUTE IT REPRESENTS |
branch | Name of the Git branch from which the pipeline that is being executed originated. |
tag | Name of the Git tag from which the pipeline that is being executed originated. |
pull_request | The number of GitHub pull request from which the pipeline that is being executed originated. |
result | Execution result of a pipeline. Possible values are: passed, stopped, canceled, and failed. |
result_reason | The reason for given result of execution. Possible values are: test, malformed, stuck, internal, user, strategy, and timeout. |
OPERATOR | OPERATION RESULT |
= | True if the keyword value and given string are equal |
!= | True if the keyword value and given string are not equal |
=~ | True if the keyword value and given PCRE* string match |
!~ | True if the keyword value and given PCRE* string do not match |
and | True if the expressions on both sides are true |
or | True if at least one of the two expressions is true |
* PCRE = Perl Compatible Regular Expression
Keyword usage
Both the result
and result_reason
keywords can only be used in auto_promote conditions,
since they are evaluated after pipeline execution is finished and the result is known.
All other when conditions are evaluated during pipeline initialization, when
the pipeline execution result is still unknown.
Functions#
Functions allow you to perform more complex checks that are not just direct boolean or regex matches.
change_in#
The change_in
function accepts one path or list of paths within the repository
as a first parameter. It checks if any path matches or contains one
of the files that was changed in a particular range of commits.
change_in(<file-pattern>, [configuration])
<file-pattern> - Required. A pattern can be:
- A file pattern relative to the root of the directory
example: "/lib" matches every file recursively in the lib directory
- A file pattern relative to the pipeline file
example: "../lib" matches every file recursively in the lib directory
- A glob pattern
example: "/lib/**/*.js" matches every JS file in the lib directory
- A list of multiple file patterns.
example: "['/lib', '/app', '/config/**/*.rb']" matches every file in the
lib, app directories, and every Ruby file in the config directory
[configuration] - Optional; a map containing the values for configurable parameters.
All parameters and their default values are stated below.
e.g. {on_tags: false, default_branch: 'master-new'}
The change_in
function calculates the commit range that should be examined in
different ways depending on whether the workflow was initiated from the master
branch or some other branch, or if it is a tag or a pull request.
The default behavior is the following:
-
On the
master
branch, the examined commit range consists of all the commits within the push that initiated the workflow. The same range is available in a job environment as an environment variable calledSEMAPHORE_GIT_COMMIT_RANGE
. In this case, the changes that are compared to the paths given as parameters are equivalent to the result of thegit diff <sha 1>^ <sha N>
command, wheresha 1
is the first commit of the push andsha N
is the last. -
On
other (non-master)
branches, the examined commit range is wider and all the commits between the head of the current branch and the common ancestor for that branch and the master branch are taken into account. The changes collected from this range are equivalent to the result of thegit diff master...<current branch>
command and are later compared to the paths passed as parameters. -
For
pull requests
, the commit range of interest is from the head of the current branch to the commit that is the common ancestor for it and the branch that is the target of the pull request. The changes gathered in this way are equivalent to the result of thegit diff <pull request target branch>...<current branch>
command and are later compared to the selected paths. -
For
tags
,change_in
always returns true if not configured otherwise.
The behavior of change_in
is configurable via a map of parameters that can be
given as a second parameter, as stated above.
The supported map parameters are:
PARAMETER | DESCRIPTION AND VALUES |
on_tags | The value of the change_in function in workflows initiated by tags. The default value is true. |
default_branch | The default value is master. If changed to another branch, change_in will act on that branch as it does by default on the master, and all other branches will be compared to it instead of to the master. |
pipeline_file | Possible values are track and ignore, and default is track. Any change to the pipeline YAML file will cause change_in to be evaluated as true, with the default track value. To avoid this, you should use ignore as the value for the pipeline_file parameter. |
branch_range | Configures the commit range that is examined on all branches except the default. The default value is $SEMAPHORE_MERGE_BASE...$SEMAPHORE_GIT_SHA , where $SEMAPHORE_MERGE_BASE is the default branch in workflows initiated from branches or a single targeted branch of a pull request, and the $SEMAPHORE_GIT_SHA is the sha of the commit for which the workflow was initiated. Here, you can use any predefined or literal values to create ranges in double-dot or triple-dot syntax, as described here in the Commit ranges section. |
default_range | Configures the commit range that is examined on the default branch. The default value is $SEMAPHORE_GIT_COMMIT_RANGE, which is described above. It accepts any commit range specified in double-dot or triple-dot syntax, and the same predefined values are available as stated above in the description of the branch_range property. |
exclude | A list of file patterns to exclude from the change-in pattern match. For example, `change_in('/', {exclude: ['/docs']})` will evaluate to true for any change in the repository, except if the change happens in the "docs" directory. |
The change_in
function is ideal for modeling Monorepo CI/CD.
Pipelines that use change_in
expressions need the full Git history and are
evaluated in dedicated Semaphore Jobs.
Usage examples for change_in#
When a directory changes#
blocks:
- name: Test WEB server
run:
when: "change_in('/web-app/')"
When a file changes#
blocks:
- name: Unit tests
run:
when: "change_in('../Gemfile.lock')"
When any file changes, except in the docs directory#
blocks:
- name: Unit tests
run:
when: "change_in('/', {exclude: ['/docs']})"
Changing the default branch from master to main#
blocks:
- name: Test WEB server
run:
when: "change_in('/web-app/', {default_branch: 'main'})"
Excluding changes in the pipeline file#
Note: If you change the pipeline file, Semaphore will consider change_in
as true.
The following illustrates how to disable this behaviour:
blocks:
- name: Test WEB server
run:
when: "change_in('/web-app/', {pipeline_file: 'ignore'})"
Usage examples for skip#
Always true#
blocks:
- name: Unit tests
skip:
when: "true"
On any branch#
blocks:
- name: Unit tests
skip:
when: "branch =~ '.*'"
When a branch is master#
blocks:
- name: Unit tests
skip:
when: "branch = 'master'"
When a branch starts with “df/”#
blocks:
- name: Unit tests
skip:
when: "branch =~ '^df/'"
When a branch is staging or master#
blocks:
- name: Unit tests
skip:
when: "branch = 'staging' OR branch = 'master'"
On any tag#
blocks:
- name: Unit tests
skip:
when: "tag =~ '.*'"
When a tag start with “v1.”#
blocks:
- name: Unit tests
skip:
when: "tag =~ '^v1\.'"
When a branch is master or a tag#
blocks:
- name: Unit tests
skip:
when: "branch = 'master' OR tag =~ '.*'"
When a branch does not start with "dev/"#
blocks:
- name: Unit tests
skip:
when: "branch !~ '^dev/'"
On any pull request#
blocks:
- name: Unit tests
skip:
when: "pull_request =~ '.*'"