Feature Score | Issue Score |
---|---|
Name-Value parameter | Key-Value custom field |
Linear parameter | Number custom field |
If only a few Score fields and/or parameters are created and few Issues are involved in your system, you can also perform the migration manually. Simply click on the values on the relevant tickets page.
If a lot of Score fields and/or parameters are created and there are many Issues involved in your system, you might want to perform the migration using a script tool. Here's how you can do this with Adaptavist ScriptRunner.
Feature Score store the selected values in the database. The values can be retrieved with their ID.
Here is an example of the data structure:
{ "calculatedValue" : 40, "calculatedColor" : "aui-lozenge-success", "tooltip" : "tooltip-sample", "scoreParameterPair": [{ "optionType" : "LINEAR", "scoreParameterId": 1, "scoreParameterOptionId": 1 }, { "optionType" : "NAME-VALUES", "scoreParameterId": 3, "scoreParameterOptionId": 5 }, { "optionType" : "LINEAR", "scoreParameterId": 2, "scoreParameterOptionId": 7 }] } |
You should explore your Feature Score parameters' and their values' ID's. You can do that on an Issue page with the help of your browser's developer tool.
Name-Value Pair IDs
Linear IDs
You can also retrieve your new Issue Score Key-Value pair custom fields' option ID, or you get get it from the URL when you are editing the option, eg.: /plugins/servlet/issue-score/customfield/key-value/admin/edit?customFieldId=10410&keyValueId=25&fieldConfigId=10514
Based on the known IDs now you can create a script that will map the Feature Score parameters to the new custom fields.
Below you can see an example for the two parameter types and their equivalents with Issue Score. We recommend to create a mapping table with the IDs, eg.:
Name-Value to Key-Value
Feature Score | | | Issue Score | ||||||
---|---|---|---|---|---|---|---|---|
Feature Score Parameter | Type | Option | ID | | | Custom Field | Type | Option | ID |
Parameter One | Name-Value | 5 | | | Parameter One | Issue Score Key-Value | |||
Option One | 9 | | | Option One - 1 | 25 |
Linear to Number
Feature Score | | | Issue Score | |||||
---|---|---|---|---|---|---|---|
Feature Score Parameter | Type | Option | ID | | | Custom Field | Type | Value |
Parameter Linear | Linear | 7 | | | Parameter Number | Number custom field | ||
1 | 1 | | | 1 |
import com.atlassian.jira.component.ComponentAccessor; import com.atlassian.jira.issue.CustomFieldManager; import com.atlassian.jira.issue.fields.CustomField; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.issue.MutableIssue; import com.atlassian.jira.security.JiraAuthenticationContext; import com.atlassian.jira.issue.search.SearchProvider; import com.atlassian.jira.jql.parser.JqlQueryParser; import com.atlassian.jira.util.JiraUtils; import com.atlassian.jira.workflow.WorkflowTransitionUtil; import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl; import com.atlassian.jira.user.util.UserManager; import com.atlassian.crowd.embedded.api.User; import com.atlassian.jira.user.ApplicationUsers; import com.atlassian.jira.user.ApplicationUser; import com.atlassian.jira.issue.util.DefaultIssueChangeHolder; import com.atlassian.jira.issue.ModifiedValue; UserManager userManager = ComponentAccessor.getUserManager(); ApplicationUser adminUserApp = userManager.getUserByName("jira.admin"); // <- Add here the user who has the necessary permissions def AuthContext=ComponentAccessor.getJiraAuthenticationContext(); AuthContext.setLoggedInUser(adminUserApp); def findIssues(String jqlQuery) { def issueManager = ComponentAccessor.issueManager def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser() def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class) def searchProvider = ComponentAccessor.getComponent(SearchProvider.class) org.apache.lucene.search.Collector collector def query = jqlQueryParser.parseQuery(jqlQuery) def results = searchProvider.search(query, user, com.atlassian.jira.web.bean.PagerFilter.getUnlimitedFilter()) results.issues.collect { issue -> issueManager.getIssueObject(issue.id) } } def currentUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser().getName(); def jqlQuery = "project = IMAS" // <- Define your project or Issues with JQL def issues = findIssues(jqlQuery) issues.each { def issueManager = ComponentAccessor.issueManager; def issue = (Issue) it; def customFieldManager = ComponentAccessor.getCustomFieldManager(); def featureScore = customFieldManager.getCustomFieldObjectByName('Feature Score'); // <- Define your FS custom field def featureScoreCFvalue = issue.getCustomFieldValue(featureScore); def keyValueOne = customFieldManager.getCustomFieldObjectByName('Parameter One'); // <- Define your Issue Score Key-Value custom field def keyValueOneCFvalue = issue.getCustomFieldValue(keyValueOne); def numberField = customFieldManager.getCustomFieldObjectByName('Issue Score Number'); // <- Define your Number custom field def numberFieldvalue = issue.getCustomFieldValue(numberField); // Example of the value mapping // IGNORE THE RED STATIC TYPE CHECKING ERROR if(featureScoreCFvalue != null) { def list = featureScoreCFvalue.getScoreParameterPair(); // <- Iterate in your FS data structure for (item in list) { if(item.scoreParameterId == 5){ // <- If "Parameter One" with ID=5 if(item.scoreParameterOptionId == 9){ // <- If "Parameter One"'s selected otpion is "Option One" with ID=9 def changeHolder = new DefaultIssueChangeHolder() keyValueOne.updateValue(null, issue, new ModifiedValue(keyValueOneCFvalue, (Double) 25),changeHolder) // <- Set Issue Score KV pair to "Option One - 1" with ID=25 } } if(item.scoreParameterId == 7){ // <- If "Parameter Linear" with ID=7 if(item.scoreParameterOptionId == 1){ // <- If "Parameter Linear"'s selected otpion is "1" with ID=1 def changeHolder = new DefaultIssueChangeHolder() numberField.updateValue(null, issue, new ModifiedValue(numberFieldvalue, (Double) 1),changeHolder) // <- Set number field to "1" } } } } } |
import com.atlassian.jira.component.ComponentAccessor; import com.atlassian.jira.issue.CustomFieldManager; import com.atlassian.jira.issue.fields.CustomField; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.issue.MutableIssue; import com.atlassian.jira.security.JiraAuthenticationContext; import com.atlassian.jira.bc.issue.search.SearchService; import com.atlassian.jira.jql.parser.JqlQueryParser; import com.atlassian.jira.util.JiraUtils; import com.atlassian.jira.workflow.WorkflowTransitionUtil; import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl; import com.atlassian.jira.user.util.UserManager; import com.atlassian.crowd.embedded.api.User; import com.atlassian.jira.user.ApplicationUsers; import com.atlassian.jira.user.ApplicationUser; import com.atlassian.jira.issue.util.DefaultIssueChangeHolder; import com.atlassian.jira.issue.ModifiedValue; UserManager userManager = ComponentAccessor.getUserManager(); ApplicationUser adminUserApp = userManager.getUserByName("jira.admin"); // <- Add here the user who has the necessary permissions def AuthContext=ComponentAccessor.getJiraAuthenticationContext(); AuthContext.setLoggedInUser(adminUserApp); def findIssues(String jqlQuery) { def issueManager = ComponentAccessor.issueManager def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser() def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class) def searchService = ComponentAccessor.getComponent(SearchService.class) org.apache.lucene.search.Collector collector def query = jqlQueryParser.parseQuery(jqlQuery) def results = searchService.search(user, query, com.atlassian.jira.web.bean.PagerFilter.getUnlimitedFilter()) results.results.collect { issue -> issueManager.getIssueObject(issue.id) } } def currentUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser().getName(); def jqlQuery = "project = IMAS" // <- Define your project or Issues with JQL def issues = findIssues(jqlQuery) issues.each { def issueManager = ComponentAccessor.issueManager; def issue = (Issue) it; def customFieldManager = ComponentAccessor.getCustomFieldManager(); def featureScore = customFieldManager.getCustomFieldObjectByName('Feature Score'); // <- Define your FS custom field def featureScoreCFvalue = issue.getCustomFieldValue(featureScore); def keyValueOne = customFieldManager.getCustomFieldObjectByName('Parameter One'); // <- Define your Issue Score Key-Value custom field def keyValueOneCFvalue = issue.getCustomFieldValue(keyValueOne); def numberField = customFieldManager.getCustomFieldObjectByName('Issue Score Number'); // <- Define your Number custom field def numberFieldvalue = issue.getCustomFieldValue(numberField); // Example of the value mapping // IGNORE THE RED STATIC TYPE CHECKING ERROR if(featureScoreCFvalue != null) { def list = featureScoreCFvalue.getScoreParameterPair(); // <- Iterate in your FS data structure for (item in list) { if(item.scoreParameterId == 5){ // <- If "Parameter One" with ID=5 if(item.scoreParameterOptionId == 9){ // <- If "Parameter One"'s selected otpion is "Option One" with ID=9 def changeHolder = new DefaultIssueChangeHolder() keyValueOne.updateValue(null, issue, new ModifiedValue(keyValueOneCFvalue, (Double) 25),changeHolder) // <- Set Issue Score KV pair to "Option One - 1" with ID=25 } } if(item.scoreParameterId == 7){ // <- If "Parameter Linear" with ID=7 if(item.scoreParameterOptionId == 1){ // <- If "Parameter Linear"'s selected otpion is "1" with ID=1 def changeHolder = new DefaultIssueChangeHolder() numberField.updateValue(null, issue, new ModifiedValue(numberFieldvalue, (Double) 1),changeHolder) // <- Set number field to "1" } } } } } |
After running the script, run the Bulk Update on these issues to apply the changes and calculate the Issue core as described here.