YouTrack Server 2023.3 Help

Generate Issues Automatically

YouTrack provides a few basic options for issue generation.

  • You can generate an issue template URL. This speeds up the process somewhat, but you need to define separate URLs for different issue types and it’s still a manual operation.

  • You can use the Clone Issue action in the issue toolbar.

If you need to create a standard set of issues on a regular basis, consider using workflows to generate these issues automatically.

Generate Subtasks When a Parent Issue is Reported

Imagine that you’re working with a development team that releases updates to a software product on a regular basis. Apart from implementing new features and fixing bugs, each release requires a standard set of tasks. For example:

  • Distribute an updated version of the product.

  • Update the documentation.

  • Update the What's new page on the product website.

  • Prepare and publish an article on the company blog.

  • Send a newsletter to customers.

  • Send a newsletter to resellers.

To save you and your colleagues a lot of time, write a workflow that generates a list of subtasks every time a Release issue is created.

You need some criteria to distinguish release issues from other issues for your product. Otherwise, you end up generating subtasks for the wrong issues. There are a number of conditions you can set up, like using a separate project for release issues or adding a specific tag. In this example, we add Release to the set of values for the Type field and generate subtasks only when a new issue with this type is created. The workflow rule looks like this:

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.onChange({ title: 'Release management', guard: (ctx) => { const issue = ctx.issue; return issue.becomesReported && issue.fields.Type.name === ctx.Type.Release.name; }, action: (ctx) => { const issue = ctx.issue; const createIssue = function (name, subsystem) { const newIssue = new entities.Issue(ctx.currentUser, issue.project, name + ' for ' + issue.summary); newIssue.fields.Subsystem = subsystem; newIssue.fields.Type = ctx.Type.Task; newIssue.links['subtask of'].add(issue); }; createIssue('Update distribution', ctx.Subsystem.Distribution); createIssue('Update documentation', ctx.Subsystem.Documentation); createIssue('Update "What\'s new"', ctx.Subsystem.Website); createIssue('Blog post', ctx.Subsystem.Blog); createIssue('Newsletter for customers', ctx.Subsystem.Newsletters); createIssue('Newsletter for resellers', ctx.Subsystem.Newsletters); }, requirements: { Type: { type: entities.EnumField.fieldType, Release: {}, Task: {} }, Subsystem: { type: entities.OwnedField.fieldType, Distribution: {}, Documentation: {}, Website: {}, Blog: {}, Newsletters: {} } } });

Generate Subtasks When a Parent Issue is Updated

This case is similar to the previous one from a technical point of view but has a slightly different application.

Let’s look at the process for an operational team that organizes business trips to conferences and events for company employees. Line managers create issues in a special project. The project uses a multi-value Travelers field to store the names of the employees who participate in the event. The operational team prepares travel documents for each employee separately, so they want to have one issue per person.

You can support this case just as we did in the previous scenario by using the value for the Type field as the guard condition. Whenever a line manager submits an issue with multiple travelers, the operational team sets the type to Group Trip. This triggers a workflow that generates a subtask for each employee in the Travelers field and sets the type for each subtask to Individual Trip. You can support this use case by making minor modifications to the previous example.

However, sometimes employees decide that they want to go to the conference after the Group Trip issue is created. For this case, you need an additional rule that creates a subtask for new travelers on the fly:

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.onChange({ title: 'Create a subtask for each new traveler', guard: (ctx) => { const fs = ctx.issue.fields; return ctx.issue.isReported && fs.Type && fs.Type.name === ctx.Type.GroupTrip.name && fs.Travelers.added.isNotEmpty(); }, action: (ctx) => { const issue = ctx.issue; const createIssue = function (traveler) { const newIssue = new entities.Issue(ctx.currentUser, issue.project, traveler.fullName + ' at ' + issue.fields.Destination); newIssue.fields.Type = ctx.Type.IndTrip; newIssue.links['subtask of'].add(issue); }; issue.fields.Travelers.added.forEach(createIssue); }, requirements: { Destination: { type: entities.Field.stringType }, Type: { type: entities.EnumField.fieldType, GroupTrip: { name: 'Group Trip' }, IndTrip: { name: 'Individual Trip' } }, Travelers: { type: entities.User.fieldType, multi: true } } });

Generate Issues on Demand

There are several situations where you want to generate issues, but you can’t use a combination of field values as the initial condition. Here, the initial condition is inside the mind of the YouTrack user.

The most obvious example is the Clone Issue workflow. This workflow lets you make a copy of an existing request whenever you need it. This workflow uses an action rule. This type of rule is triggered by a user-defined command, either by selecting this action from the Command Dialog menu or by executing this command in the Apply Command dialog.

Going back to the previous example, let’s say that you want to provide employees with some swag to give to partners or hand out at the conference booth. In this case, you can write an action rule that generates a subtask for the group trip. The workflow takes the value from the Destination field in the parent task and sets the summary for the subtask to Prepare swag for "Destination":

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.action({ title: 'Create a swag subtask', command: 'swag-subtask', guard: (ctx) => { return ctx.issue.isReported; }, action: (ctx) => { const issue = ctx.issue; const newIssue = new entities.Issue(ctx.currentUser, issue.project, 'Prepare swag for ' + issue.fields.Destination); newIssue.fields.Type = ctx.Type.Swag; newIssue.links['subtask of'].add(issue); }, requirements: { Destination: { type: entities.Field.stringType }, Type: { type: entities.EnumField.fieldType, Swag: {} } } });

Generate Issues on a Schedule

So far we’ve shown you several ways to generate issues in response to human actions. However, there are many situations where you don’t even need a human to do the grunt work.

Consider the requirements for a team of developer advocates. One of the numerous responsibilities of this team is to prepare a monthly internal newsletter. The task is the same every month: same concept, same deadline, same assignee. Instead of creating this issue manually, set up a schedule to create it automatically:

const entities = require('@jetbrains/youtrack-scripting-api/entities'); const MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; const DAY_IN_MS = 24 * 60 * 60 * 1000; exports.rule = entities.Issue.onSchedule({ title: 'Internal newsletter', search: '#DA-1', // anchor issue; it is required to ensure that // this rule is executed exactly once according to schedule cron: '0 0 19 15 1/1 ? *', // on the 15th day of every month at 19:00 action: (ctx) => { const date = new Date(Date.now() + 31 * DAY_IN_MS); date.setDate(1); const month = MONTHS[date.getMonth()]; const year = date.getFullYear(); const newIssue = new entities.Issue(ctx.currentUser, ctx.issue.project, month + ' ' + year + ' Internal Newsletter'); newIssue.fields.Assignee = ctx.author; newIssue.fields.Subsystem = ctx.Subsystem.Newsletters; newIssue.fields.DD = date.getTime(); }, requirements: { Assignee: { type: entities.User.fieldType }, Subsystem: { type: entities.OwnedField.fieldType, Newsletters: {} }, DD: { type: entities.Field.dateType, name: 'Due Date' }, author: { type: entities.User, login: 'admin' }, da: { type: entities.Issue, id: 'DA-1' } } });
Last modified: 22 March 2024