js/advanced-state-machine/state-machine.js (165 lines of code) (raw):
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var HOUR_IN_MS = 60 * 60 * 1000;
var DAY_IN_MS = 24 * HOUR_IN_MS;
exports.rule = entities.Issue.stateMachine({
title: 'Advanced state machine',
fieldName: 'State',
states: {
'Submitted': {
initial: true,
transitions: {
time_event: {
after: 3 * DAY_IN_MS,
action: function(ctx) {
var issue = ctx.issue;
var user = issue.fields.Assignee;
if (!user) {
user = issue.project.leader;
}
var subject = "[Youtrack, State reminder] Issue " + issue.id +
" is still Submitted: " + issue.summary;
var body = "Hi, " + user.fullName +
"! <br><br> Issue <a href=''" + issue.url + "'>" + issue.id +
"</a>" + " is still in Submitted state: " +
"<a href='" + issue.url + "'>" + issue.summary + "</a>" +
"<br> Please start working on it or specify a more accurate state.<br><br>" +
"<p style='color: gray;font-size: 12px;margin-top: 1em;border-top: 1px solid #D4D5D6'>" +
"Sincerely yours, YouTrack" + "</p>";
user.notify(subject, body);
},
targetState: 'Submitted'
},
fix: {targetState: 'Fixed'},
open: {targetState: 'Open'},
'in progress': {targetState: 'In Progress'},
discuss: {targetState: 'To be discussed'},
'can\'t reproduce': {targetState: 'Can\'t Reproduce'},
obsolete: {targetState: 'Obsolete'},
duplicate: {targetState: 'Duplicate'},
'as designed': {targetState: 'As designed'},
invalidate: {targetState: 'Invalid'}
}
},
'Open': {
transitions: {
fix: {targetState: 'Fixed'},
'in progress': {targetState: 'In Progress'},
discuss: {targetState: 'To be discussed'},
'can\'t reproduce': {targetState: 'Can\'t Reproduce'},
obsolete: {targetState: 'Obsolete'},
duplicate: {targetState: 'Duplicate'},
'as designed': {targetState: 'As designed'},
invalidate: {targetState: 'Invalid'},
wait: {targetState: 'Wait for Reply'}
}
},
'Obsolete': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'Duplicate': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'In Progress': {
transitions: {
fix: {targetState: 'Fixed'},
reopen: {targetState: 'Open'},
'can\'t reproduce': {targetState: 'Can\'t Reproduce'},
obsolete: {targetState: 'Obsolete'},
'as designed': {targetState: 'As designed'}
}
},
'To be discussed': {
transitions: {
'in progress': {targetState: 'In Progress'},
obsolete: {targetState: 'Obsolete'},
duplicate: {targetState: 'Duplicate'}
}
},
'Can\'t reproduce': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'As designed': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'Won\'t fix' : {
transitions: {
reopen: {targetState: 'Open'}
}
},
'Invalid': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'Incomplete': {
transitions: {
reopen: {targetState: 'Open'}
}
},
'Fixed': {
transitions: {
reopen: {targetState: 'Open'},
verify: {targetState: 'Verified'},
'can\'t verify': {targetState: 'Without verification'}
}
},
'Without verification': {
onEnter: function(ctx) {
ctx.issue.fields.VerifiedBy = ctx.currentUser;
},
transitions: {
reopen: {targetState: 'Open'}
}
},
'Verified': {
onEnter: function(ctx) {
ctx.issue.fields.required(ctx.VerifiedInBuild,
"Specify verified in build");
ctx.issue.fields.VerifiedBy = ctx.currentUser;
},
onExit: function(ctx) {
ctx.issue.fields.VerifiedInBuild = null;
},
transitions: {
reopen: {targetState: 'Open'}
}
},
'Wait for Reply': {
transitions: {
fix: {targetState: 'Fixed'},
open: {targetState: 'Open'},
'in progress': {targetState: 'In Progress'},
discuss: {targetState: 'To be discussed'},
'can\'t reproduce': {targetState: 'Can\'t Reproduce'},
obsolete: {targetState: 'Obsolete'},
duplicate: {targetState: 'Duplicate'},
'as designed': {targetState: 'As designed'},
invalidate: {targetState: 'Invalid'}
}
}
},
requirements: {
State: {
type: entities.State.fieldType
},
Assignee: {
type: entities.User.fieldType
},
VerifiedBy: {
type: entities.User.fieldType,
name: 'Verified by'
},
VerifiedInBuild: {
type: entities.Build.fieldType,
name: 'Verified in build'
}
}
});