You are not logged in. Click here to log in.

codebeamer Application Lifecycle Management (ALM)

Search In Project

Search inClear

Calculated Issue Fields


From CB-5.4 you can define read-only tracker fields whose content is calculated from other tracker item fields.

Every custom field can become a computed field, by specifying an expression or formula for the field:

Figure: Tracker Customize Field Properties


Example 1: Past Deadline Test (for Issue Resolution )

In this example, we want to display whether we have already passed an issue's scheduled End Date. Click 'Add custom field' at the bottom of the Tracker → Customize → Field Properties tab. ('Past End Date' is already implemented by codeBeamer, using the red exclamation mark in the issue display). Our new custom field is called 'Past Deadline', and it must be set up as type boolean, and it returns true if the issue is very late. Under the 'Layout and Content' column of the Field Properties, for the new custom field, the '=' field is defined as:

not(endDate >= fn:Date("today"))

Be sure to checkmark the list column to list the field (Selected in the Field Properties) if desired. Also be sure to set up appropriate permissions under the Field Access tab, to allow the field to be viewed. The write permissions, as specified under Field Access, only take effect if the custom field's computed-value field definition is deleted, and it becomes a non-computed field. For more information about functions available for the computed tracker fields, see the Functions section of this document, below.

Example 2: Weight = Priority * Severity

We want to combine issue priority and severity into a new field “Weight”, with

Weight = Priority * Severity

Priority is a (single) choice field with the following choice values:

Figure: Priority Choice Field Values

Severity is a (multiple) choice field with these defined values:

Figure: Severity Choice Field Values

All choice fields, except Status and Priority, are lists or arrays of values. However, the GUI for static choice fields currently only allows selection of a single value. So in order to access the first/single value of a (multiple) choice field, we must use the [0] operator, e.g. Severity[0].

The “Highest” priority and the highest severity (“Blocker”) selections both have the lowest ID, so in order to compute a Weight proportional to the logical order of Priority and Severity, we must use operands that are inversely proportional to the choice value ids, e.g. : integer Weight =

(5 - Priority.id) * (6 - Severity[0].id)

An empty Priority or Severity would yield an id of null, so the above formula would return the highest possible weight (= 30) for issues with empty Priority and Severity, which is wrong, so we must handle empty values appropriately, i.e.: integer Weight =

(empty Priority ? 0 : 5 - Priority.id) * (empty Severity ? 0 : 6 - Severity[0].id) 


Example 3: Compute column(s) in an embedded table from the values of other column(s)

Since CB-7.3, a tracker (item) can also have tables. A table consists of one or more columns.

E.g. A table called Matrix containing four columns:




The first two columns A and B contain numeric operands and the other two columns should contain the product and sum/total of the operands (per row).


If you are addressing a table column, e.g. via it's attribute/property name tableColumn[0,1], then you must be aware, that you always address the whole column (an array/vector of column values (indexed by row)).

E.g. for this table

A B
1 5
2 6
3 7


The expression A or tableColumn[0,0] would yield [1, 2, 3] and B or tableColumn[0,1] would be [5, 6, 7].

To address the whole table, use the table's name or attribute, e.g. Matrix or table[0], which would yield an array of table rows, where each row is an array of table column values (in the order of the columns).

[
  [1, 5],
  [2, 6],
  [3, 7]
]


The index of the first row is 0 and the first table row can be accessed as

  • table[0][0]or
  • Matrix[0],
and would yield [1, 5].

To address the value of Column A (tableColumn[0,0]) in the second row of the Matrix, you could write:
  • table[0][1][0]
  • Matrix[1][0]
  • tableColumn[0,0][1]
  • A[1]

So how can we define a third column Product, whose value is the product of A multiplied by B (for each row) ?

If we would define Product to be computed as
  • tableColumn[0,0] * tableColumn[0,1]
  • or simply A * B,
then this would mean a multiplication of two vectors, e.g. [1, 2, 3] * [5, 6, 7], an operation not supported by the expression language.
Also the result would be a two dimensional array, and not a one-dimensional column value vector !

The solution is, to use a projection: table.{ row | expression } , that iterates over each row in the table and produces an array of values, one value per row according to expression!




The projection/expression
table[0].{row | row[0] * row[1] }

reads as:

  • Iterate over table[0]
    • for each row (an array of column values)
      • evalute the expression row[0] * row[1]
  • return an array of the expression values per row


So for our example table, the result would be the array/vector: [5, 12, 21]

Please note that tableColumn[x,y] is a fixed property name text, therefore y is not adjusted when column position is changed. When defining formulas involving table columns, one may not rely on the order of columns, but property names have to be checked (this can be done by setting the "Show property name" check-box in field configuration page).

At other places [y] is used as an index number (not text). For example table[x][y] refers to the y-th row in table[x].

Caution: The interpretation of table column indices has changed with codeBeamer 20.11 and newer, which could break expression written in older versions!
  • Before 20.11, a column index was interpreted as the ordinal index of the column in the table's columns list.
    • Adding, Removing or Re-ordering columns could therefore change the ordinal index of a column!

      E.g.: Switch position of Sum and Product:



      The ordinal index of Product, that was 2, is now 3, which leads to an inconsistency in table cell access via table column index:
      • table[0][row][3] != tableColumn[0,2][row]

  • After 20.11, a column index is always interpreted as the immutable/unique column id, which is the second index in the immutable/unique column property name.
    E.g. the column id/index of Product (tableColumn[0,2]) is 2, independent of it's position.
    • Adding, Removing or Re-ordering columns will not change the column id/index of existing columns and column access stays consistent:
      • table[0][row][2] == tableColumn[0,2][row]

Syntax

Unified Expression Language (EL) syntax is used for the field values' formulae.

The unified expression language defines the following literals:

  • Boolean: true and false
  • Integer: as in Java
  • Floating point: as in Java
  • String: with single and double quotes; " is escaped as \", ' is escaped as \', and \ is escaped as \\ .
  • Null: null


In addition to the . and [] operators, the expression language provides the following operators:

  • Arithmetic: +, - (binary), *, / and div, % and mod, - (unary)
  • Logical: and, &&, or,||, not, !
  • Relational: ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le. Comparisons can be made against other values, or against boolean, string, integer, or floating point literals.
  • Empty: The empty operator is a prefix operation that can be used to determine whether a value is null or empty.
  • Conditional: A ? B : C. Evaluate B or C, depending on the result of the evaluation of A.
  • Projection: .{alias|expression} Is a special operator on collections, that iterates over the collection and creates a new collection by evaluating the specified (sub-) expression for each element alias of the original collection.


The precedence of operators highest to lowest, left to right is as follows:

  • [] .
  • () - Used to change the precedence of operators.
  • - (unary) not ! empty
  • * / div % mod
  • + - (binary)
  • < > <= >= lt gt le ge
  • == != eq ne
  • && and
  • || or
  • ? :


The following words are reserved for the JSP expression language and should not be used as identifiers.

and eq gt true instanceof
or ne le false empty
not lt ge null div mod


Many of these words are not in the language now, but they may be in the future, so you should avoid using them. For more information on the Unified Expression Language, you could start with: http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html

Context variables

The execution/evaluation context of a unified expression contains the following objects:

Object Type Comment
user UserDto The current user, that executes/evaluates the expression (since CB-9.2)
project ProjectDto The current project, the expression is evaluated in
tracker TrackerDto The current tracker, the expression is evaluated in
this TrackerItemDto The current tracker item, the expression is evaluated on
orig TrackerItemDto In CB-9.3 and newer, you can refer to old/original values of a tracker item during a state transition or update via orig.
If the expression is not evaluated in the context of a tracker item state transition or update, then orig is the same as this.
E.g. (dflt(this.storyPoints, 0) - dflt(orig.storyPoints, 0) calculates the difference between the new and the old story points.


You can use the dot (.) operator, to access attributes of context objects, e.g. user.realName or project.name.


To access attributes (fields) of the current tracker item (this), you can ommit this. in front of the attribute/field identifier, e.g. submitter is equivalent to this.submitter.


To refer to (the value) of tracker item fields, the following field identifiers are allowed:

  • the field property/attribute name, e.g. id, name, description, submitter, submittedAt, namedPriority, status, assignedTo, subjects, categories, versions, customField[0], choiceList[2], etc.
  • or the field label, but only,
    • if the label only consists of alphanumeric characters ([A-Z],[a-z],[0-9]), ‘$‘(dollar sign) and ‘_‘ (underscore),
    • does not start with digits ([0-9])
    • and does not contain HTML markup.
    • e.g. Color is allowed, but Background color, Best.-Nr., Estimated<br/>Effort or <b>v</b><sub>max</sub> (vmax) are not allowed
  • or the RESTful field name (lower camel case of field label, with all HMTL markup and not allowed characters removed)
    • e.g. color, backgroundColor, bestNr, estimatedEffort and vmax


The field's property and label are displayed in their respective columns in the Tracker → Customize → Field Properties area.


For static choice fields, in CB-9.3 and newer, you can also refer to

  • the list of defined choice field options: choiceField_$options
    • e.g. status_$options or choiceList[1]_$options
  • a specific choice field option, per option id or lowercase option name: choiceField_$option[idOrName]
    • e.g. status_$option["new"], namedPriority_$option["high"] or choiceList[1]_$option[2]
    • Choice option names can be changed, to using option ids is safer, although using option names may be more convenient or easier to understand.


To access individual values of multi-value choice fields, use the [] operator, e.g. categories[0], choiceList[2][0]


Please note: choiceList[1]_$option[2] refers to the option with id==2 of the choice field choiceList[1], not the third option.


To access attributes of complex field values, e.g. choice values, use the . operator followed by the attribute, e.g. Priority.id, Status.name, Resolution[0].name


All references, choice and members field values have at least the following attributes:

  • id Integer
  • name Text


To extract attributes from a multi-value field, use a projection. E.g. to create a list of the names of all users/roles assigned to the item, you can use:

assignedTo.{member|member.name} 


You can use such a projection in combination with the function valuesInList to check if the item is assigned to some particular users, e.g.

fn:valuesInList(assignedTo.{member|member.name}, “bond”, “Project Admin”) ?



Functions

Within field value expressions/formulas, you can use the following standard functions:

Function Signature Meaning
concat String concat(Object...) Converts all parameters to strings and concatenates them to a single result string.
contains boolean contains(String text, String part) Tests, if the specified text contains the specified part
containsIgnoreCase boolean containsIgnoreCase(String text, String part) Tests, if the specified text contains the specified part, irrespective of case
endsWith boolean endsWith(String text, String suffix) Tests if the specified text ends with the specified suffix
escapeXml String escapeXml(String text) Escapes characters with a special meaning in XML with appropriate escape sequences
format String format(String pattern, Object... args) Create a string representation of the specified arguments using a MessageFormat pattern.
indexOf int indexOf(String text, String part) Finds the first index of the specified part within text, or -1 if not found
join String join(String[] array, String separator) Joins the elements of the provided array into a single String, separated by the separator
length int length(Object) Returns the length of the passed string, or the number of elements of the passed array or collection
printf String printf(String format, Object... args) Create a string representation of the specified arguments using a printf like format
replace String replace(String text, String replace, String replacement) Replaces a String with another String inside a larger String
split String[] split(String text, String separator) Splits the provided text into an array (at each occurence of the separator)
startsWith boolean startsWith(String text, String prefix) Tests if the specified text starts with the specified prefix
substring String substring(String text, int start, int end) Gets a substring from the specified String, from the start position (inclusive) to the end position (exlusive)
substringAfter String substringAfter(String text, String separator) Gets the substring after the first occurrence of the separator
substringBefore String substringBefore(String text, String separator) Gets the substring before the first occurrence of the separator
substringBetween String substringBetween(String text, String open, String close) Gets the substring after the first occurrence of the open string and before the occurance of the close string
toLowerCase String toLowerCase(String text) Converts a String to lower case
toUpperCase String toUpperCase(String text) Converts a String to upper case
trim String trim(String text) Removes leading and trailing whitespace


The case of function names is significant. The usage of the prefix fn: when referring to functions is optional, e.g.

concat(customField[3], " ", customField[4], " has downloaded and installed codeBeamer.")

or

fn:format("{0,date,yyyy-MM-dd HH:mm}", submittedAt)



In CodeBeamer 8.2.1 and newer, there is also:

Function Signature Meaning
distinct List distinct(List list) Returns a list with all not null/distinct/unique values in the specified list.
min Object min(List list) Returns the minimum/smallest value in the specified list
max Object max(List list) Returns the maximum/largest value in the specified list
sum Number sum(List list) Returns the sum/total of all numeric values in the specified list
avg Double avg(List list) Returns the average of all numeric values in the specified list
dflt Object dflt(Object... value) Returns the first of the specified objects, that is not null


New functions in codeBeamer 9.3.0

Function Signature Meaning
union List union(Object... values) Returns a new list, that contains the union of all distinct values. If values are lists or arrays, then the list/array items are included in the union, not the list/arrays themselves.
E.g. union(assignedTo, supervisors) gives you the distinct union of all groups, users and roles, that are either assignedTo or supervisors of the current item
union( members(project, Role("Project Admin")), User("KlausMehling") ) gives you the distinct union of all users and groups, that have the role with name "Project Admin" in the current project, plus the user with name "KlausMehling"
intersection List intersection(Object... values) Returns a new list, that contains the intersection of the specified values. If the values are lists or arrays, then the intersection contains those distinct elements, that are common in all values.
E.g. intersection( members(project, Role("Project Admin")), members(project, Role("Stakeholder")) )
gives you the list of those users and groups, that have the role "Project Admin" and the role "Stakeholder" in the current project.
disjunction List disjunction(Object... values) Returns a new list, that contains the disjunction of the specified values. If the values are lists or arrays, then the disjunction contains those distinct elements, that are not common in all values
subtract List subtract(Object... values) Returns a new list, that contains the first value, that should be a list or array, minus all other values, that can be individual values or also lists or arrays.
E.g. subtract(assignedTo, members(project, Role("Developer") ) returns the distinct users, groups and roles, that are assigned to the current item, except those users and groups, that are have the role "Developer" in the current project.
ascending List ascending(List list) Returns a new list, that contains the items of the specified list in ascending order
descending List descending(List list) Returns a new list, that contains the items of the specified list in descending order
reverse List reverse(List list) Returns a new list, that contains the items of the specified list in reverse order
first List first(int x, List items) Returns a new list, that contains the first x items of the specified list, or the list itself, if it does not contain more than x items
last List last(int x, List items) Returns a new list, that contains the last x items of the specified list, or the list itself, if it does not contain more than x items
User UserDto User(Object idOrName) Returns the user with the specified id or name, e.g. User(1) is the user with id == 1, User("bond") is the user with name == "bond"
Group ArtifactDto Group(Object idOrName) Returns the user group artifact with the specified id or name, e.g. Group(1) is the user group with id == 1, Group("sysadmin") is the user group with name == "sysadmin"
Role RoleDto Role(Object idOrName) Returns the role stereotype with the specified id or name, e.g. Role(1) is the role (stereotype) with id == 1, Role("Project Admin") is the role (stereotype) with name == "Project Admin"
Project ProjectDto Project(Object idOrName) Returns the project with the specified id or name, e.g. Project(1) is the project with id == 1, Project("Demo") is the project with name == "Demo"
Tracker TrackerDto Tracker(Object... idOrName) Returns the tracker with the specified id or the tracker with the specified name in the specified project, e.g. Tracker(1234) is the tracker with id == 1, Tracker(project, "Bugs") is the tracker with name == "Bugs" in the current project, Tracker(Project("Demo"), "Tasks") or short Tracker("Demo", "Tasks") is the "Tasks" tracker in the "Demo" project.
Item TrackerItemDto Item(Integer id) Returns the tracker item with the specified id, e.g. Item(123456)
typeOf String typeOf(Object object) Returns the type of the specified object: ["User", "Group", "Role", "Project", "Tracker", "Item", "Option", "Object", "Array", "List", "Date", "number", "boolean", "string", "undefined"]
members List members(Object... values) Returns a list of users, groups and roles according to the specified values.
E.g. members(Group("sysadmin")) gives all users, that are member in the group "sysadmin".
members(project, Role("Developer"), Role("Stakeholder"), Project("Demo"), Role("Tester") gives the distinct set of users and groups, that have the roles "Developer" or "Stakeholder" in the current project, or the role "Tester" in the "Demo" project.
members(assignedTo, supervisors, choiceList[4]) gives the distinct set of all users, groups and roles, that are referenced in the fields assignedTo, supervisors and choiceList[4].
users List users(Object... values) Returns a list of users according to the specified values.
E.g. users(assignedTo, supervisors) gives all users, that are directly assigned to or supervisors of this item.
users(this, true, assignedTo) gives the distinct set of users, that are directly assigned to this item, or indirectly, because they are member in a group, that is assigned.
users(project, true, Role("Developer")) gives the distinct set of users, that are either directly or indirectly member in the role "Developer" of the current project.
users("klaus", "bond") returns a list containing the users with names "klaus" and "bond".
users("bond", Group("sysadmin"), Project("Demo"), true, Role("Project Admin"), Role("Stakeholder")) returns a list containing the distinct set of user "bond", members of group "sysadmin" and direct and indirect members of role "ProjectAdmin" and "Stakeholder" of project "Demo".
groups List groups(Object... values) Returns a list of groups according to the specified values.
E.g. groups(assignedTo, supervisors) returns a list of all distinct groups, that are directly assigned to or supervisor of the current item.
groups(this, true, assignedTo) returns a list of all distinct groups, that are either directly or indirectly (via role) assigned to the current item.
groups(project, Role("Project Admin")) returns a list of all user groups, that have the role "Project Admin" in the current project.
groups(4711, "sysadmin") returns a list containing the group with id == 4711 and also the group with name == "sysadmin"
roles List roles(Object... values) Returns a list of roles according to the specified values.
E.g. roles(assignedTo, supervisors) returns a list of all distinct roles, that are directly assigned to or supervisor of the current item.
roles(project) returns a list of all roles in the current project
roles("ProjectAdmin", "Developer") returns a list with specified named roles
projects List projects(Object... values) Returns a list of projects according to the specified values.
E.g. projects(choiceList[6]) returns all projects, that are referenced in the choiceList[6] of the current item.
projects(6378, 1542, 21746) returns a list of the projects with the specified ids (or names)
trackers List trackers(Object... values) Returns a list of trackers according to the specified values.
E.g. trackers(subjects.{subject|subject.choiceList[5]}) returns all trackers, that are referenced in the choiceList[5] of all subjects of the current item.
trackers(project, "Bug", "Task") returns a list of all Bug and Task trackers in the current project.
trackers(Project("Demo"), "Customer Requirement Specifications", "System Requirements Specifications") return a list with the Customer - and System Requirement Specifications trackers of the "Demo" project


Plus additional mathematical functions:


Function Signature Meaning
Integer Integer Integer(Object value) Returns an Integer, if the specified value is a numeric value, e.g. a Number or a numeric string, otherwise null.
Number Number Number(Object value) Returns a Number, if the specified value is a numeric value, e.g. a Number or a numeric string, otherwise null.
random Double random() Generates a pseudo random number in the range [0 .. 1)
sin Double sin(Number angle) Returns the trigonometric sine of an angle (in radians)
cos Double cos(Number angle) Returns the trigonometric cosine of an angle (in radians)
tan Double tan(Number angle) Returns the trigonometric tangent of an angle (in radians)
asin Double asin(Number value) Returns the arc sine of a value; the returned angle is in the range [-π/2 .. π/2].
acos Double acos(Number value) Returns the arc cosine of a value; the returned angle is in the range [0 .. π].
atan Double atan(Number value) Returns the arc tangent of a value; the returned angle is in the range [-π/2 .. π/2].
toRadians Double toRadians(Number angle) Converts an angle measured in degrees to an approximately equivalent angle measured in radians
toDegrees Double toDegrees(Number radians) Converts an angle measured in radians to an approximately equivalent angle measured in degrees
exp Double exp(Number x) Returns ex, where e is Euler's number.
sinh Double sinh(Number x) Returns the hyperbolic sine of a value, that is defined to be: (ex - e-x) / 2
cosh Double cosh(Number x) Returns the hyperbolic cosine of a value, that is defined to be: (ex + e-x) / 2
tanh Double tanh(Number x) Returns the hyperbolic tangent of a value, that is defined to be: (ex - e-x) / (ex + e-x), in other words: sinh(x) / cosh(x).
log Double log(Number x) Returns the natural logarithm (base e) of a value: ln(x) or loge(x)
log10 Double log10(Number x) Returns the base 10 logarithm of a value: log10(x)
sqrt Double sqrt(Number x) Returns the (positive) square root of a value: √x
cbrt Double cbrt(Number x) Returns the cube root of the value: ∛x
pow Number pow(Number x, Number y) Returns the value of x raised to the power of y: xy
abs Number abs(Number x) Returns the absolute value: |x|
floor Long floor(Number x) Returns the largest integer value ≤ x
ceil Long ceil(Number x) Returns the smallest integer value ≥ x
round Long round(Number x) Returns the integer value, that is closest to x
signum Integer signum(Number x) Returns -1, 0 or 1, depending on whether the number is less, equal or greater than 0.


Plus functions for random string generation:


Function Signature Meaning
randomString String randomString(int length) Creates a random string whose length is the number of characters specified.
randomAscii String randomAscii(int length) Creates a random string whose length is the number of characters specified and that only contains ASCII characters [32 .. 126]
randomAlphabetic String randomAlphabetic(int length) Creates a random string whose length is the number of characters specified and that only contains alphabetic characters.
randomAlphanumeric String randomAlphanumeric(int length) Creates a random string whose length is the number of characters specified and that only contains alpha-numeric characters.
randomNumeric String randomNumeric(int length) Creates a random string whose length is the number of characters specified and that only contains numeric characters.


Plus functions for net working time arithmetic, based on the System default and Project specific Working Time settings:

Function Signature Meaning
isWorkday boolean isWorkday(Object context, Date date Check if the specified date is on a work day, according to the work time calendar in the specified context, that should be a project or project aware object, e.g. tracker or tracker item. If context is null, then the system wide work time calendar will be used.
scrollToWorkday Date scrollToWorkday(Object context, Date date, boolean forward Scroll the specified date to the same time-of-day of the next/previous work day.
If the specified date is already a work day, then the unmodified date and time will be returned.
To scroll to the next/previous work day other than the specified day, use scrollWorkdays(context, date, ±1)
scrollWorkdays Date scrollWorkdays(Object context, Date date, int days Scroll the specified date to the same time-of-day the specified number of work days ahead or back.
scrollToWorkTime Date scrollToWorkTime(Object context, Date date, boolean forward) Scroll the specified date to the next/previous business/working hours.
If the date is already within working hours, then the date will not be modified.
scrollWorkTime Date scrollWorkTime(Object context, Date date, int distance, String unit) Scroll the specified Calendar date by the specified distance of net working time.
The distance can be positive, to scroll forward into the future, or negative, to scroll backwards into the past.
The scroll unit can be "d(ay(s))", "h(our(s))", "m(in(ute(s)))" or "s(ec(ond(s)))", where 1 d(ay) = 24 h(ours)
workTimeBetween Long workTimeBetween(Object context, Date from, Date until, String unit) Get the net working time between the two specified dates in the specified unit.
If from or until is null, then the result will be null.
If from is after until, then the result will be negative.
The result unit can be "d(ay(s))", "h(our(s))", "m(in(ute(s)))", "s(ec(ond(s)))" or null to return milliseconds.


These new functions (plus the previously existing length and join allow to define map/reduce expressions, typically but not exclusively, in conjunction with (multi-level) projections.

E.g.:
A task has multiple subjects (via the subjects reference field). Each subject is another tracker item, that each has a priority.
The priority of the task should reflect the highest priority of all subjects:

max(subjects.{subject|subject.priority})


E.g.:
A Bug refers to one or more Builds, that are affected by this bug (via a custom reference field, e.g. choiceList[1]).
Each Build is a config item, that itself refers to a Release (via the versions field). Different Builds can belong to the same Release.
The field Detected in (Release) of the Bug should now be automatically computed to reflect the Releases of all Builds affected by this bug:

distinct(choiceList[1].{build|build.versions.{version|version}})

Please note the nested projections, which executes as

List result;
for (Object build in choiceList[1]) {
  for (Object version in build.versions) {
     result.add(version);
  }
}
return distinct(result);


E.g.:
The Severity of an item should be the highest Severity of all Subjects:

List(min(subjects.{subject|subject.severities.{severity|severity}}))

or

first(1, ascending(subjects.{subject|subject.severities.{severity|severity}}))

Please note:

  • Severity is a choice list/field, so the field value is a list of choice options. By default, only one list element is allowed.
  • Severity choice options are ordered descending from Highest to Lowest, so we must use min or first in order to get the highest severity.


E.g.:

Show the last two comments on the tracker item:

join(first(2, reverse(distinct(attachments.{attachment|attachment.description}))).toArray(), "\\\\")

That reads as:

  • Collect the comments of all attachments:
    attachments.{attachment|attachment.description} 
  • Remove all duplicates and empty comments:
    distinct(...)
  • Reverse the order of comments (last comment first):
    reverse(...)
  • Extract the first 2 comments (due to reverse order, these are the last/newest 2 comments in descending order):
    first(2, ...)
  • Concatenate the comments into a single string, separated by a Wiki linebreak:
    join(... .toArray(), "\\\\")



CodeBeamer also provides the following specific functions:


Function Signature Meaning
List List List(Object...) Create a List from the passed arguments or the passed array
Date Date Date(String date[, String timezone]) Create a date according to the passed argument (and timezone).
roundDate Date roundDate(Date date, String precision) Round a date according to the specified precision (see below)
truncateDate Date truncateDate(Date date, String precision) Truncate a date according to the specified precision (see below)
shiftDate Date shiftDate(Date date, int distance, String unit) Shift a date by the specified distance in the specified unit (see below).
To shift by net working time, you should use scrollWorkTime (CB-9.3 and newer) instead.
timeBetween Long timeBetween(Date date1, Date date2, String unit) Returns the time between two dates in the specified unit (see below), based on 7 days per week, 24 hours per day, 60 minutes per hour and 60 seconds per minute.
To get the net working time between two dates, you should use workTimeBetween (CB-9.3 and newer) instead.
The result can be negative, if date1 is after date2.
E.g. timeBetween(Date("2018-12-31"), Date("2019-01-01", "Year") returns 0, because the difference between the two dates is less than a year. It's also less than a month or a week.
But it is 1 "d(ay(s))", 24 "h(our(s))", 1440 "m(in(ute(s)))" or 86400 "s(ec(ond(s)))".
inSamePeriod boolean inSamePeriod(Date date1, Date date2, String period) Returns true if both dates are within the same calendar period, e.g. "Year", "Month", "Day", etc.
E.g. inSamePeriod(Date("2019-01-01 00:00"), Date("2019-01-01 12:00", period) returns true for "Y(ear)", "M(onth" and "d(ay)" and false for any other period.
isSameDay boolean isSameDay(Date date1, Date date2) Returns true if both dates are within the same calendar day.
This is equivalent to inSamePeriod(date1, date2, "day").
countryCode String countryCode(String country) Get the ISO 3166 2-letter country code for the specified country code or English country name
valueInList boolean valueInList(Object value, Object... values) Returns true if the first argument is equal to any of the following arguments
valuesInList boolean valuesInList(Iterable list, Object... values) Returns true if any element of the specified collection or array is equal to any of the following arguments.
objectInList boolean objectInList(NamedDto object, String csv) Returns true if the specified object is referenced in the specified comma-separated list of object references
objectsInList boolean objectsInList(List<? extends NamedDto> objects, String csv) Returns true if any of the specified objects is referenced in the specified comma-separated list of object references
objectIdInList boolean objectIdInList(Identifiable object, Integer... ids) Returns true if the ID of the specified object is equal to any of the specified ids
objectIdsInList boolean objectIdsInList(List<Identifiable> objects, Integer... ids) Returns true if the ID of an object in the specified list is equal to any of the specified ids.


In CB-9.2 and newer, there is also:


Function Signature Meaning
userInGroup boolean userInGroup(UserDto user, String... groups) returns true, if the specified user is member in at least one of the specified user groups, otherwise false
userInRole boolean userInRole(UserDto user, ProjectDto project, String... roles) returns true, if the specified user has at least one of the specified roles in the specified project, otherwise false
userHasPermission boolean userHasPermission(UserDto user, String... permissions) returns true, if the specified user has at least one of the specified System permissions (see table below), otherwise false
userHasProjectPermission boolean userHasProjectPermission(UserDto user, ProjectDto project, String... permissions) returns true, if the specified user has at least one of the specified Project permissions (see table below) on the specified project, otherwise false
userHasTrackerPermission boolean userHasTrackerPermission(UserDto user, TrackerDto tracker, String... permissions) returns true, if the specified user has at least one of the specified Tracker permissions (see table below) on the specified tracker, otherwise false



The parameter date for the function Date, can be either an absolute date specified as:

  • "yyyy-MM-dd[ HH:mm[:ss]]"
  • plus an optional time zone, e.g.
    • "UTC", if the literal represents coordinated universal time
    • "default", "system" or "local", if the literal represents default/system/local time (of the codeBeamer installation/server).
    • the time zone offset from GMT, as "GMT[±][hh[:mm]]"
    • a time zone abbreviation
    • if no timezone for the date is specified, the default will be the time zone of the current user, or, if there is no current user, or if it does not have a special time zone setting, the default time zone of the codeBeamer system.

or one of the following String constants:

  • "Now"
  • "Today"
  • "Tomorrow"
  • "Yesterday"
  • "Start of this week"
  • "End of this week"
  • "Start of next week"
  • "End of next week"
  • "Start of last week"
  • "End of last week"
  • "Start of this month"
  • "End of this month"
  • "Start of next month"
  • "End of next month"
  • "Start of last month"
  • "End of last month"
  • "Start of this year"
  • "End of this year"
  • "Start of next year"
  • "End of next year"
  • "Start of last year"
  • "End of last year"

E.g:

endDate >= Date("today")


The precision for roundDate and truncateDate and the unit of shiftDate and timeBetween must be (an abbreviation of) :

  • "Year"
  • "Month"
  • "Week"
  • "day"
  • "hour"
  • "minute"
  • "second"

E.g:

roundDate(endDate, "h")
shiftDate(startDate, 30, "min")

For single value attributes like status, priority or submitter, you can use valueInList().
E.g. Check if the name of the user that has submitted the item is “bond” or “klaus”:

valueInList(submitter.name, "bond", "klaus")


But for attributes with multiple values (e.g. assignedTo, supervisors, subjects, versions, etc. plus all custom choice lists), checking for constant values requires valuesInList() in combination with a projection.
E.g. To check if the issue owner/supervisors list contains any of the specified users (by name):

valuesInList(supervisors.{principal|principal.name}, "bond", "klaus")


The function objectIdsInList() is functionally equivalent to

valuesInList(objects.{object|object.id}, ids)

E.g: Check if the field “Resolution” contains a value with ID 2 or 4:

objectIdsInList(resolutions, 2, 4)

or

valuesInList(resolutions.{resolution|resolution.id}, 2, 4)



The groups parameter(s) for the function userInGroup, are the names of User Groups:

User Group Description
sysadmin The System Administrators Group
user The "Regular" User Group


There can be any number of additional user groups.


In most cases, it will be more appropriate to check, if a user has a specific System Permission (that can be granted via different User Groups), e.g. instead of

userInGroup(user, "sysadmin")

you would use

userHasPermission(user, "system_admin")




The roles parameter(s) for the function userInRole, are the names of Project Roles :

Project Role Description
Project Admin The role for Project Administrators
Developer The role for (Software) Developers in the project
Stakeholder The role for Stakeholders in the project
Product Owner The role for Product Owners in the project
Scrum Master The role for Scrum Masters in the project
Test Lead The role for Test Lead(er)s in the project
Test Engineer The role for Test Engineers in the project
Tester The role for Testers in the project


There can be any number of additional project roles.


E.g. Check if the current user has the role Developer or Tester in the current project:

userInRole(user, project, "Developer", "Tester")

P.S. In most cases, it will be more appropriate to check, if a user has a specific Project Permission (that can be granted via different Project Roles), e.g. instead of

userInRole(user, project, "Project Admin")

you would use

userHasProjectPermission(user, project, "project_admin")



The permissions parameter(s) for the function userHasPermission, are the names of System Permissions:


System Permission Description
wiki_edit_own_page Allows users to edit own Wiki pages
account_admin_own Allows users to administer own account data settings
account_modify_own_timezone_dateformat Allows users to administer own timezone and date format data settings
account_admin Allows users to administer all account data settings (name,e-mail,password, phone number, ...)
account_address_view Allows users to view the address field in all accounts
account_company_view Allows users to view the company field in all accounts
account_phone_view Allows users to view the phone field in all accounts
account_email_view Allows users to view the email field in all accounts
account_skills_view Allows users to view the skill field in all accounts
account_role_view Allows users to view user group settings and members
account_role_admin Allows users to create, administer user groups and assign members
document_add_global Allows users to add new project-independent documents
label_public_create Allows users to create new public tags
label_public_admin Allows users to administer public tags
system_project_create Allows users to create a new project
system_admin Allows users to administer the portal
service_desk Allows users to access the Service Desk
queries_view Allows users to access Queries
review Allows users to do Reviews
api_permission Allows user to access to the Rest / Remote API
only_api_permission If set, users in groups with this permission cannot use the GUI


System permissions are granted to user groups and indirectly to all users in that groups.



The permissions parameter(s) for the function userHasProjectPermission, are the names of Project Permissions:


Project Permission Description
wiki_space_view Allows users access to the project Wiki
document_view Allows users access to the project "Documents"
document_view_history Allows users to view the document version history
document_add Allows users to add new documents to a project
document_unpack Allows users to upload and unpack Zip and Tar files
document_subscribe Allows users to subscribe documents to get email notifications when a document is read or modified by an other user
document_subscribe_others Allows users to subscribe documents for project members to get email notifications when a document is read or modified by an other user
document_subscribers_view Allows users to view the subscriber list
tracker_view Allows users to view tracker list and the "Trackers" tab
tracker_admin Allows users to administer project trackers, set permissions, add custom fields, set default fields, ...
tracker_report Allows users to access and execute reports
cmdb_view Allows users to view the project CMDB
cmdb_admin Allows users to administer the project CMDB, create categories, set permissions, add custom fields, set default fields, ..
branch_view Allows users to view branches
branch_admin Allows users to administer tracker branches
baseline_view Allows users to view baselines
baseline_admin Allows users to administer project baselines
scm_view Allows users to view the repository hierarchy in this project, even if they don't have access to any of the repositories.
scm_admin Allows users to create new top-level repositories in this project, and to update or delete any existing one.
members_view Allows users to view project members
members_admin Allows users to administer project members
member_role_view Allows users to view project role permission settings
project_admin Allows users to administer all project settings


Project permissions are granted to project roles and indirectly to all project members with that roles.



The permissions parameter(s) for the function userHasTrackerPermission, are the names of Tracker Permissions:


Tracker Permission Description
issue_add Allows users to create new items in a tracker
issue_view Allows users to see own items in a tracker
issue_view_not_own Allows users to see all items in a tracker
issue_edit Allows users to edit own items in a tracker
issue_edit_not_own Allows users to edit any items in a tracker
issue_mass_edit Allows users to mass edit multiple items in a tracker
issue_close Allows users to close items in a tracker
issue_delete Allows users to delete items in a tracker
issue_history_view Allows users to see the history of items in a tracker
issue_escalation_view Allows users to view issue escalation schedules in a tracker
issue_attachment_view Allows users to view issue comments or attachments in a tracker
issue_comment_add Allows users to add comments to issues in a tracker
issue_attachment_add Allows users to add attachments to issues in a tracker
issue_attachment_edit Allows users to edit/delete any issue comments or attachments in a tracker
issue_attachment_edit_own Allows users to edit/delete own issue comments or attachments in a tracker
issue_subscribe Allows users to subscribe notifications on a single tracker item
issue_subscribe_others Allows users to manage subscriptions of other users for notifications on a single tracker item
tracker_subscribe Allows users to subscribe notifications on the whole tracker
tracker_subscribe_others Allows users to manage subscriptions of other users for notifications on the whole tracker
tracker_subscribers_view Allows users to view subscriptions of other users for notifications on the whole tracker
admin_public_view Allows users to administrate (create, update and delete) public views on the tracker
issue_association_view Allows users to see tracker item associations
issue_association_edit Allows users to edit (create, update and delete) tracker item associations
issue_suspected_merge Allows to merge tracker item
branch_merge Allows to merge branches


Tracker permissions are granted to project roles via Tracker → Customize → Permissions, and so indirectly to all project members in that roles.


CB:/images/space.gif

New functions in codeBeamer 9.4.0

Function Signature Meaning
hasSuspectedLink boolean hasSuspectedLink(TrackerItemDto) Returns true if the given tracker item has suspected link(s).
hasUpstreamSuspectedLink boolean hasUpstreamSuspectedLink(TrackerItemDto) Returns true if the given tracker item has upstream suspected link(s).
hasDownstreamSuspectedLink boolean hasDownstreamSuspectedLink(TrackerItemDto) Returns true if the given tracker item has downstream suspected link(s).


E.g. Check if the tracker item does not have suspected links:

!hasSuspectedLink(this)

E.g. Check if the tracker item has upstream suspected links and does not have downstream suspected links:

hasUpstreamSuspectedLink(this) and !hasDownstreamSuspectedLink(this)


Calculated Field Dependencies

A calculated field may use reference fields in its formula. Before 9.5 these computed field values were recalculated when the item was updated. Starting from 9.5 the field value can be recalculated whenever an item the formula depends on is updated. For this to work efficiently codeBeamer need to store the dependencies of the custom fields. You can check these dependencies by clicking on the ''''Compute Dependencies'''' link under the computed field formula textarea. This will parse the formula and show the dependencies (if any). The list consists of the the trackers and fields on which the formula depends.

In some cases this dependency list cannot be computed automatically: when the formula is very complex, when the fields used in the formula refers a tracker type not a tracker explicitly. In this cases you can add a dependency manually using the select lists under the textarea. The lists:

  • Project and Tracker: the tracker of the referring field that the formula depends on
  • Field: the field that the formula depends on
  • Referred Tracker: a tracker referred by the field. If an item from this tracker referenced through the field is updated then the formula is recalculated.

Note that whenever you change the formula your manually added dependencies are cleared and you need to add them manually.