YouTrack Standalone 2017.1 Help

Grammar

This page describes the basic grammar, variable declarations, data types and literals that are used in the YouTrack workflow programming language.

Workflow Language Elements

The workflow programming language borrows most of its syntax from JavaScript. If you are familiar with JavaScript, you will quickly recognize the structure that is used to write a workflow rule.

If you're not a programmer, you can find your way around with the code completion feature in the workflow editor. The workflow editor shows you a list of available options for every element in the code. The editor also displays default text that tells you what is expected for each line.

/help/img/youtrack/2017.1/workflowEditorCodeCompletion_thumbnail.png

The workflow language is case-sensitive and uses the Unicode character set.

Workflow Rule Syntax

The syntax that is used for each rule is defined by the rule type. The workflow editor applies constraints when you write that help you follow the required syntax.

The syntax for each rule type is as follows:

Stateless
rule [rule name] when <issue created or updated> { <define statements> }

The initial when statement determines whether the rule is triggered on issue creation or update.

Schedule
schedule rule [rule name] [schedule] [<expression>] { <define statements> }

The initial schedule statement determines when the rule is triggered. The following intervals are supported:

  • every minute
  • daily at <hour>:<minute>:<second>
  • weekly on <day of week> at <hour>:<minute>:<second>
  • hourly at <minute>:<second>
  • monthly on <day of month> at <hour>:<minute>:<second>
  • yearly on <month>, <day of month> at <hour>:<minute>:<second>
  • cron: [cron expression]

The expression (set in square brackets) that follows the schedule statement is a guard condition. The guard condition determines whether the subsequent statements are executed.

State-machine
statemachine [rule name] for field [field name] } initial state [field value] { } state [field value] { } }

For each state, you specify the conditions for applying an action. The following options are available:

StatementDescription
enterThe changes that are specified in a nested block statement are applied when the field is set to the specified value.
exitThe changes that are specified in a nested block statement are applied when the field is changed from the specified value.
on [action] [condition] do {statements} transit to [field value]The changes that are specified in the {statements} block are applied when the action is applied with a command or the field is set to the specified value. The optional [condition] block specifies additional criteria that must be met to apply the specified changes. After the changes are applied, the issue transitions automatically to the specified value.
in [time frame] [condition] do {statements} transit to [field value]The changes that are specified in the {statements} block are applied after the specified time frame. The optional [condition] block specifies additional criteria that must be met to apply the specified changes. After the changes are applied, the issue transitions automatically to the specified value.

Literals

The workflow programming language uses the following keywords to represent fixed values.

KeywordDescriptionExample
loggedInUserReferences the user who is currently logged in to YouTrack.issue.Assignee = loggedInUser
issueReferences the current issue.when issue.becomesReported()
nowReferences the current date and time in UTC.Due date = now
trueA Boolean literal value.var isHandled = true
falseA Boolean literal value.var hasChildren = false
nullA reference literal value.var number = null

Use the following formats to reference literal values for specific data types.

TypeFormatExample
dateWritten in the format year-month-day. Use the T operation to combine with a time value.
if (created < 2012-Dec-31 && !isResolved()) { tags.add(project.getUser("root").getSharedTag("obsolete?")); }
timeWritten in the format hour-minute-second. Use the T operation to combine with a date value.
daily at 08:00:00 [issue.resolved == null && issue.Priority == {Normal} && issue.created < now - 7 days]{ issue.Priority = {Major}; }
integerUnformatted numeric value.
var increaseNumber = Internal number + 1;
periodRepresented by an integer and the time period. The following period constants are supported:
  • millisecond(s)
  • second(s)
  • minute(s)
  • hour(s)
  • day(s)
  • week(s)
  • month(s)
  • year(s)
if (updated + 10 months < now) { project.leader.watchIssue(issue); }
stringSet in quotation marks
if (now > created + 3 days && Assignee == null) { message("Issue is three days old and is still unassigned!"); }

You can reference literal values for entities with the construction {entity: static_entity_name}.

ReferenceValue
{group: [group_name]}UserGroup literal.
{issue: [issueID]}Issue literal.
{project: [project_shortName]}Project literal.
{savedSearch: [savedSearchName]}SavedSearch literal.
{tag: [tagName]}IssueTag literal.
{user: [username]}User literal.
{[customFieldName]}CustomField literal.

The following examples show you how to insert static references to different entities.

CodeDescription
{group: QA Engineers}.notifyAllUsers("Test failed!", "Please look at the failed test " + getId())
References the UserGroup QA Engineers.
assert {issue: IDEA-99999}.Type == {Feature}: "It should be the cool feature about the new look and feel!";
References a single Issue IDEA-99999.
for each currency in {project: Business Trips}.valuesFor(Currency) { if (currency.name == {Dollar}) { assert currency.colorIndex == 17: "Dollar should be green!"; } }
References the Project Business Trips.
for each notMyIssue in loggedInUser.getIssues({savedSearch: Reported by me}, "for: -me") { notMyIssue.Assignee = loggedInUser; }
References the SavedSearch Reported by me.
rule Regression when State.becomes({Reopened}) { tags.add({tag: regression}); }
References the IssueTag regression.

Variables

Variables are declared with the keyword var, followed by the name of the variable. You can specify the initial value with the = sign, as with JavaScript.

var notInitializedVariable; var initializedVariable = "Hello";

The data type of the variable is inferred from the type that is specified in the initial expression. When a variable has no initial value, its value is inferred from its usages.

Once you have declared a variable, you can refer to it by its name.

notInitializedVar = "World!"; notInitializedVar = initializedVar + ", " + notInitializedVar;

In the following example, the variable user is used to set the assignee of an issue.

var user; if (issue.Assignee == null) { user = issue.project.leader; } else { user = issue.Assignee; }

When you use the createNewIssue method, an issue is created with the default (or empty) values for each field as configured for the project. To create an issue with specific values for fields, use variable declarations.

The following sample shows how to create an issue in the project with the ID RM, specify values for custom fields, and add a depends on link for the current issue to the issue that is created by the workflow.

var i = loggedInUser.createNewIssue("RM"); i.Assignee = Marketing; i.Due Date = Due Date - 1 month; i.summary = "Write text for mailing list"; i.Version = Version; i.Product = Product; depends on.add(i);

State-machine Declarations

State-machine rules use a pre-defined set of declarations. These declarations identify the field that is managed by the state-machine rule and values that are assigned to each transition.

DeclarationDescription
for fieldIdentifies the field that is managed by the state-machine rule.
initial stateSets the value that is assigned to new issues for the specified field.
stateSpecifies a value in the set of values for the custom field. Allowed transitions for the specified value are defined in the block statements that follow the declaration.
transit toSpecifies the value that is set for the specified field. This declaration is used in an on statement.

Comments

You can use comments to add notes to your workflow rules. This can help others understand what a rule does and how it can be implemented. You can also use comments to disable specific lines of code.

To insert a comment, use //. All of the text that follows on the same line is commented out. For example:

for each subtask in parent.parent for { //We can't use subtask.isResolved() here, as this method relies on issue.resolved //property, which is updated after workflow rules are executed. if (!subtask.State.isResolved) { allSubtasksResolved = false; break; } }
Last modified: 18 April 2017