How do you find issues when custom field changed in ScriptRunner Console?

Diana
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.
August 25, 2022

Since you can't use JQL operator "was" or "changed" for custom field, I'm resorting to ScriptRunner Console.

I have issue types Bug and Story that both uses a radio button custom field (let's say with options 1,2,3,4 etc). When a Bug or Story is created, it might have "Option 1" selected. But later on, the radio button custom field was changed to "Option 2". 

How do I pull issues that were once "Option 1" as well as all issues that are still "Option 1" on the Console? 

I have looked up these references, but we don't have easybi and would like not to resort to purchasing apps. https://community.atlassian.com/t5/Jira-questions/How-to-get-historical-values-from-custom-field-with-scriptrunner/qaq-p/1879270 

1 answer

1 accepted

0 votes
Answer accepted
Tim Chen August 26, 2022

Using issue.getCustomFieldValue for radio button IS Option 1

Using changeHistoryManager.getChangeItemsForField to retrieve updated histories of radio button in specific issue. 

def radio_field = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName(RADIO_FIELD_NAME)[0]

// radio button IS Option 1
Closure<Boolean> is_option_1 = {Issue i ->
i.getCustomFieldValue(radio_field).value == 'Option 1'
}

// radio button WAS Option 1
Closure<Boolean> was_option_1 = {Issue i ->
// retrieve histories of specific customfield in issue
def radio_field_histories = ComponentAccessor.changeHistoryManager.getChangeItemsForField(
i, radio_field.name
)

// histories were once changed from Option 1
radio_field_histories.any{ChangeItemBean changed_item ->
changed_item.fromString == 'Option 1'
}
}

// issue = looped Bug & Story issue
return is_option_1(issue) ?: was_option_1(issue)
Diana
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.
September 6, 2022

Hi @Tim Chen 

Sorry for late response. 

I'm getting a variable undeclared error under "changed_item" in the "changed_item.fromSting". My groovy language skills is subpar.

For the "return is_option_1(issue)" etc, how do I looped Bug and Story issue there?

Diana
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.
September 12, 2022

Hi @Tim Chen 

Just want to say I have figured out a simple method! Many thanks to Ravi Sagar's video:  https://www.ravisagar.in/videos/scriptrunner-retrieve-specific-field-change-history 

This works for me:

import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.ApplicationUser
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger("My Username Here")
log.setLevel(Level.DEBUG)

log.debug("Script started")

IssueManager im = ComponentAccessor.getIssueManager();
MutableIssue issue = im.getIssueObject("ABC-12345")

//to see all field changes
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
changeHistoryManager.getAllChangeItems(issue).each { it ->
log.debug(it.created.toString() + ": " + it.field + " - " + it.from + "->" +it.to)
}

//to specific a single field
changeHistoryManager.getChangeItemsForField(issue, "Custom Field Name Here").each { it ->
log.debug(it.created.toString() + ": " + it.field + " - " + it.fromString + "->" +it.toString)
}

 

The only downside is that I can only search 1 issue at a time. I'm pretty sure if I add more conditions to my liking, then I can achieve my end goal which is to find a way to use this script and insert a type of JQL query. Like "find all Bugs and Story issues in Project ABC and in Sprints 1, 2, 3"

But I wanted to share this so that others can use and maybe build on.

Tim Chen September 15, 2022

Hi, @Diana Gorv 

Sorry for late response.

You can use JQL in SR for searching all story and bug issues like below:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.jql.parser.JqlQueryParser

import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.Issue
import com.atlassian.query.Query

String jql_string = "issuetype in (Story, Bug)" // JQL search string
Query parsed_query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery(jql_string)
PagerFilter page_filter = new PagerFilter(100) // 100 means searching 100 satisfied issues
// PagerFilter page_filter = PagerFilter.unlimitedFilter // for searching all satisfied issues

ApplicationUser current_user = ComponentAccessor.jiraAuthenticationContext.loggedInUser

List<Issue> story_and_bug_issues = ComponentAccessor.getComponent(SearchService).search(
current_user, parsed_query, page_filter
).results

story_and_bug_issues.each{Issue i ->
// check the value of the radio field by combining with previous script :)
}

 

Hope it helps. :)

Diana
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.
September 15, 2022

Hi @Tim Chen 

Thank you for the jql parse code!

Is there a way I can make List<Issue> as some sort of MutableIssue?

Right now, I'm trying to achieve like this

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.jql.parser.JqlQueryParser

import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.Issue
import com.atlassian.query.Query

String jql_string = "issuetype in (Story, Bug) AND radiobutton IS NOT Empty" // JQL search string
Query parsed_query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery(jql_string)
PagerFilter page_filter = new PagerFilter(100) // 100 means searching 100 satisfied issues
// PagerFilter page_filter = PagerFilter.unlimitedFilter // for searching all satisfied issues

ApplicationUser current_user = ComponentAccessor.jiraAuthenticationContext.loggedInUser

List<Issue> story_and_bug_issues = ComponentAccessor.getComponent(SearchService).search(
current_user, parsed_query, page_filter
).results

//to specific a single field
changeHistoryManager.getChangeItemsForField(story_and_bug_issues, "Custom Field Name Here").each { it ->
log.debug(it.created.toString() + ": " + it.field + " - " + it.fromString + "->" +it.toString)
}

But I can't get a matching method while using a List<Issue> from the query.

Tim Chen September 15, 2022

The first argument of changeHistoryManager.getChangeItemsForField is a single Issue object. Therefore story_and_bug_issues is List<Issue> so it is not allowed. You should to use that method while looping story_and_bug_issues, like: 

story_and_bug_issues.each{Issue i ->
changeHistoryManager.getChangeItemsForField(i, "FIELD NAME").each{
// your log message
}
}

Besides, for changing Issue object to MutableIssue object, using IssueManager to retrieve the MutableIssue object, like

story_and_bug_issues.each{Issue i ->
MutableIssue mutable_issue = ComponentAccessor.issueManager.getIssueByKey(i.key)
}

And it is able to change List<Issue> to List<MutableIssue> like:

List<MutableIssue> mutable_issues = story_and_bug_issues.collect{Issue i ->
ComponentAccessor.issueManager.getIssueByKey(i.key)
}

Suggest an answer

Log in or Sign up to answer