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.