I'm totally new to ScriptRunner and have been tasked to search through a project's issues' change history and find where a now-deleted old custom field was set and set the value to a brand new custom field. Can anyone help me on this?
Thanks!
The below code was tested on JIRA Server V8.20.8,
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
//Load needed Managers
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
//Load JQL Managers
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchService = ComponentAccessor.getComponent(SearchService)
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()
//Get your project issues based on with JQL
def query = jqlQueryParser.parseQuery("Your JQL Here ")
def results = searchService .search(user , query, PagerFilter.getUnlimitedFilter())
//Loop on Issues to set the value of the new custom field based on the old one value
results.getResults().each{item ->
def issue = issueManager.getIssueObject(item.key)
// Load the new custom field object of the current issue
def newCustomField = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Your New Custom Field Name'}
// Get the latest value of the old custom field of the current issue
def oldCustomFieldHisotry = changeHistoryManager.getChangeItemsForField(issue, "Your Old Custom field Name").sort{it.getCreated()}
def oldCustomFieldValue = oldCustomFieldHisotry.size()>0?oldCustomFieldHisotry.last().to:null
//Set the new custom field with the old custom field value
if(oldCustomFieldValue != null)
{
newCustomField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(newCustomField), oldCustomFieldValue),new DefaultIssueChangeHolder())
}
}
Did it do *nothing*, or did it throw an error?
Here's a version of the script with a lot of logging thrown in. Can you tell us what the log says?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Ken. i see it shows error (null) for the old field value. I wonder why, since the old field is not null (the value in this field is text + SQL query which is bit long)
WARN [runner.ScriptBindingsManager]: null
However if I check server log results, I see the entire value of the old field.
[c.o.scriptrunner.runner.ScriptBindingsManager] [com.atlassian.jira.issue.history.ChangeItemBean@29a6f8d8[fieldType=custom,field=NAME,from=<null>,fromString=<null>,to=<null>,toString=TEXTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I was able to copy it using this for one ticket:
def oldCustomFieldHisotry = changeHistoryManager.getChangeItemsForField(issue, "Custom Field").sort{it.getCreated()}
def oldCustomFieldValue = oldCustomFieldHisotry?.last().toString
//Set the new custom field with the old custom field value
if(oldCustomFieldValue != null)
{
newCustomField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(newCustomField), oldCustomFieldValue),new DefaultIssueChangeHolder())
}
}
But when i update the query for more tickets, I get this error
ERROR [common.UserScriptEndpoint]: Script console script failed: java.util.NoSuchElementException: Cannot access last() element from an empty List at Script497$_run_closure1.doCall(Script497.groovy:39) at Script497.run(Script497.groovy:28)
I think I need to add a line to ignore and search through the list if Custom Field is not in the history search. How do I write this? :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You could wrap it in a try/catch, so that any errors it encounters don't halt the script. We only try/catch the part of the loop that is likely to fail, i.e. the bit that handles the change history.
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
//Load needed Managers
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
//Load JQL Managers
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchService = ComponentAccessor.getComponent(SearchService)
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()
//Get your project issues based on with JQL
def query = jqlQueryParser.parseQuery("Your JQL Here ")
def results = searchService .search(user , query, PagerFilter.getUnlimitedFilter())
//Loop on Issues to set the value of the new custom field based on the old one value
results.getResults().each{item ->
log.warn("Search result: ${item}")
def issue = issueManager.getIssueObject(item.key)
log.warn("Issue: ${issue}")
// Load the new custom field object of the current issue
def newCustomField = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Your New Custom Field Name'}
log.warn(newCustomField.toString())
try{
// Get the latest value of the old custom field of the current issue
def oldCustomFieldHisotry = changeHistoryManager.getChangeItemsForField(issue, "Your Old Custom field Name").sort{it.getCreated()}
def oldCustomFieldValue = oldCustomFieldHisotry.size()>0?oldCustomFieldHisotry.last().to:null
//Set the new custom field with the old custom field value
if(oldCustomFieldValue != null)
{
newCustomField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(newCustomField), oldCustomFieldValue),new DefaultIssueChangeHolder())
}else{log.warn("${oldCustomFieldValue} was null")}
}catch(Exception e){
log.warn("Encountered an error: ${e})
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you. That didn't solve it, but I finally solved it. Just a small change to the original script is required to solve this issue. :
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.history.ChangeItemBean
//Load needed Managers
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
//Load JQL Managers
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchService = ComponentAccessor.getComponent(SearchService)
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()
//Get your project issues based on with JQL
def query = jqlQueryParser.parseQuery("Your JQL Here")
def results = searchService .search(user , query, PagerFilter.getUnlimitedFilter())
//Loop on Issues to set the value of the new custom field based on the old one value
results.getResults().each{item ->
def issue = issueManager.getIssueObject(item.key)
// Load the new custom field object of the current issue
def newCustomField = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Your Old Custom field Name'}
// Get the latest value of the old custom field of the current issue
def oldCustomFieldHisotry = changeHistoryManager.getChangeItemsForField(issue, "Your New Custom field Name").sort{it.getCreated()}
def oldCustomFieldValue = oldCustomFieldHisotry.size() > 0? oldCustomFieldHisotry.last().toString:null
//Set the new custom field with the old custom field value
if(oldCustomFieldValue != null)
{
newCustomField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(newCustomField), oldCustomFieldValue),new DefaultIssueChangeHolder())
log.warn("${issue} ${oldCustomFieldValue}")
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
If we update a custom field's value by following the method above, does it show up in the issue's history? (I believe it doesn't)
So, what's the right way to update a custom field's value by storing history?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Did anyone figure out how to accomplish this in Jira Cloud? I tried using the original script but the "imports" aren't a thing in cloud.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.