Skip to content

IF var condition THEN

Runs the ops nested underneath it when one or more comparisons against the stash hold true. This is the general-purpose branch in the palette: it reads values straight from the stash, compares them without you writing any code, and combines several comparisons with a single any/all/none choice.

Reach for it first. IF var THEN and IF var ne value THEN only do a plain string equality test on one variable, and IF condition THEN makes you write Perl or JavaScript. This op covers the ground between them.

condition rows status EQUALS approved env LIKE ^(PROD|PRE)$ errors IS EMPTY When all true false run the nested ops skip to the next op

Fields

When

Decides how the individual condition rows combine.

When The block runs if
All every row is true
Any at least one row is true
None no row is true

None is the opposite of Any, not the opposite of All. One true row is enough to shut the block down.

Every setting short-circuits. All stops at the first row that comes out false, Any and None stop at the first row that comes out true, and the remaining rows are never evaluated. Order your rows cheapest-first and put guards ahead of the rows that depend on them.

Leave When unset and the block never runs, whatever the rows say. Nothing warns you. Pick one of the three values even when you only have a single row.

Stash Variable

The left side of the comparison. Write the variable name on its own, with no ${} wrapper: status, not ${status}. A row whose variable is blank fails validation, so every row has to name something.

Dots walk into nested data, so topic.title reads the title out of a topic. Positions in a list take square brackets: job.changesets[0].name reaches the first entry, while job.changesets.0.name resolves to nothing at all. A path that does not resolve gives back an empty value instead of an error, which is why IS EMPTY is the safe way to test whether something reached the stash at all.

Operator

Picks the comparison, listed in full below. A new row starts on IS TRUE. Your choice reshapes the rest of the row: IS TRUE, IS FALSE, IS EMPTY and NOT EMPTY hide the value field because they only inspect the left side, and the case and numeric checkboxes appear only for the operators that honour them.

Value

The right side of the comparison. Unlike the variable field, this one expands ${var} placeholders against the stash, so ${project.name}-build and release/${version} both work. That asymmetry catches people out: the left field is a path, the right field is a template.

For LIKE and NOT LIKE, type a regular expression.

IN and NOT IN never split what you type. approved,scheduled is compared as one long string and matches nothing, which is the most common way to get a row that is silently always false. The several values have to arrive as several values: point the field at a stash key that already holds a list, ${allowed_statuses}, built by PUSH VAR or by SET EXPR returning a list. For a fixed set typed into the form, use LIKE with ^(approved|scheduled)$, or give each value its own row and set When to Any.

Options

Two checkboxes, shown only for the operators that support them.

Ignore case lowercases both sides before comparing. On LIKE and NOT LIKE it makes the pattern itself case-insensitive instead.

Numeric switches from text ordering to number ordering. This matters more than it looks: as text, 9 sorts after 10, and 007 is not 7. Tick it for build numbers, counts, sizes, anything that came out of arithmetic.

Add condition and Remove

Add condition appends another row; Remove deletes the row it sits in. Rows have no individual weight and no nesting of their own, so every row answers to the same When setting. For mixed and/or logic, nest a second IF var condition THEN inside the first, or move the whole test into IF condition THEN.

Operators

Operator True when Value field Options
IS TRUE the variable holds a non-empty, non-zero value; for a list, any element does hidden none
IS FALSE nothing in the variable is truthy hidden none
IS EMPTY the variable is unset, an empty string, an empty list or an empty hash hidden none
NOT EMPTY the variable holds something hidden none
EQUALS the two sides match exactly text case, numeric
NOT EQUALS the sides differ text case, numeric
GREATER THAN, >=, LESS THAN, <= the ordering holds text case, numeric
LIKE the regular expression matches somewhere in the value regex case
NOT LIKE the regular expression does not match regex case
IN the value resolves to a list and the variable equals one of its entries list case
NOT IN the variable matches none of them list case
HAS the variable is a list or hash and the value is one of its entries text case
NOT HAS that list does not contain the value text case

IN and HAS look alike and get swapped constantly. IN asks whether one stash value appears in the list on the right. HAS asks whether the text on the right appears in a list sitting in the stash on the left. When the variable holds many things, you want HAS. Neither one builds a list out of a comma-separated string, so the side that is meant to hold several values has to hold a real list. On a hash, both operators look at the keys and the values.

An unset variable is true for IS EMPTY and true for IS FALSE. A variable holding 0 is true for IS FALSE and false for IS EMPTY, because a zero is a character like any other. Use IS EMPTY when the difference between "never set" and "set to zero" is the thing you are testing.

An operator the server does not recognise stops the rule with an error rather than quietly evaluating false. That only happens to hand-edited rules, since the form can only produce the operators above.

Combining with other ops

Drop ELSE or ELSIF condition THEN directly after this op for the other branch. They bind to the closest preceding IF, so keep them adjacent in the tree.

The same condition builder drives WHILE condition and DO-WHILE condition, so everything on this page applies there too. A WHILE whose body never changes the variable it tests will spin forever.

To branch on something the stash does not carry yet, load it first. The loader services write into the stash and this op reads whatever they left behind.

Examples

Skip a deployment block unless the topic reached a status that permits it, on the environments you care about. Both sets are written as patterns because they are typed into the form.

When: All
  status   LIKE   ^(approved|scheduled)$
  env      LIKE   ^(PROD|PRE)$             (Ignore case)

The same test against a list another op left in the stash, where IN does apply.

When: All
  status   IN   ${allowed_statuses}

Stop early when an earlier step recorded trouble. Nest FAIL inside to end the job.

When: Any
  build_errors    NOT EMPTY
  test_failures   GREATER THAN   0   (Numeric)

Act only on unassigned incidents, reading paths out of a loaded topic.

When: All
  topic.owners     IS EMPTY
  topic.category   EQUALS   incident   (Ignore case)