Scriptrunner: Validate that values of two custom fields are not identical

Declan Murphy June 23, 2015

Hi. I'm in need of a validator on a transition that checks to see if the values of two select fields "Source Language" and "Target Language" are not identical. I've tried my hand at creating a script using scriptrunner that would do exactly this but it doesn't seem to be working.

Can someone with more knowledge of groovy scripting and scriptrunner for JIRA tell me where I'm going wrong and point me in the right direction?

import com.opensymphony.workflow.InvalidInputException
def cfm = ComponentManager.instance.getCustomFieldManager()
 
def src = (issue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10206')).getValue()
def target = (issue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10207')).getValue()
 
if (src.equalsIgnoreCase( target )) {
   invalidInputException = new InvalidInputException("Source and Target Language must not be the same.")
}

Thank you kindly.

 

Edit: Thank you to Kostas for providing me with the answer. The completed code is as follows:
(I've edited the code to be a general solution)

import org.apache.log4j.Category;
import com.atlassian.jira.ComponentManager;
import com.opensymphony.workflow.InvalidInputException;
import com.atlassian.jira.ComponentManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.util.ImportUtils;
import com.opensymphony.util.TextUtils
import com.atlassian.jira.component.ComponentAccessor;
  
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
 
CustomField customField_1 = customFieldManager.getCustomFieldObject("customfield_id");
CustomField customField_2 = customFieldManager.getCustomFieldObject("customfield_id");
String string_1 = issue.getCustomFieldValue( customField_1 );
String string_2 = issue.getCustomFieldValue( customField_2 );

if (string_1.equals(string_2)) {
throw new InvalidInputException("Validation Error")
}

4 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

2 votes
Answer accepted
Tsol
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 23, 2015

I think something like the following will do the work for you

import org.apache.log4j.Category;
import com.atlassian.jira.ComponentManager;
import com.opensymphony.workflow.InvalidInputException;
import com.atlassian.jira.ComponentManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.util.ImportUtils;
import com.opensymphony.util.TextUtils
import com.atlassian.jira.component.ComponentAccessor;
 
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();

CustomField customField_1 = customFieldManager.getCustomFieldObject( id );
CustomField customField_2 = customFieldManager.getCustomFieldObject( id );

if (issue.getCustomFieldValue( customField_1 ) == issue.getCustomFieldValue( customField_2 )) {
invalidInputException = new InvalidInputException("Source and Target Language must not be the same.")
}
Declan Murphy June 23, 2015

Thank you for the help. Using your code and throwing the exception as Jamie suggested, I can see that the values of customField_1 and customField_2 are indeed identical. However, for whatever reason, the if statement isn't throwing the exception as it should. Is this a problem with the comparison? Is is that I'm comparing Strings and thus the regular equality operator doesn't work? I'm stumped since I see no reason otherwise as to why the validator is failing.

Tsol
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 23, 2015

Try the comparison with equals statement if ((issue.getCustomFieldValue( customField_1 ).toString()).equals(issue.getCustomFieldValue( customField_2 ).toString()))

Declan Murphy June 23, 2015

After further fumbling, I've managed to get it working. I'll update my question with the working code. Your code was basically right, I just had to convert the CustomField values to strings and compare those strings.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 24, 2015

> Is this a problem with the comparison? Is is that I'm comparing Strings and thus the regular equality operator doesn't work? I'm stumped since I see no reason otherwise as to why the validator is failing. The code as written is not comparing as strings... it will work if they are two text fields. However if they are say select fields it will compare two Option objects, even if they have the same "value" they will have different IDs. So the correct code really depends on what type of fields they are. Converting to string will work as it happens for selects and radios, because toString returns the option value.

1 vote
JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 23, 2015

If Kostas answer doesn't work, try instead:

throw new InvalidInputException("Source ...")

then try to narrow down what's failing, eg removing all the logic and just throwing the invalid input ex.

0 votes
Brian Alden May 22, 2017

(1) Can this be used as a Condition rather than a Validator? What alterations need to be made?

(2) What is the code for the opposite condition: string_1 does NOT equal string_2? I need a condition that two fields DO match.

Thanks.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 24, 2017

For a condition go Script Condition -> Simple Scripted Condition.

To check two custom fields do not match:

cfValues['Name of field 1'] != cfValues['Name of field 2']

To check for equality just change the operator to ==

0 votes
Hernan Montes
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 5, 2017

We are trying to do the same here, we are working to validate that a single select and a checkbox is not the same value, we already tried with simple validators and this script and it doesn't work, the error log is as follows:

2017-01-05 11:28:24,692 http-bio-80-exec-1185 ERROR US_EXT_Praecipio 688x119372x2 14a760t 10.0.64.47 /secure/admin/groovy/GroovyRunner.jspa [onresolve.jira.groovy.GroovyRunner] The script failed : javax.script.ScriptException: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: issue for class: Script7

javax.script.ScriptException: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: issue for class: Script7

  at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:117)

  at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:103)

  at javax.script.AbstractScriptEngine.eval(Unknown Source)

  at com.onresolve.jira.groovy.GroovyRunner.runFile(GroovyRunner.java:102)

  at com.onresolve.jira.groovy.GroovyRunner.run(GroovyRunner.java:62)

  at com.onresolve.jira.groovy.GroovyRunner.doExecute(GroovyRunner.java:250)  <+1> (ActionSupport.java:165)

  at com.atlassian.jira.action.JiraActionSupport.execute(JiraActionSupport.java:82)  <+7> (DefaultInterceptorChain.java:39) (NestedInterceptorChain.java:31) (ChainedInterceptor.java:16) (DefaultInterceptorChain.java:35) (GenericDispatcher.java:221) (GenericDispatcher.java:150) (JiraWebworkActionDispatcher.java:153)

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)  <+14> (ApplicationFilterChain.java:305) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (XContentTypeOptionsNoSniffFilter.java:22) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (HeaderSanitisingFilter.java:44) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)

  at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:36)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)

  at com.atlassian.jira.tzdetect.IncludeResourcesFilter.doFilter(IncludeResourcesFilter.java:39)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)

  at com.atlassian.jira.baseurl.IncludeResourcesFilter.doFilter(IncludeResourcesFilter.java:38)  <+8> (AbstractHttpFilter.java:31) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)

  at com.atlassian.mywork.client.filter.ServingRequestsFilter.doFilter(ServingRequestsFilter.java:37)  <+20> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AccessLogFilter.java:103) (AccessLogFilter.java:87) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (XsrfTokenAdditionRequestFilter.java:54) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (SiteMeshFilter.java:129) (SiteMeshFilter.java:77) (SitemeshPageFilter.java:124) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)

  at com.atlassian.labs.remoteapps.modules.permissions.ApiScopingFilter.doFilter(ApiScopingFilter.java:60)  <+32> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (SecurityFilter.java:234) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (TrustedApplicationsFilter.java:98) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (BaseLoginFilter.java:169) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:55) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ProfilingFilter.java:99) (JIRAProfilingFilter.java:19) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractJohnsonFilter.java:71) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210)

  at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)

  at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)

  at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)  <+9> (UrlRewriteFilter.java:394) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (GzipFilter.java:74) (GzipFilter.java:51) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)

  at com.atlassian.labs.remoteapps.modules.oauth.OAuth2LOFilter.doFilter(OAuth2LOFilter.java:70)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)

  at com.atlassian.labs.remoteapps.util.http.bigpipe.RequestIdSettingFilter.doFilter(RequestIdSettingFilter.java:22)  <+43> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (JWDSendRedirectFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractCachingFilter.java:33) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (AbstractEncodingFilter.java:41) (AbstractHttpFilter.java:31) (PathMatchingEncodingFilter.java:49) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (JiraStartupChecklistFilter.java:74) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (MultiTenantServletFilter.java:91) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:243) (ApplicationFilterChain.java:210) (StandardWrapperValve.java:225) (StandardContextValve.java:123) (AuthenticatorBase.java:472) (StandardHostValve.java:168) (ErrorReportValve.java:98) (StandardEngineValve.java:118) (AccessLogValve.java:927) (CoyoteAdapter.java:407) (AbstractHttp11Processor.java:1001) (AbstractProtocol.java:585) (JIoEndpoint.java:312)

  at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)

  at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

  at java.lang.Thread.run(Unknown Source)

Caused by: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: issue for class: Script7

  at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:318)

  at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:111)

  ... 163 more

Caused by: groovy.lang.MissingPropertyException: No such property: issue for class: Script7

  at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)

  at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)

  at Script7.run(Script7.groovy:19)

  at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:315)

  ... 164 more

2017-01-05 11:29:16,381 http-bio-80-exec-1210 ERROR US_EXT_Praecipio 689x119650x4 14a760t 10.0.64.47 /secure/QuickCreateIssue.jspa [groovy.canned.utils.ConditionUtils] javax.script.ScriptException: java.lang.NullPointerException: Cannot invoke method contains() on null object

2017-01-05 11:34:42,548 http-bio-80-exec-1213 ERROR US_EXT_Praecipio 694x121378x1 14a760t 10.0.64.47 /secure/QuickCreateIssue.jspa [groovy.canned.utils.ConditionUtils] javax.script.ScriptException: java.lang.NullPointerException: Cannot invoke method contains() on null object

2017-01-05 11:40:03,105 http-bio-80-exec-1222 INFO KC6P 700x123208x1 11y5iwy 10.0.85.77 /secure/WorkflowUIDispatcher.jspa [jira.web.action.XsrfErrorAction] The security token is missing for 'KC6P'. User-Agent : 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'

2017-01-05 11:42:41,985 http-bio-80-exec-1267 ERROR US_EXT_Praecipio 702x123690x1 14a760t 10.0.64.47 /secure/QuickCreateIssue.jspa [groovy.canned.utils.ConditionUtils] javax.script.ScriptException: java.lang.NullPointerException: Cannot invoke method contains() on null object

Please keep in mind this is an old environment, script runner is version 2, so I wonder if that's the case.

JamieA
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 5, 2017

can you post your script, all versions, and a screenshot of the config pls.

Hernan Montes
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 5, 2017

Here's the script called fieldcomparison.groovy

import org.apache.log4j.Category;
import com.atlassian.jira.ComponentManager;
import com.opensymphony.workflow.InvalidInputException;
import com.atlassian.jira.ComponentManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.util.ImportUtils;
import com.opensymphony.util.TextUtils
import com.atlassian.jira.component.ComponentAccessor;
  
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
 
CustomField customField_1 = customFieldManager.getCustomFieldObject("customfield_10555");
CustomField customField_2 = customFieldManager.getCustomFieldObject("customfield_10550");
 
String string_1 = issue.getCustomFieldValue( customField_1 );
String string_2 = issue.getCustomFieldValue( customField_2 );
 
if (string_1.equals(string_2)) {
throw new InvalidInputException("Validation Error")
}

JIRA version is 5.2, script runner is 2.1.2, and I don't know which configuration do you need, we are setting the script as a validator script under the open step of a workflow, we are just adding the path to the script, this means the issue doesn't exist still when running the script, we want this to validate before the issue gets created.

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

TAGS
AUG Leaders

Atlassian Community Events