Capture time when a custom field in an issue is updated and no. of weekdays since it is last updated

Marija Ušakova March 29, 2018

Dear @Alexey Matveev as you always help me every time. Would you be able to look into my issue, Please. 

I want to capture time when a custom field in an issue is updated and no. of weekdays since it is last updated. It's returning null. 

I found this code in the community pages: it is not working for me. I need your advise.

import com.atlassian.jira.component.ComponentAccessor

def issueManager = ComponentAccessor.getIssueManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

def issue = issueManager.getIssueObject("PT-12867")
def previousTransitison = changeHistoryManager.getChangeItemsForField(issue, 'customFieldId=10013')
previousTransitison*.created.max(){}

 

Result is null.

3 answers

1 accepted

1 vote
Answer accepted
Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 29, 2018

Hello, @Marija Ušakova.

The answer of @Ivan Tovbin is a valid answer. I would like just to add, that your script did not work, because you passed 'customFieldId=10013' to the getChangeItemsForField method. You should pass the name of your custom field in the method.

Also the script of Ivan will return your the date difference with weekends, but I guess, you wanted to exclude weekdays. I would suggest you the following script:

import com.atlassian.jira.component.ComponentAccessor
import java.sql.Timestamp
import java.util.Calendar

Calendar endCal = Calendar.getInstance();
Calendar startCal = Calendar.getInstance();
def issueManager = ComponentAccessor.getIssueManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def issue = issueManager.getIssueObject("PT-12867")
def previousTransitison = changeHistoryManager.getChangeItemsForField(issue, 'yourCustomFieldName')
startCal.setTime(previousTransitison*.created.max())

int workDays = 0
while (startCal.getTimeInMillis() < endCal.getTimeInMillis()) {

startCal.add(Calendar.DAY_OF_MONTH, 1);
if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
++workDays;
}

} ;
log.error("n. of working days: " + workDays)

 

Marija Ušakova March 30, 2018

So may I ask, how to use this in jql query as there are many issues using this custom field and I should have mentioned earlier this problem like in the program we only pass the issue one at a time vs scan all issues. As always thank you.

Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 30, 2018

You should change your script to this one

import com.atlassian.jira.component.ComponentAccessor
import java.sql.Timestamp
import java.util.Calendar

Calendar endCal = Calendar.getInstance();
Calendar startCal = Calendar.getInstance();
def issueManager = ComponentAccessor.getIssueManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def issue = issueManager.getIssueObject("PT-12867")
def previousTransitison = changeHistoryManager.getChangeItemsForField(issue, 'yourCustomFieldName')
startCal.setTime(previousTransitison*.created.max())

int workDays = 0
while (startCal.getTimeInMillis() < endCal.getTimeInMillis()) {

startCal.add(Calendar.DAY_OF_MONTH, 1);
if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
++workDays;
}

} ;
return workDay

Then you should set Number searcher or Number range searcher for the custom field and then you can use the field in your JQL queries.

Marija Ušakova April 1, 2018

@Alexey Matveev My current issue with that setting is I do not have the custom field as a number searcher, but it is a text field and I wish to see the timestamp of it when it was last updated and put the difference in number or use now() in jql search and please do note that I don't know how to rewrite the code to search for all issues not just PT-12867. As always thank you very much.

Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 1, 2018

1. JQL result is always a list of issues. You can define custom fields, which you want to see in the list. You can not add any additional information. That is why if you want to show a timestamp, when a field was changed, then you need to add a scirpted custom field, which would show you the information.

2. If you want to filter issues, where a number of days passed since the last update, in JQL then you have 2 choices

- you can create a scripted custom field with the Number searcher and make it the Number type

- you can write your own JQL function, let s say (myFieldChangedWithin(Number numberOfDays)), which will return you all issues, changed within the number of Days.

In my opinion, the first method is prefferable. Because it is easy to write and you will not have performance problems.

The second method is difficult to write and prone to poor performance.

If you take the first method (create a scripted field), then your script will look like this.

import com.atlassian.jira.component.ComponentAccessor
import java.sql.Timestamp
import java.util.Calendar

Calendar endCal = Calendar.getInstance();
Calendar startCal = Calendar.getInstance();
def issueManager = ComponentAccessor.getIssueManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
def previousTransitison = changeHistoryManager.getChangeItemsForField(issue, 'yourCustomFieldName')
startCal.setTime(previousTransitison*.created.max())

int workDays = 0
while (startCal.getTimeInMillis() < endCal.getTimeInMillis()) {

startCal.add(Calendar.DAY_OF_MONTH, 1);
if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
++workDays;
}

} ;
return workDay

Suppose, you added a custom field called NDaysFromLastUpdate. Then you can write in JQL like this

NDaysFromLastUpdate = 2

It will mean, that you want to find all issues, where the number of days since last update equals 2.

Marija Ušakova April 2, 2018

Thank you @Alexey Matveev it worked. Can you help me with another question, I want to create mock user groups and users for testing out permissions. 

Something like this: 

import com.atlassian.jira.component.ComponentAccessor;
def mu = ComponentAccessor.getUserUtil()
def user = mu.getUserByName("test.user_ad1")
def group = mu.getGroupObject("jira-developers")
uu.addUserToGroup(group, user.getDirectoryUser())

.... I do need your input..

But i need to add groups as well to local jira group and also Active Directory. Many Thanks

Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 3, 2018

You want to create groups in a script or you want to add users to already created groups?

if you want to add users to local groups, then there will be no problems. If you want to add users to AD groups, then your user directory must be setup as Read/Write and the user, under which you connect to the AD in the user directory settings, must have permissions to add users to group in AD.

 

I had a look at your script. I guess you are on the right way. If something does not work, then let me know.

Marija Ušakova April 3, 2018

@Alexey Matveev I did succeed adding new users in the internal directory but, so now I need your help creating new 'group' to the internal directory.

 

Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 3, 2018

You can create a group like this

 

import com.atlassian.jira.component.ComponentAccessor

ComponentAccessor.getGroupManager().createGroup("group name")
Marija Ušakova April 3, 2018

That helps and works@Alexey Matveev Many many thanks.

0 votes
David L December 8, 2021

Here is another example using html to format the old strings from the new strings for a custom field. I've tested the timestamp of the custom field doesn't update if the overall Jira issue is updated

{code}


//define classes
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.changehistory.ChangeHistoryItem
import com.atlassian.jira.issue.history.ChangeItemBean

IssueManager issueManager = ComponentAccessor.getIssueManager();

// definitions
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager();
def changeItems = changeHistoryManager.getChangeItemsForField(issue, "<custom field name>);

// def userUtil = ComponentAccessor.getUserUtil(); // if you want to show the respective JiraUser object which executed the change

def last_change = changeItems.last();
def lastModifiedCF = last_change["field"];
def fromValue = last_change["fromString"];
def toValue = last_change["toString"];
def timeStamp = last_change["created"];

// HTML function to add bold and color text to categories: fromValue will be Bold Red, toValue will be Bold Green, Timestamp will be Bold Black

def String formatted = """
<server>
<p><strong>Modified Field:</strong> $lastModifiedCF</p>
<p><strong><span style="color: rgb(226, 80, 65);">From Value:</span></strong> $fromValue</p>
<p><strong><span style="color: rgb(65, 168, 95);">To Value:</span></strong> $toValue</p>
<p><strong>TimeStamp:&nbsp;</strong> $timeStamp</p>
</server>
"""
return formatted;
{code}
0 votes
Ivan Tovbin
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 29, 2018

Hi Marija,

Assuming you want this returned as a scripted field value, here's the code to do it:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.changehistory.ChangeHistoryManager
import java.sql.Timestamp

ChangeHistoryManager changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
List changes = changeHistoryManager.getChangeItemsForField(issue, "yourCustomFieldName")
Timestamp currentTime = new Timestamp(System.currentTimeMillis())
int daysSinceLastChange = currentTime - changes[changes.size()-1].getCreated()
return daysSinceLastChange

This'll return the number of days since your custom field last update.

Marija Ušakova March 30, 2018

Thank you very much and I needed this input. As I have additional question and I need some guidance for scanning all the issues and putting it in the jql query.

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events