Propagate Values Between Issues
A common requirement for issue tracking is to update the values in an issue based on changes that are applied to a related issue. In YouTrack, this use case is supported with workflows.
The next two cases demonstrate how to update issues in response to changes in other issues. These issues are linked with a parent-subtask relationship. However, you can apply this approach to issues with other link types, depending on your process.
Update Subtaks When Changes are Applied to the Parent Issue
The first direction is to apply updates with a top-down approach: when updates are applied to a parent issue, the subtasks are updated accordingly. We call this behavior inheritance and have several default workflows in YouTrack that implement this behavior for various fields, like Subtask Inherit Assignee, Subtask Inherit Fix Versions, and Subtask Inherit Subsystem. Let’s take a look at the corresponding rule for the Subsystem field:
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: workflow.i18n('Copy subsystem from parent task when issue is linked as a subtask'),
guard: function(ctx) {
return ctx.issue.links['parent for'].added.isNotEmpty() &&
ctx.issue.fields.Subsystem;
},
action: function(ctx) {
var issue = ctx.issue;
var safeSetSubsystem = function(subtask) {
if (subtask.project && !subtask.project.isArchived) {
if (subtask.project.key === issue.project.key ||
subtask.project.findFieldByName(ctx.Subsystem.name)) {
if (!subtask.fields.Subsystem) {
var value = subtask.project.findFieldByName(ctx.Subsystem.name)
.findValueByName(issue.fields.Subsystem.name);
if (value) {
subtask.fields.Subsystem = value;
}
}
}
}
};
issue.links['parent for'].added.forEach(safeSetSubsystem);
},
requirements: {
Subsystem: {
type: entities.EnumField.fieldType
},
SubtaskOf: {
type: entities.IssueLinkPrototype,
name: 'Subtask',
outward: 'parent for',
inward: 'subtask of'
}
}
});
You may notice that this rule is pretty verbose. This verbosity guarantees that the rule won't fail with an error when one of the subtasks belongs to a project that doesn't use a Subsystem field. We recommend that you follow this approach every time, as the rule can potentially refer to issues in projects other than the project to which this rule is attached.
Update Parent Issues When Changes are Applied to Subtasks
The second direction is from the bottom up. This approach is used when subtasks represent the steps for completing a larger task. When all of the subtasks reach a specific state, this means that the parent issue has reached this state as well. The most basic example is to close the parent issue as fixed when all subtasks are fixed. This rule is one of the modules in the default Subtasks workflow:
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: workflow.i18n('Fix parent when all subtasks are resolved'),
guard: function(ctx) {
return ctx.issue.isReported && ctx.issue.becomesResolved;
},
action: function(ctx) {
var processParent = function(issue) {
if (issue.links['subtask of'].isEmpty()) {
return;
}
var parent = issue.links['subtask of'].first();
if (parent && parent.project && !parent.project.isArchived &&
parent.isReported && !parent.isResolved) {
var unresolvedSubtask = parent.links['parent for'].find(function(subtask) {
return subtask.isReported && !subtask.fields.State.isResolved;
});
if (!unresolvedSubtask) {
var field = parent.project.findFieldByName(ctx.State.name);
if (field) {
var value = field.findValueByName(ctx.State.Fixed.name);
if (value) {
parent.State = value;
workflow.message(workflow.i18n('Automatically set {0} as Done', parent.id));
return parent;
}
}
}
}
};
var issue = ctx.issue;
while (issue) {
issue = processParent(issue);
}
},
requirements: {
State: {
type: entities.State.fieldType,
Fixed: {}
}
}
});
Depending on your process, this ‘reaching-the-target-state’ condition can be very different. For example, you can have a field Documentation provided with the values No(default) and Yes When each subtask is assigned Yesto this field, this means that the entire parent issue is documented.