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 Subtasks 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:
const entities = require('@jetbrains/youtrack-scripting-api/entities');
const workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: 'Copy subsystem from parent task when issue is linked as a subtask',
guard: (ctx) => {
return ctx.issue.links['parent for'].added.isNotEmpty() &&
ctx.issue.fields.Subsystem;
},
action: (ctx) => {
const issue = ctx.issue;
const 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) {
const 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 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:
const entities = require('@jetbrains/youtrack-scripting-api/entities');
const workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: 'Fix parent when all subtasks are resolved',
guard: (ctx) => {
return ctx.issue.isReported && ctx.issue.becomesResolved;
},
action: (ctx) => {
const processParent = function (issue) {
if (issue.links['subtask of'].isEmpty()) {
return;
}
const parent = issue.links['subtask of'].first();
if (parent && parent.project && !parent.project.isArchived &&
parent.isReported && !parent.isResolved) {
const unresolvedSubtask = parent.links['parent for'].find(function (subtask) {
return subtask.isReported && !subtask.fields.State.isResolved;
});
if (!unresolvedSubtask) {
const field = parent.project.findFieldByName(ctx.State.name);
if (field) {
const 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;
}
}
}
}
};
let 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 Yes to this field, this means that the entire parent issue is documented.