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.
Atlassian Government Cloud has achieved FedRAMP Authorization at the Moderate level! Join our webinar to learn how you can accelerate mission success and move work forward faster in cloud, all while ensuring your critical data is secure.
Register NowOnline 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.