Hi all,
This post relates to one of my other posts (https://community.atlassian.com/t5/Marketplace-Apps-Integrations/Scripted-fields-for-time-in-statuses/qaq-p/1624738).
This is a question merely out of curiosity. I'm pretty sure it isn't possible...but I'm wondering if it's possible to take the result values of scripted fields made in scriptrunner, and add them together, or subtract one result value from the other.
To elaborate further, I have three scripted fields: one that calculates time spent in To Do-category statuses (like 'To Do', 'Open', 'New', 'Selected for Dev', etc..), one that calculates time spent in In Progress-category statuses ('In Progress', 'Ready for Work', 'In Review', 'With Reporter', etc...), and one that calcualtes time in statuses that indicate that progress has been halted (namely. 'On Hold', 'Blocked', and 'Stalled').
Here are the scripts for each scripted field...
Time in TODO
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.history.ChangeItemBean;
import com.atlassian.jira.issue.Issue;
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def statusName = "New"
def createdDateDiff = System.currentTimeMillis() - issue.getCreated().getTime()
List<Long> rt = [0L]
// Adding time from when issue is created to the first time the status changes
rt << createdDateDiff
def changeItems = changeHistoryManager.getChangeItemsForField(issue, "status")
changeItems.reverse().each {ChangeItemBean item -> item.fromString
// Get the time passed since status change
def timeDiff = System.currentTimeMillis() - item.created.getTime()
// If the status change is from 'New', subtract the time passed since then
if (item.fromString == statusName) {
rt << -timeDiff
}
// If the status change goes to our status, we want to add the time passed since then
if (item.toString == statusName){
rt << timeDiff
}
}
def intakeReview = "Intake Review"
def rt2 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == intakeReview && item.fromString != item.toString) {
rt2 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == intakeReview) {
rt2 << timeDiff
}
}
def backlogged = "Backlogged"
def rt3 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == backlogged && item.fromString != item.toString) {
rt3 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == backlogged) {
rt3 << timeDiff
}
}
List<Long> rtTotal = new ArrayList<Long>()
rtTotal.addAll(rt)
rtTotal.addAll(rt2)
rtTotal.addAll(rt3)
def total = (rtTotal.sum() as Long) / 1000
return Math.round(total) ?: 0
Time in IN PROGRESS
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.history.ChangeItemBean;
import com.atlassian.jira.issue.Issue;
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def changeItems = changeHistoryManager.getChangeItemsForField(issue, "status")
def inProgress = "In Progress"
def rt = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == inProgress && item.fromString != item.toString) {
rt << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == inProgress) {
rt << timeDiff
}
}
def rdyForWork = "Ready for Work"
def rt2 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == rdyForWork && item.fromString != item.toString) {
rt2 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == rdyForWork) {
rt2 << timeDiff
}
}
def inAnalysis = "In Analysis"
def rt3 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == inAnalysis && item.fromString != item.toString) {
rt3 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == inAnalysis) {
rt3 << timeDiff
}
}
def inReview = "In Review"
def rt4 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == inReview && item.fromString != item.toString) {
rt4 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == inReview) {
rt4 << timeDiff
}
}
def codeReview = "Code Review"
def rt5 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == codeReview && item.fromString != item.toString) {
rt5 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == codeReview) {
rt5 << timeDiff
}
}
def pending = "Pending"
def rt6 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == pending && item.fromString != item.toString) {
rt6 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == pending) {
rt6 << timeDiff
}
}
def withReporter = "With Reporter"
def rt7 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == withReporter && item.fromString != item.toString) {
rt7 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == withReporter) {
rt7 << timeDiff
}
}
def withTeam = "With Team"
def rt8 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == withTeam && item.fromString != item.toString) {
rt8 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == withTeam) {
rt8 << timeDiff
}
}
def rdyForAcceptance = "Ready for Acceptance"
def rt9 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == rdyForAcceptance && item.fromString != item.toString) {
rt9 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == rdyForAcceptance) {
rt9 << timeDiff
}
}
def overdue = "Overdue"
def rt10 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == overdue && item.fromString != item.toString) {
rt10 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == overdue) {
rt10 << timeDiff
}
}
List<Long> rtTotal = new ArrayList<Long>()
rtTotal.addAll(rt)
rtTotal.addAll(rt2)
rtTotal.addAll(rt3)
rtTotal.addAll(rt4)
rtTotal.addAll(rt5)
rtTotal.addAll(rt6)
rtTotal.addAll(rt7)
rtTotal.addAll(rt8)
rtTotal.addAll(rt9)
rtTotal.addAll(rt10)
def total = (rtTotal.sum() as Long) / 1000
return Math.round(total) ?: 0
Time PROGRESS HALTED
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.history.ChangeItemBean;
import com.atlassian.jira.issue.Issue;
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def changeItems = changeHistoryManager.getChangeItemsForField(issue, "status")
def onHold = "On Hold"
def rt = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == onHold && item.fromString != item.toString) {
rt << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == onHold) {
rt << timeDiff
}
}
def blocked = "Blocked"
def rt2 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == blocked && item.fromString != item.toString) {
rt2 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == blocked) {
rt2 << timeDiff
}
}
def stalled = "Stalled"
def rt3 = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status")
changeItems.reverse().each {ChangeItemBean item ->
def timeDiff = System.currentTimeMillis() - item.created.time
// Subtract time if the "from" status is equal to the status to be checked and from and to statuses are different.
// This allows to count the time the issue is in the state for the first time
if (item.fromString == stalled && item.fromString != item.toString) {
rt3 << -timeDiff
}
// Add time if the "to" status is equal to the status to be checked
if (item.toString == stalled) {
rt3 << timeDiff
}
}
List<Long> rtTotal = new ArrayList<Long>()
rtTotal.addAll(rt)
rtTotal.addAll(rt2)
rtTotal.addAll(rt3)
def total = (rtTotal.sum() as Long) / 1000
return Math.round(total) ?: 0
The scripted fields all work as intended...although I'd preferably like for them to look into the scope of the workflow in context of the issue in concern and add all workflow statuses within respective issue categories, rather than me just relying on a set list of statuses. If anyone had any suggestions/tips on improving the scripts to follow this logic, that'd be great too.
But more importantly, I want to take the (Duration) results of each of these scripted fields and add them together. Is that at all possible?