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. |
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:
(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. "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.true
or false
. %{...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. 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. ["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. The parser used in the app for mathematical calculation, time-formulas and boolean expressions uses the following data types:
Data type | Description | Example |
---|---|---|
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. | 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(), | |
| 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(), |
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( |
There are two functions available for transforming types from Text-String to Number and viceversa, and also from other types to Text-String.
Function | Input | Output |
---|---|---|
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(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(number list l) |
| Returns a with a comma separated list of decimal representation of the numeric values in l. Example: |
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(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(string list l) : string |
| Returns a with a comma separated list of string values in l. Example: |
toString(string list l, string separator) |
| Returns a a list of string values in l separated by string separator. Example: |
toString(issue list l) |
| Returns a with a comma separated list of issue keys. Example: |
toString(issue list l, string separator) |
| Returns a with a list of issue keys separated by string separator. Example: |
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, Example: |
toInteger(string s, string radix) |
| returns the represented by the string s as a signed integer in the radix specified by argument radix. Example: |
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(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: |
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: |
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: |
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)
.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.:
Operator | Meaning | Examples (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"] |
The following comparison operators are applicable to String and String List types. This operators have the peculiarity that ignores the case of the characters.
Operator | Meaning | Examples (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 |
Comparison Operator | Boolean | Number | String | Number List | String List | Issue List | Multi-Valued Fields |
---|---|---|---|---|---|---|---|
= | X | X | X | X | X | X | X |
!= | X | X | X | X | X | X | X |
< | - | X | X | - | - | - | - |
> | - | X | X | - | - | - | - |
<= | - | X | X | - | - | - | - |
>= | - | X | X | - | - | - | - |
~ | - | - | X | X | X | X | X |
!~ | - | - | X | X | X | X | X |
in | - | - | X | X | X | X | X |
not in | - | - | X | X | X | X | X |
any in | - | - | - | X | X | X | X |
none in | - | - | - | X | X | X | X |
=~ | - | - | X | - | X | - | - |
!=~ | - | - | X | - | X | - | - |
~~ | - | - | X | - | X | - | - |
!~~ | - | - | X | - | X | - | - |
in~ | - | - | X | - | X | - | - |
not in~ | - | - | X | - | X | - | - |
any in~ | - | - | - | - | X | - | - |
none in~ | - | - | - | - | X | - | - |
Notice that:
~
, !~
, 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"
.~
, !~
, 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"
.~
, !~
, 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]
.=
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]
.<
, >
, <=
and >=
work according to lexicographical order when comparing strings.A reference of all data types can be found here. |
~
, !~
, in
and not in
any in
and none in
=~
, !=~
, ~~
, !~~
, in~
, not in~
, any in~
and none in~
Issue lists