Developer Portal for YouTrack and Hub Help

Time Management

This workflow defines state transitions and notifications based on the amount of time an issue spends in a specific state.

Name

@jetbrains/youtrack-workflow-time-management

Auto-attached

no

Modules

Define transitions for "State" field with predefined time constraints (state-machine rule)

Use Case

This workflow was originally taken from a submitted request (JT-6331).

The user who submitted this issue wanted to track issues reported by customers, prospects and team members and make sure issues are resolved within a specific time frame.

When a customer reports an issue:

  • The support engineers have one hour to acknowledge the issue.

  • The support engineers then have four hours to reproduce the case or to engage in a discussion to reproduce it:

    • If the issue is not reproduced within a day, then the support manager is involved and the sales department is notified.

    • After three days, the sales department organizes a customer visit to verify the issue on-site.

  • If the issue is classified as a bug, the issue is assigned to the R&D department.

Modules

This module contains a state-machine rule that defines the state transitions for issues in the project and determines the amount of time an issue can spend in each state.

Define transitions for "State" field with predefined time constraints

  1. The initial state is Submitted.

  2. When the issue enters the Submitted state, the Subsystem field is set to Support. The support engineer is set as the Assignee.

  3. From the Submitted state, the issue can transition to one of the following states:

    • If the state is unchanged after one hour, the state is automatically set to Overdue.

    • On event (action) reproducing, the state is set to Open.

    • On event (action) incomplete, the state is set to Incomplete.

  4. When the state is set to Overdue, a notification is sent to the Assignee (if the issue is assigned), subsystem owner (if the owner of the Support subsystem is defined), or the project owner (if none of the previous conditions are true).

  5. From the Overdue state, the issue can transition to one of the following states:

    • On event (action) reproducing the state is set to Open.

    • On event (action) incomplete the state is set to Incomplete.

  6. From the Open state, the issue can transition to one of the following states:

    • If the state is unchanged after four hours, the state is automatically set to Wait for reproduce.

    • On event (action) approved the state is set to Approved.

    • On event (action) incomplete the state is set to Incomplete.

    • On event (action) can't reproduce the state is set to Can't Reproduce.

  7. From the Wait for reproduce state, the issue can transition to one of the following states:

    • If the state is unchanged after one day, notification is sent to the owner of the Support subsystem (if defined) or the project owner.

    • If the state is unchanged after three days, a separate notification is sent to the owner of the Support subsystem (if defined) or the project owner.

    • On event (action) approved the state is set to Approved.

    • On event (action) incomplete the state is set to Incomplete.

    • On event (action) can't reproduce the state is set to Can't Reproduce.

  8. When the state is set to Approved, the rule verifies that the Assignee is also set.

  9. From the Approved state, the issue can transition to one of the following states:

    • On event (action) fixed the state is set to Fixed state.

    • On event (action) obsolete the state is set set (should transit) to Obsolete state.

  10. From the Fixed state,the issue can transition to one of the following states:

    • On event (action) verify, the state is set to Verified state.

    • On event (action) reopen, the state is set to Open state.

  11. From Can't Reproduce, Incomplete, Obsolete and Verified states, the issue can transition to the Open state upon action reopen.

const entities = require('@jetbrains/youtrack-scripting-api/entities'); const workflow = require('@jetbrains/youtrack-scripting-api/workflow'); const findResponsibleAndNotify = function (issue, title, body) { let user; if ((issue.fields.Subsystem || {}).owner) { user = issue.fields.Subsystem.owner; } else { user = issue.project.leader; } user.notify(title, body); }; const ONE_HOUR = 1000 * 60 * 60; const ONE_DAY = ONE_HOUR * 24; exports.rule = entities.Issue.stateMachine({ title: 'Define transitions for "State" field with predefined time constraints', fieldName: 'State', states: { Submitted: { initial: true, onEnter: (ctx) => { ctx.issue.fields.Subsystem = ctx.Subsystem.Support; }, onExit: (ctx) => { ctx.issue.fields.required(ctx.Assignee, workflow.i18n('Responsible support engineer is required!')); }, transitions: { reproducing: { targetState: 'Open' }, incomplete: { targetState: 'Incomplete' }, overdue: { targetState: 'Overdue', after: ONE_HOUR } } }, Overdue: { onEnter: (ctx) => { const issue = ctx.issue; let user; if (issue.fields.Assignee) { user = issue.fields.Assignee; } else if ((issue.fields.Subsystem || {}).owner) { user = issue.fields.Subsystem.owner; } else { user = issue.project.leader; } user.notify(workflow.i18n('Acknowledgement needed'), workflow.i18n('Issue {0} is waiting for Acknowledgement.', issue.id)); }, transitions: { incomplete: { targetState: 'Incomplete' }, reproducing: { targetState: 'Open' } } }, Open: { transitions: { wait: { after: 4 * ONE_HOUR, targetState: 'Wait for reproduce' }, approved: { targetState: 'Approved' }, incomplete: { targetState: 'Incomplete' }, 'can\'t reproduce': { targetState: 'Can\'t Reproduce' } } }, 'Wait for reproduce': { transitions: { notify1: { after: ONE_DAY, targetState: 'Wait for reproduce', action: (ctx) => { findResponsibleAndNotify( ctx.issue, workflow.i18n('Issue is not reproduced in 1 day'), workflow.i18n('Issue {0} is still waiting for reproduction steps.', ctx.issue.id)); } }, notify4: { after: 4 * ONE_DAY, targetState: 'Wait for reproduce', action: (ctx) => { findResponsibleAndNotify( ctx.issue, workflow.i18n('Issue is not reproduced in 4 days'), workflow.i18n('Issue {0} is not reproduced, it\'s better to visit customer on his site.', ctx.issue.id)); } }, approved: { targetState: 'Approved' }, 'can\'t reproduce': { targetState: 'Can\'t Reproduce' }, incomplete: { targetState: 'Incomplete' } } }, 'Can\'t Reproduce': { transitions: { reopen: { targetState: 'Open' } } }, Incomplete: { transitions: { reopen: { targetState: 'Open' } } }, Approved: { onEnter: (ctx) => { ctx.issue.fields.required(ctx.Assignee); }, transitions: { fixed: { targetState: 'Fixed' }, obsolete: { targetState: 'Obsolete' } } }, Fixed: { transitions: { verify: { targetState: 'Verified' }, reopen: { targetState: 'Open' } } }, Obsolete: { transitions: { reopen: { targetState: 'Open' } } }, Verified: { transitions: { reopen: { targetState: 'Open' } } } }, requirements: { Subsystem: { type: entities.OwnedField.fieldType, Support: {} }, Assignee: { type: entities.User.fieldType } } });
Last modified: 7 October 2024