Using the Workflow API
Use the information on this page to learn how to work with specific entities in the workflow API that are not described in other sections of the workflow reference.
Accessing Properties, Custom Fields, and Issue Links
Follow these guidelines to access issue properties, values in custom fields, and issue links.
Predefined issue fields like summary
, description
, and reporter
are all properties of the issue
entity.
var summary = issue.summary;
issue.summary = "Just a bug";
References to values in a custom field vary based on whether the field stores single or multiple values.
For fields that store single values, you can reference the value directly:
var state = issue.fields.State; issue.fields.State = ctx.State.Open; if (issue.fields.State.name === ctx.State.Fixed.name) { // Do stuff }
For fields that store multiple values, the values are stored as a set. The operations that are available for sets are described in more detail in the next section.
var versions = issue.fields["Fix versions"]; versions.forEach(function(v) { subtask.fields["Fix versions"].add(v); });
If you set the alias
property for a custom field in the requirements
statement, you can use this alias to access values for the field as well. For example, if the alias for the Fix versions field is set to FV
:
issue.fields.FV.forEach(function(v) {
// Do stuff
});
Issue link types are accessed by their inward or outward name. For example, relates to
or parent for
.Issue links are always treated as a set.
var parent = issue.links["subtask of"].first();
parent.links["parent for"].add(issue);
Note that custom fields and issue link types that contain spaces or other non-alphabetic characters must be set in quotation marks and brackets.
Working with Set Objects
There are several groups of operations you can do with multiple values (returned as Set<value type>):
Access them directly (
first()
,last()
,get(index)
) or by iterator (entries()
,values()
).Traverse over all values in Set with
forEach(visitor)
.Look for values with
find(predicate)
and check if a value is in Set withhas(value)
.Check size with
isEmpty()
,isNotEmpty()
andsize
property.Modify content with
add(element)
,remove(element)
andclear()
.Get the current changes for a Set object with the
added
,removed
andisChanged
properties.
For a detailed description of this object, see Set.
Calling Methods
// Call entity method:
var stateCF = issue.project.findFieldByName('State');
// Call static method:
var p = entities.Project.findByKey('INT');
// Call issue constructor:
var newIssue = new entities.Issue(ctx.currentUser, issue.project, "Subtask");
Finding Specific Entities
There are two ways to find a specific entity, like an issue or a user, and use it in a workflow script:
Add it in the requirements and reference it in the context. Use this approach as often as you can, as it is the most reliable. If the specified entity is not found in your database, the script is not executed.
If the first option is not applicable for whatever reason, use the
findBy*
andfind*By*
methods from the workflow API:
Use findBy*
methods to find a single occurrence of a specific entity:
var issue = entities.Issue.findById('MP-23'); // an entities.Issue or null
var projectByName = entities.Project.findByName('Music Production'); // an entities.Project or null
var projectByKey = entities.Project.findByKey('MP'); // an entities.Project or null
var user = entities.User.findByLogin('jane.smith'); // an entities.User or null
var userGroup = entities.UserGroup.findByName('MP team'); // an entities.UserGroup or null
var agiles = entities.Agile.findByName('MP Scrum'); // a Set of entities.Agile
var tags = entities.IssueTag.findByName('production'); // a Set od entities.IssueTag
var queries = entities.SavedQuery.findByName('MP Backlog'); // a Set of entities.SavedQuery
Use find*By*
methods to find child entities:
var sprint = agiles.first().findSprintByName('Sprint 23'); // an entities.Sprint or null
var priorityField = projectByKey.findFieldByName('Priority'); // an entities.ProjectCustomField or null
var major = field.findValueByName('Major'); // an entities.Field or null
var critical = field.findValueByOrdinal(1); // an entities.Field or null
var assigneeField = projectByKey.findFieldByName('Assignee');
var jane = assigneeField.findValueByLogin('jane.smith'); // an entities.User or null
var groupField = projectByKey.findFieldByName('Requestors');
var newBand = groupField.findValueByName('New Band'); // an entities.UserGroup or null
Finding Multiple Issues
Sometimes you might want to find a set of issues that match certain criteria and process them in the scope of a single rule. For example, you can compile a list of issues and sent it as an email message. In these situations, the search API can help. Here's a simple example:
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var search = require('@jetbrains/youtrack-scripting-api/search');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: 'Do not allow developers to have more than 1 issue in progress per project',
action: function(ctx) {
var issue = ctx.issue;
if (issue.isReported &&
(issue.fields.becomes(ctx.State, ctx.State['In Progress']) ||
issue.fields.isChanged(ctx.Assignee)) &&
(issue.fields.Assignee || {}).login === ctx.currentUser.login) {
// First, we build a search query that checks the project that the issue belongs to and returns all of the issues
// that are assigned to current user except for this issue.
var query = 'for: me State: {In Progress} issue id: -' + issue.id;
var inProgress = search.search(issue.project, query, ctx.currentUser);
// If any issues are found, we get the first one and warn the user.
if (inProgress.isNotEmpty()) {
var otherIssue = inProgress.first();
var message = 'Dear ' + ctx.currentUser.login + ', please close <a href="' +
otherIssue.url + '">' + otherIssue.id + '</a> first!';
workflow.check(false, message);
}
}
},
requirements: {
State: {
type: entities.State.fieldType,
'In Progress': {}
},
Assignee: {
type: entities.User.fieldType
}
}
});