there was Jira Workflow Toolbox (JWT) and now, almost ten years after the initial public release, used by more than 4000 active customers and 140 versions later, comes its natural descendant, Automation Toolbox for Jira .

The team at Decadis took a long time planning the development of Automation Toolbox for Jira as this new app had some very major prerequisites to fulfill - namely providing as much known and proven JWT functionality as possible in a non-workflow environment. It has been a daunting task, but, we hope for you as a user, worthwhile. Even though you need no prior knowledge of JWT to use Automation Toolbox for Jira, you can depend on the functionality designed and developed with many years of Jira app experience.     

Where JWT has used the slogan "Turn your ideas into workflows" for many years, ATJ will hopefully help you to "Turn your ideas into automatisms" wherever and whenever these are appropriate. The possible use-cases are endless.   

To get started, please continue to the ATJ Fundamentals, a summary of the primary functions and the terminology used by ATJ


The Expression Parser Syntax Specification

Automation Toolbox for Jira uses a powerful expression parser for interpreting expressions with logical, mathematical, date-time and string-text terms. This parser is a fundamental part of the app, and is used by various features in the app. The parser offers very similar functionality to the expression parser known to Jira Workflow Toolbox users. There are some differences, mainly in field code usage and the lack of ephemeral fields. 

You can use the provided parser functionality with a number of triggers, conditions, actions and selectors.      

The following is a simple example of parser usage for the Condition → Boolean Condition where the condition will return true  if the issues Due date is greater than the current date.

 


The available Selectors, Conditions and Actions depend on the selected Trigger.


There are five types of expressions that can be parsed:

  • Mathematical and Time: returns a number. When it represents a Date or Time, it returns the number of milliseconds elapsed since January 1, 1970, 00:00:00 GMT
    Examples:
    • (1 * 2) / 3
    • {...duedate} + 2 * {HOUR} : adding 2 hours to Due Date
    • round(({...duedate} - {...currentDateTime}) / {HOUR}) : calculate the number of hours from Current date and time to Due Date.
  • Text-String: returns a string. This kind of expressions is used in advanced mode of the Action Update Field .
    Examples:
    • "Hello" + " " + "world" + "." : concatenating 4 string literals.
    • trim(%{...summary}) : removing leading and trailing blanks from Summary.
    • %{...description} + "\nLAST USER: " + toUpperCase(%{...currentUser}) : adding to Description a new line with string "LAST USER: " and the name of current user  in upper case.
  • Boolean (also known as Logical): it returns a logical value true or false .
    Examples:
    • %{...cf10005} = "Yes" : compares the value stored in a field with literal string "Yes".
    • datePart({...duedate}, LOCAL) > datePart({...currentDateTime}, LOCAL) : returns true only if Due Date (field code {...duedate}) is later than Current date (field code {...currentDateTime}) in server's local timezone.
    • %{...cf10020} != null AND %{cf10021} = null : returns true only if {...cf10020} field is initialized and field {...cf10021} is not initialized.
    • timePart({...currentDateTime}, LOCAL) >= 8:00 AND timePart({...currentDateTime}, LOCAL) <= 17:30 : Current time (field code {...currentDateTime}) is between 8:00 AM and 5:30 PM in server's local timezone.
  • Issue List: is used for selecting issues (is much like JQL) within Automation Toolbox for Jira expressions, and returns a list of issues.
    Examples:
    • subtasks() : returns the list of sub-tasks of current issue.
    • linkedIssues("is blocked by, is caused by") : returns the list of issues linked to current one through issue link types "is blocked by" and "is caused by".
    • filterByIssueType(linkedIssues(), "Bug, Incident") : returns the list of linked issues with issue type "Bug" or "Incident".
    • filterByPredicate(siblingSubtasks(), %{...resolution} != null) : returns the list of sibling sub-tasks (i.e., sub-tasks of same parent as current sub-task) which are not resolved. 
  • String List: expression that returns a list of strings.
    Examples:
    • ["red", "blue", "green"] : literal definition of a string list with the names of 3 colors.
    • fieldValue(%{...summary}, subtasks()) : returns the list of summaries of sub-tasks of current issue.
    • toStringList(%{...components}) : returns a list with the names of the components in current issue. 
        


Data types

The parser used in the app for mathematical calculation, time-formulas and boolean expressions uses the following data types:

Data typeDescriptionExample

Comparison operators return a logical value true or false , as well as some functions. isActive(string user_name)

This type represents numeric values, and is also used to store Date, Time and Date-Time () values. When storing any temporal value, the number represents the milliseconds elapsed since January 1, 1970, 00:00:00 GMT.
Number or Date-Time fields can be referenced as numbers using the following notation: {...somefield}.

1, 1.1, -1.1, .1, -.1

This type represents any kind of text or character string including all kinds of select and multi-select fields . Any field type or data type is susceptible of being transformed to text, so any field can be referenced as a text-string value using the following notation: %{...anyfield}, and %{...anyfield.i} for Cascading Select or Multi-Cascading Select fields, where i is the index that represents the level to be accessed. (i = 0 is used for base level).

"Hello world"

This type represents a collection of numeric values returned by various functions. The size may vary from 0 to any number of numeric values. It is used to read the value of a numeric field in a selection of issues. You can also use literals like  [1, 2, 3]. fieldValue(), append(), union(), except(), intersect() and distinct(), 
[1, 2, 3]

This type represents a collection of string values returned by various functions. The size may vary from 0 to any number of string values. It is also used to read the value of a string field in a selection of issues. You can also use literals like  ["string_A", "string_B", "string_C"]. fieldValue(), append(), union(), except(), intersect() and distinct(), 
["string_A", "string_B", "string_C"]

This type represents a collection of issues. The size may vary from 0 to any number of issues.
It's returned by issue selection or filtering functions like subtasks(), linkedIssues(), filterByIssueType(), distinct(), etc.
subtasks(), linkedIssues(), transitionLinkedIssues(), filterByFieldValue(), filterByStatus(), filterByIssueType(), filterByResolution(), filterByProject(), append(), union(), except(), intersect() and distinct(

Casting values to another type

There are two functions available for transforming types from Text-String to Number and viceversa, and also from other types to Text-String.

FunctionInputOutput
toString(number n)

Returns a  with the decimal representation of the numeric value in n. Numeric value of a Date-Time field is number of milliseconds elapsed since January 1, 1970, 00:00:00 GMT.

Example: toString(3.141592) returns "3.141592" .

toString(number n, number decimals)

Returns a  with the decimal representation of the numeric value in n limiting the fractional part to the number of digits in parameter decimals.

Example: toString(3.141592, 2) returns "3.14" .

toString(number list l)

Returns a  with a comma separated list of decimal representation of the numeric values  in l.

Example: toString([1, 2, 3, 4.0]) returns "1, 2, 3, 4" .

toString(number list l, number decimals)

Returns a  with a comma separated list of decimal representations of the numeric values in l, with the number of characters in the decimal part specified by parameter decimals.

Example: toString([1.123, 2.452, 3.64612], 2) returns the following string: "1.12, 2.45, 3.65" .

toString(number list l, number decimals, string separator) : string

Returns a  with a list of decimal representations of the numeric values in l, with the number of characters in the decimal part specified by parameter decimals and separated by string separator.

Example: toString([1.123, 2.452, 3.64612], 2, " : ") returns the following string: "1.12 : 2.45 : 3.65" .

toString(string list l) : string

Returns a  with a comma separated list of string values in l.

Example: toString(["Hello", " ", "world", "!"]) returns "Hello, , world, !" .

toString(string list l, string separator)

Returns a  a list of string values in l separated by string separator.

Example: toString(["blue", "red", "green"], "; ") returns "blue; red; green" .

toString(issue list l

Returns a  with a comma separated list of issue keys.

Example: toString(subtasks()) returns "CRM-5, CRM-6" , being CRM-5 and CRM-6 the keys of current issue's sub-tasks.

toString(issue list l, string separator)


Returns a  with a list of issue keys separated by string separator.

Example: toString(subtasks(), " ") returns "CRM-5 CRM-6", being CRM-5 and CRM-6 the keys of current issue's subtasks.

toNumber(string s)

Returns the  represented by the string s. This function expects a decimal representation of a number. In case it is not possible to parse the s to number, null is returned.

Example: toNumber("3.14") returns 3.14 .

toInteger(string s, string radix)

returns the  represented by the string s as a signed integer in the radix specified by argument radix.

Example: toInteger("ff", 16) returns 255 .

toStringList(string s, string separators)

 with a list of tokens separated by one or more characters

Returns a  with tokens in argument s separated by characters in argument separators. Leading and trailing spaces around each token are automatically removed.

Example: toStringList("red, orange, yellow; green; blue; purple", ",;") returns the following string list: ["red", "orange", "yellow", "green", "blue", "purple"] .

toStringList(multi-valued field field)

field code for a -value field in format %{...somefield}. Multi-valued fields are Multi Select, Checkboxes, Components, Versions, Multi User Picker, Multi Group Picker, Issue Pickers, Attachments and Labels.

Returns a  representing each of the values selected in the field.

Example: toStringList(%{...components}) returns a list of strings with each of the components selected in current issue.

toNumberList(string s, string separators)

 with a list of numbers in decimal representation separated by one or more characters

This function expects in argument s a string containing numbers in decimal representation separated by characters in argument separators, and returns a .

Example: toNumberList("1, 3, 5; 7; 11; 13", ",;") returns the following number list: [1, 3, 5, 7, 11, 13] .

issueKeysToIssueList(string issue_keys)

 with a comma separated list of issue keys

Returns an  with all issues with keys in argument issue_keys. Argument issue_keys is a string containing a comma separated list of issue keys.

Example: issueKeysToIssueList("CRM-12, HT-254") returns an issue list with issues with keys CRM-12 and HT-254.

Automatic casting from Number to Text-String: Whenever you write a numeric term at the right-hand side of concat operator + or a comparison operator like = , and the left-hand side is occupied by a text-string term, the parser will automatically transform the right-hand side term into a string

  • + (string concat): "His age is " + 30 is equivalent to "His age is " + toString(30) .
  • = (any comparison operator): "30" = 30 is equivalent to "30" = toString(30) .

Operators

The following comparison operators are available for types Number, Text-String, Number List, String List and Issue List. Operators = and != are also available for type Boolean.:

OperatorMeaningExamples (all examples return true)
= equal to 1 = 1
"HELLO" = toUpperCase("Hello")
%{...description} = {...timeoriginalestimate} , auto-casting numeric field {...timeoriginalestimate} to Text-String.
%{...timeoriginalestimate} = toString({...timeoriginalestimate}) , explicit casting of numeric field {...timeoriginalestimate} to Text-String.
true = true
%{...cf10001} = null , for checking whether field with code %{...cf10001} is not initialized.
[1, 2, 3] = [1, 2, 3] , when used with lists elements existence and its order are evaluated.
["blue", "red", "green"] = ["blue", "red", "green"]
!= not equal to 0 != 1
"HELLO" != "Hello"
%{...description} != "Hello"
true != false
{...cf10010} != null , for checking whether the numeric field with code {...cf10010} is initialized.
[1, 2, 3] != [1, 3, 2] , when used with lists elements existence and its order are evaluated.
["blue", "red", "green"] != ["blue", "green", "red"]
< lower than 1 < 2
"abc" < "bbc"
"abc" < "abcd"
> greater than 2 > 1
"bbc" > "abc"
"abcd" > "abc"
<= less than or equal to-
>= greater than or equal to-
~ contains "Hello world!" ~ "world" , checks whether a string contains a substring.
%{...componentLeads} ~ %{...currentUser} , checks whether "Component leaders" contains "Current user".
linkedIssues() ~ subtasks() , checks whether all sub-tasks are also linked to current issue.
[1, 2, 3, 2, 2, 4] ~ [2, 1, 2] , when used with lists cardinalities must match.
["blue", "red", "green", "red", "white", "red"] ~ ["red", "green", "red"]
(["green", "red"] ~ ["red", "green", "red"]) = false
!~ doesn't contain "world" !~ "Hello world!"
%{...fixVersions} !~ %{...versions} , checks whether "Fix version/s" doesn't contain all versions in "Affects version/s".
fieldValue(%{...reporter}, linkedIssues()) !~ fieldValue(%{...reporter}, subtasks()) , checks whether linked issues reporters don't include all sub-tasks reporters.
[1, 2, 3, 2, 2, 4] !~ [2, 1, 1, 4] , when used with lists cardinalities must match.
["blue", "red", "green", "red", "red"] !~ ["red", "green", "green", "red"]
in is contained in "world" in "Hello world!" , to check whether a substring is contained in a string.
%{...currentUser} in %{...componentLeads} , checks whether "Current user" is contained in "Component leaders".
subtasks() in linkedIssues() , checks whether all sub-tasks are also linked to current issue.
[1, 1, 2] in [2, 1, 1, 1, 4] , cardinality must match.
["blue", "red", "red"] in ["red", "green", "blue", "red", "red"] , cardinality must match.
2 in [1, 2, 3]
"blue" in ["red, "blue", "white"]
not in isn't contained in "Hello world!" not in "world"
%{...versions} not in %{...fixVersions} , checks whether not all versions in "Affects version/s" are contained in "Fix version/s".
fieldValue(%{...reporter}, subtasks()) not in fieldValue(%{...reporter}, linkedIssues()) , checks whether not all sub-tasks reporters are included in linked issues reporters.
[1, 1, 2, 2] not in [2, 1, 1, 1, 4] , cardinality must match.
["blue", "red", "red", "blue"] not in ["red", "blue", "red", "red"] , cardinality must match.
5 not in [1, 2, 3, 3, 4]
"orange" not in ["blue", "red", "white"]
any in some element is in %{...versions} any in %{...fixVersions} , checks whether any version in "Affects version/s" is contained in "Fix version/s".
fieldValue(%{...reporter}, subtasks()) any in fieldValue(%{...reporter}, linkedIssues()) , checks whether any sub-task's reporter is present among linked issues reporters.
[1, 3] any in [3, 4, 5]
["blue", "white"] any in ["black", "white", "green"]
none in no single element is in %{...versions} none in %{...fixVersions} , checks whether there isn't a single version "Affects version/s" in "Fix version/s".
fieldValue(%{...reporter}, subtasks()) none in fieldValue(%{...reporter}, linkedIssues()) , checks whether there isn't a single sub-task reporter among linked issues reporters.
[1, 2] none in [3, 4, 5]
["blue", "red"] none in ["black", "white", "green"]


Case Ignoring Operators

The following comparison operators are applicable to String and String List types. This operators have the peculiarity that ignores the case of the characters.

OperatorMeaningExamples (all examples return true)
=~ equal to "HELLO" =~ "Hello"
"up" =~ "UP"
["blue", "red", "green"] =~ ["Blue", "RED", "Green"]
!=~ not equal to " HELLO" !=~ "Hello"
"up" !=~ "down"
("up" !=~ "UP") = false
["blue", "red"] !=~ ["Blue", "green"]
["blue", "red"] !=~ ["Red", "BLUE"]
(["blue", "red", "green"] !=~ ["Blue", "RED", "Green"]) = false
~~ contains "Hello World!" ~~ "world" , checks whether a string contains a substring.
"A small step for a man" ~~ "STEP" , checks whether a string contains a substring.
["one", "two", "three"] ~~ ["TWO", "One"] , checks whether a string list contains all the elements of another string list.
!~~ doesn't contain "Hello World!" !~~ "bye" , checks whether a string doesn't contain a substring.
"A small step for a man" !~~ "big" , checks whether a string doesn't contain a substring.
["one", "two", "three"] !~~ ["Four"] , checks whether a string list doesn't contain one element of another string list.
(["one", "two", "three"] !~~ ["TWO"]) = false
in~ is contained in "world" in~ "Hello World!" , checks whether a substring is contained in another string.
"STEP" in~ "A small step for a man" , checks whether a substring is contained in another string.
["TWO", "One"] in~ ["one", "two", "three"] , checks whether all the elements of a string list are contained in another string list.
not in~ isn't contained in "bye" not in~ "Hello World!" , checks whether a substring is not contained in another string.
"big" not in~ "A small step for a man" , checks whether a substring is not contained in another string.
["Four"] not in~ ["one", "two", "three"] , checks whether any of the elements of a string list are not contained in another string list.
(["TWO"] not in~ ["one", "two", "three"]) = false
any in~ some element is in ["blue", "violet"] any in~ ["Blue", "Red", "Green"]
["Five", "One"] any in~ ["FOUR", "FIVE", "SIX"]
none in~ no single element is in ["Orange"] any in~ ["red", "blue", "green"]
(["orange"] any in~ ["Red", "Orange"]) = false


Applicable Data Types

Comparison OperatorBooleanNumberStringNumber ListString ListIssue ListMulti-Valued Fields
= XXXXXXX
!= XXXXXXX
< -XX----
> -XX----
<= -XX----
>= -XX----
~ --XXXXX
!~ --XXXXX
in --XXXXX
not in --XXXXX
any in ---XXXX
none in ---XXXX
=~ --X-X--
!=~ --X-X--
~~ --X-X--
!~~ --X-X--
in~ --X-X--
not in~ --X-X--
any in~ ----X--
none in~ ----X--

Notice that:

  • Operators ~, !~, in  and not in can be used for checking a single element (number or string) against a  number list or a string list. Example: 1 in [1, 2, 3] or ["blue", "red"] ~ "blue" .
  • Operators ~, !~, in  and  not in when used with string are useful to look for substrings in another string. Example: "I love coding" ~ "love" but "I don't like Mondays" !~ "Fridays", or "love" in "I love coding" but "Fridays" not in "I don't like Mondays" .
  • Operators  ~!~in  and  not in respect cardinality, i.e., container list must have at least the same number of elements as contained list. Example: [1, 1] in [1, 1, 1] but [1, 1] not in [1, 2, 3] .
  • Operators = and != , when used for comparing lists, require to have the same elements, with the same cardinality and the same order. Example: [1, 2, 3] = [1, 2, 3] but [4, 5, 6] != [4, 6, 5] .
  • Operators <, >, <= and >= work according to lexicographical order when comparing strings.


A reference of all data types can be found here.


  • Operators ~, !~, in and not in
  • Operators any in and none in
  • Operators =~, !=~, ~~, !~~, in~, not in~, any in~ and none in~

Boolean expressions

Numbers, dates and times

Strings

Issue lists

Number lists

String lists

List operators

Selectable fields

Users, groups and roles

Historical field values

Versions

Miscellaneous