Hi everybody,
After looking for a solution myslef, I'm kind out of idea right now. Here's the situation :
Environment : Jira 5.2.11 / Script Runner 2.1.15
When creating an issue, (in post-function) I want to :
- Extract values from a cascading select field (Nature of the Request - cf id:17000)
- Check if the word 'QlikView' is in the first value
- Update another cascading field (System and Sub-System - cf id 11201) with values (existing in the field configuration, let's say Data - QlikView)
So far, I have this script I modified to fit my needs, BUT the updating process doesn't manage to update the cf 11201 value.
When checking the script with the script console, I don't have any error message and it gives me back the correct value (Data - QlikView).
But when I put the script in the workflow, the value isn't updated in the cf 11201
// and if I look at the logs, i have the following message :
// Caused by: java.lang.NoClassDefFoundError: com/opensymphony/user/User
// --> caused by a plugin old version
Do you have any clues about what's wrong?
Thanks!
import org.apache.log4j.Category import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import com.atlassian.jira.ComponentManager import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.util.IssueChangeHolder import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem import com.atlassian.jira.issue.customfields.manager.OptionsManager import com.atlassian.jira.issue.customfields.view.CustomFieldParams import com.atlassian.jira.issue.customfields.view.CustomFieldParamsImpl import com.atlassian.jira.issue.fields.layout.field.FieldLayoutStorageException import com.atlassian.jira.issue.customfields.impl.CascadingSelectCFType import com.atlassian.jira.issue.customfields.option.Option import com.atlassian.jira.component.ComponentAccessor import com.opensymphony.workflow.WorkflowContext; MutableIssue issue = issue CustomFieldManager cfManager2 = ComponentManager.getInstance().getCustomFieldManager() // name of the first cascading field I will extract the value in order to check it CustomField cf2 = cfManager2.getCustomFieldObject(17000) String first = issue.getCustomFieldValue(cf2)?.values()*.value[0] String second = issue.getCustomFieldValue(cf2)?.values()*.value[1] // name of the cascading field where I want to put my new value CustomField categoryCF = ComponentManager.getInstance().getCustomFieldManager().getCustomFieldObjectByName("Système et sous-système"); CustomFieldParams cfVal = issue.getCustomFieldValue(categoryCF) as CustomFieldParams if (categoryCF == null || !(categoryCF.getCustomFieldType() instanceof CascadingSelectCFType)) { log.error("Expected customfield doesn't exist or doesn't have the expected type."); } OptionsManager optionsManager = ComponentAccessor.getOptionsManager(); Option parentOptionObj = optionsManager.findByOptionId(11124); // value to put in first list Option childOptionObj = optionsManager.findByOptionId(11211); // value to put in second list Map<String,Object> newValues = new HashMap<String, String>(); // checking if the value in the first cascading field is correct if (first.contains('QlikView')) { newValues.put(null, parentOptionObj); newValues.put("1", childOptionObj); // then updating the second cascading field with new values categoryCF.updateValue(null, issue, new ModifiedValue(cfVal,newValues), new DefaultIssueChangeHolder()); issue.store() }
Ok, if you want to update a blank cascading select field, you just have to put in comment the following lines :
// Object cValue = categoryCF.getValue(cIssue); // if (cValue == null) { // log.error("Expected customfield doesn't have any value."); // }
and replace the last line of the script with :
categoryCF.updateValue(null, cIssue, new ModifiedValue(null, newValues), new DefaultIssueChangeHolder());
Hi,
Using ComponentAccessor now
import com.atlassian.jira.component.ComponentAccessor //(...) CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() //(...) def CUSTOM_FIELD_ID = 11201; // set your Cascading Select custom field Id //Get your Cascading Select CF Object def categoryCF = customFieldManager.getCustomFieldObject(CUSTOM_FIELD_ID);
If we want to find the Parent and the child Options Object from the string of their context label :
// if you know or you find these strings String stParentOption = "Targeted parent option"; String stChildOption = "Targeted child option of the selected parent"; // you'll be able to find their Options objects as below // null as parentId to find the string into the parent options list of the context Option parentOptionObj = optionsManager.getOptions(categoryCF.getRelevantConfig(cIssue)).getOptionForValue(stParentOption,null) // knowing the parent Option object, you'll find the children on its Id Option childOptionObj = optionsManager.getOptions(myCascadingCf.getRelevantConfig(cIssue)).getOptionForValue(stChildOption,parentOptionObj.optionId)
and I add how I store it
def newValues = new HashMap(); newValues.put(null, parentOptionObj); newValues.put("1", childOptionObj); classificationObj.updateValue(null, cIssue, new ModifiedValue(null, newValues), changeHolder); // deprecated way to store the issue cIssue.store() // to be updated with something like // issueManager.updateIssue(cUser, cIssue, EventDispatchOption.DO_NOT_DISPATCH, false);
have fun
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Which of the scripts above could be used to copy the contents of a select list (single) to a select list (cascading), changing from a single entry to a map form?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
A script below I used to copy values from a source Cascading Select CF, named "Classification Incident", to a target one, named "Classification", using a JQL query filter
/** * Created by robert_mota on 18/12/2014. * Script to use one shot to copy "Classification Incident" CF * into "Classification" * * Prerequisite : all the values of the source Cascading Select CF * must be in context configuration of the target CF */ import com.atlassian.crowd.embedded.api.User import com.atlassian.jira.bc.issue.search.SearchService import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.event.type.EventDispatchOption import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.IssueManager import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.customfields.manager.OptionsManager import com.atlassian.jira.issue.customfields.option.Option import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import com.atlassian.jira.issue.util.IssueChangeHolder import com.atlassian.jira.web.bean.PagerFilter import org.apache.log4j.Level import org.apache.log4j.Logger import com.atlassian.jira.issue.ModifiedValue CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() IssueChangeHolder changeHolder = new DefaultIssueChangeHolder(); Logger log = Logger.getLogger("com.onresolve.jira.groovy") log.setLevel(Level.DEBUG) log.debug("Begin: Fix Classification ****************************"); OptionsManager optionsManager = ComponentAccessor.getOptionsManager(); // to test on 1 issue //jqlSearch = "project = CSI AND issuetype = incident AND \"Classification Incident\" is not EMPTY and Classification is not EMPTY and key in (CSI-23015)" // to run on all issues of the search jqlSearch = "project = CSI AND issuetype = incident AND \"Classification Incident\" is not EMPTY and Classification is not EMPTY" SearchService searchService = ComponentAccessor.getComponent(SearchService.class) // ComponentAccessor.getJiraAuthenticationContext().getUser() returns an ApplicationUser // To get the User needed for SearchService below, use getDirectoryUser() method User user = ComponentAccessor.getJiraAuthenticationContext().getUser().getDirectoryUser() IssueManager issueManager = ComponentAccessor.getIssueManager() if (!user) { log.debug("User not found ****************************"); return false; } SearchService.ParseResult parseResult = searchService.parseQuery(user, jqlSearch) if (parseResult.isValid()) { def searchResult = searchService.search(user, parseResult.getQuery(), PagerFilter.getUnlimitedFilter()) // Transform issues from DocumentIssueImpl to the "pure" form IssueImpl (some methods don't work with DocumentIssueImps) def issues = searchResult.issues.collect {issueManager.getIssueObject(it.id)} issues.each { MutableIssue incident = it as MutableIssue; // Source CF named "Classification Incident" id = 10490 def classificationIncidentObj = customFieldManager.getCustomFieldObjectByName("Classification Incident"); // to use ID //def classificationIncidentObj = customFieldManager.getCustomFieldObject(10490); // Target CF cible Classification id = 10367 def classificationObj = customFieldManager.getCustomFieldObjectByName("Classification"); //def classificationObj = customFieldManager.getCustomFieldObject(10367); def classificationIncident = classificationIncidentObj.getValue(incident); //log.debug ("\n Incident: Classification Incident Parent: " + classificationIncident.get(null)); //log.debug ("\n Incident: Classification Incident Child: " + classificationIncident.get("1")); String stParentOption = classificationIncident.get(null); String stChildOption = classificationIncident.get("1"); //log.debug ("\n Incident: stParentOption = " + stParentOption); //log.debug ("\n Incident: stChildOption = " + stChildOption); Option parentOptionObj = optionsManager.getOptions(classificationObj.getRelevantConfig(incident)).getOptionForValue(stParentOption,null) //log.debug ("\n Target Parent Classification = " + parentOptionObj); Option childOptionObj = optionsManager.getOptions(classificationObj.getRelevantConfig(incident)).getOptionForValue(stChildOption,parentOptionObj.optionId) //log.debug ("\n Target Classification child ("+ parentOptionObj + ") = " + childOptionObj); def newValues = new HashMap(); newValues.put(null, parentOptionObj); newValues.put("1", childOptionObj); //log.debug ("\n Target Classification Parent new value: " + newValues.get(null)); //log.debug ("\n Target Classification Child new value: " + newValues.get("1")); // To store it classificationObj.updateValue(null, incident, new ModifiedValue(null, newValues), changeHolder); // deprecated method to store issues //incident.store() // new way to store issues issueManager.updateIssue(user, incident, EventDispatchOption.DO_NOT_DISPATCH, false); } } else { log.debug("Invalid JQL: " + jqlSearch); return false; } log.debug("End: Fix Classification ****************************"); return true;
Regards
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.
Ok, I made some progress. Right now, this script can modify the value of a cascading select field already containing values. I have now to make it work with an empty field.
Hope this first script can help some people :
import org.apache.log4j.Category import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.util.DefaultIssueChangeHolder import com.atlassian.jira.ComponentManager import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.util.IssueChangeHolder import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem import com.atlassian.jira.issue.customfields.manager.OptionsManager import com.atlassian.jira.issue.customfields.view.CustomFieldParams import com.atlassian.jira.issue.customfields.view.CustomFieldParamsImpl import com.atlassian.jira.issue.fields.layout.field.FieldLayoutStorageException import com.atlassian.jira.issue.customfields.impl.CascadingSelectCFType import com.atlassian.jira.issue.customfields.option.Option import com.atlassian.jira.component.ComponentAccessor import com.atlassian.crowd.embedded.api.User; MutableIssue cIssue = issue // get customfield CustomField categoryCF = ComponentManager.getInstance().getCustomFieldManager().getCustomFieldObject(11201); if (categoryCF == null || !(categoryCF.getCustomFieldType() instanceof CascadingSelectCFType)) { log.error("Expected customfield doesn't exist or doesn't have the expected type."); } OptionsManager optionsManager = (OptionsManager)ComponentManager.getComponentInstanceOfType(OptionsManager.class); // get customfield value Object cValue = categoryCF.getValue(cIssue); if (cValue == null) { log.error("Expected customfield doesn't have any value."); } Option parentOptionObj = optionsManager.findByOptionId(11124); // get first value to input Option childOptionObj = optionsManager.findByOptionId(11211); // get second value to input Map<String,Object> newValues = new HashMap<String, String>(); newValues.put(null, parentOptionObj); //input value in first dropdown newValues.put("1", childOptionObj); // input value in second dropdown //update issue and save modifications in database categoryCF.updateValue(null, cIssue, new ModifiedValue(cValue, newValues), new DefaultIssueChangeHolder()); issue.store()
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
check the "setFieldValue" method on following class, i hope it will help you
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Rambanam, i'll check and let you know! :)
Cheers!
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
yes in the workflow transition you check any other validators or postfunctions present.
Eventhough you disabled, those were not removed from the transition. You need to manually remove them.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The above script appear to be correct for me.
You check any validator script running in the transition which uses com/opensymphony/user/User object.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
it should be import
com.atlassian.crowd.embedded.api.User; as prasad suggested
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
you have to use following import
import com.atlassian.crowd.embedded.api.User;
opensymphony user has deprecated!!
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.