Jira Software Version: 8.22.6
Adaptavist Script Runner Version: 6.41.0
I'm trying to update the Time Tracking fields on a Story, when the issues and sub-tasks beneath the story submit their work logs. I'm using a listener that fires when a work log is submitted.
I have already checked the variables and verified that the time tracking variables are accurate up to the point of the updateValue() method at the end of this code. The code is compiling and firing without any errors. The listener log says it's running fine.
However, when I add a work logged record to an issue or sub-task, the corresponding Story's Time Tracking fields are not updating at all. I'm adding "Dummy" variables to over-right the Story's current numbers, in order to verify that the code is actually working.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import java.text.SimpleDateFormat
Issue issue = event.issue
String issueTypeName = event.issue.getIssueType().name
// Load Components
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def issueManager = ComponentAccessor.getIssueManager()
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def changeHolder = new DefaultIssueChangeHolder()
def actionName = issue.getStatus().name
// Create Variables
def cfOriginalHourEstimate = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Original Hour Estimate'}
def cfRemainingHourEstimate = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Remaining Hour Estimate'}
def cfLoggedHours = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Logged Hours'}
def cfTotalHours = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Total Hours'}
def cfStoryLink = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Story Link'}
String cvStoryLink = issue.getCustomFieldValue(cfStoryLink)
//ASSIGN DUMMY VARIABLES
def originalHourEstimateDummy = 10 as double
def remainingHourEstimateDummy = 6 as double
def loggedHoursDummy = 4 as double
def totalHoursDummy = 10 as double
// Get Custom Fields
cfOriginalHourEstimate = customFieldManager.getCustomFieldObjectsByName('Original Hour Estimate')[0]
cfRemainingHourEstimate = customFieldManager.getCustomFieldObjectsByName('Remaining Hour Estimate')[0]
cfLoggedHours = customFieldManager.getCustomFieldObjectsByName('Logged Hours')[0]
cfTotalHours = customFieldManager.getCustomFieldObjectsByName('Total Hours')[0]
// These functions ARE running, without errors, but the desired effects aren't happening...
cfOriginalHourEstimate.updateValue(null, remoteIssue, new ModifiedValue(issue.getCustomFieldValue(cfOriginalHourEstimate), originalHourEstimateDummy), changeHolder)
cfRemainingHourEstimate.updateValue(null, remoteIssue, new ModifiedValue(issue.getCustomFieldValue(cfRemainingHourEstimate), remainingHourEstimateDummy), changeHolder)
cfLoggedHours.updateValue(null, remoteIssue, new ModifiedValue(issue.getCustomFieldValue(cfLoggedHours), loggedHoursDummy), changeHolder)
cfTotalHours.updateValue(null, remoteIssue, new ModifiedValue(issue.getCustomFieldValue(cfTotalHours), totalHoursDummy), changeHolder)
// Let's try triggering a re-index once the changes have been uploaded
boolean isIndex = ImportUtils.isIndexIssues()
ImportUtils.setIndexIssues(true)
IssueIndexingService IssueIndexingService = (IssueIndexingService) ComponentAccessor.getComponent(IssueIndexingService.class)
IssueIndexingService.reIndex(issue)
There are 2 interesting posts about a similar thing:
The second one hints towards IssueManager/update not working, and IssueService being the only one functional way of doing this.
The first one contains a solid snippet example from Peter-Dave Sheehan which you could use as a template and try this with IssueInputParameters and IssueService.
I'll copy paste his sample code:
import com.atlassian.jira.component.ComponentAccessor
def issueService = ComponentAccessor.issueService
def issueManager = ComponentAccessor.issueManager
def inputParameters = issueService.newIssueInputParameters()
def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def issue = issueManager.getIssueObject('JSP-1922')
inputParameters.originalEstimate =(Long)(2)
def validationResult = issueService.validateUpdate(user,issue.id,inputParameters)
issueService.update(user, validationResult)
When I was going through your code, I noticed you were referring to "remoteIssue" in CustomField#updateValue() methods, but I do not see where this "remoteIssue" is declared. In any case, with IssueService we don't need to ponder about it.
What I do have doubts about are this "Total Hours" and "Logged Hours". This doesn't sound related to Time Tracking.. are those number custom fields? Come to think of it I do not see any of those 4 fields as "custom fields" on my instance.
I do have doubts about trying to set "logged hours" if we are still talking about Time Tracking - because it consists and aggregates multiple worklogs, so I don't see that functioning as a "number" field to just set a value to. I reckon that to do anything about worklogs, it would need https://docs.atlassian.com/software/jira/docs/api/8.20.12/com/atlassian/jira/bc/issue/worklog/WorklogService.html
Yeah, the "remoteIssue" is a reference to the Story, while "issue" would be an issue / sub-task trigger that is linked to the Story. I'm trying to use a listener to gather all the time spent on a Story's corresponding issues / subtasks, and post that total on the Story's Time Spent.
I'm so close to getting this right!
"issueService.update(currentUser, validationResult)" is doing the trick to update a Story's "Original Estimate" and "Remainder", all that's left is making sure the current "Time Spent" values are also updating. Those ones are intricately tied to the Story's work orders and can't be altered directly.
I've got through the "WorklogService.html" file, which is great for interacting with work orders. I used it to delete the dummy work logs I'd created on my Story during testing. I assumed this would reset the story's "Time Spent" variable to "0", since there are no more work logs.
Here's where it gets weird. Despite my Story having 0 work logs (therefore, it should have a time spent of 0), it still says this story has 2 hours of Time Spent.
I've tried to directly update that value to 0 hours of Time Spent, but the change doesn't take place. Here's the code. It's running without errors, but the Time Spent value doesn't update:
inputParameters.timeSpent = (Long) 00.0
def validationResult = issueService.validateUpdate(currentUser,getStoryIssueId,inputParameters)
try {
issueService.update(currentUser, validationResult)
log.warn ("Success")
} catch(Exception e) {
log.warn("Exception: ${e}")
}
So, when I look at the "Time Tracking" graph for my Story, the "Estimated" and "Remaining" times have been successfully reset to 1 week.
The "Time Spent" row still shows 2 hours of work logged, despite all the work logs having been deleted.
Is there a way to tell the Story to re-calculate it's "Time Spent"? Or Modify the Time Spent value directly?
Once it can be accurately reset to 0 hours, I intend to create a new work log which will contain the sum of all the "time spent" values from all the corresponding issues / subtasks.
This is the code I used to delete the story's work logs. Did I miss a step that would have triggered the necessary re-calculation?
def storyWorkLogs = workLogManager.getByIssue(story_issue)
storyWorkLogs.each{
def worklogId = it.id
def newRemaining = 140400 as Long
try{
workLogManager.deleteWorklogsForIssue(story_issue)
} catch(Exception e) {
log.warn("Exception: ${e}")
}
}
What are your thoughts?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
According to the documentation here: https://docs.atlassian.com/software/jira/docs/api/8.22.6/com/atlassian/jira/issue/IssueInputParameters.html#setTimeSpent-java.lang.Long-
The IssueInputParameters class, has a method "setTimeSpent( Long TimeSpent )", which should successfully update the Story's "Time Spent" variable, but again, I run this code without errors but nothing changes.
// RESET TIME LOGGED
inputParameters.setTimeSpent(0)
def validationResult = issueService.validateUpdate(currentUser,getStoryIssueId,inputParameters)
try {
issueService.update(currentUser, validationResult)
log.warn ("Success")
} catch(Exception e) {
log.warn("Exception: ${e}")
}
I've been looking through the documentation for WorklogManager, here: https://docs.atlassian.com/software/jira/docs/api/8.22.6/com/atlassian/jira/issue/worklog/WorklogManager.html#deleteWorklogsForIssue-com.atlassian.jira.issue.Issue-
I see plenty for creating, editing and deleting worklogs, but nothing for telling the Story to re-calculate it's "Time Spent" variable, now that all the work logs have been deleted.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I figured it out. It was miss-communication with my boss. He was using a Gaant Chart to track work log totals separately, through custom fields. I was trying to track the work logs with Jira's native fields for that function.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've also added another line of code to implement the Issue Manager to trigger the update.
I'm still not seeing any changes to the targeted Story's Time Tracking Fields, despite the listener firing just fine and not flagging any errors at all.
issueManager.updateIssue(user, remoteIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Join us to learn how your team can stay fully engaged in meetings without worrying about writing everything down. Dive into Loom's newest feature, Loom AI for meetings, which automatically takes notes and tracks action items.
Register today!Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.