Hi All,
Newbie here, struggling to putting together working script after several hours of attempted learning and forum research.
Jira Software Server 9.0.0 (On-Premise) and Groovy Scripting.
Goal: prevent user from transitioning an issue forward in workflow if selected value from among aerial options ("Yes", "No" or the default "None") for custom field is set to "Yes".
Here's the code block so far... bolded/italicized code is where I've been unsuccessful.
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.fields.CustomField
def CUSTOM_FIELD_ID = 10405L
def MESSAGE_ERROR = "Field ${getCustomFieldObject(CUSTOM_FIELD_ID)} is required"
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).name == "Yes"){
throw new InvalidInputException("Response cannot be "Yes", click Cancel")
}
if(!getCustomFieldValue(issue, CUSTOM_FIELD_ID)){
throw new InvalidInputException(MESSAGE_ERROR)
}
def getCustomFieldValue(issue, Long fieldId) {
issue.getCustomFieldValue(getCustomFieldObject(fieldId))
}
def getCustomFieldObject(Long fieldId) {
ComponentAccessor.customFieldManager.getCustomFieldObject(fieldId)
}
Above script is successful in blocking transition when there is not a custom field value entered by user (i.e., "None"), but again, having huge time in attempting to solve for also blocking transition if user chooses/selects "Yes" and tries to move issue forward in workflow.
Any help or input is very appreciated!
Have you check what is returned by logging it ?
getCustomFieldValue(issue, CUSTOM_FIELD_ID).name
Have you try
getCustomFieldValue(issue, CUSTOM_FIELD_ID).get value()
Regards
Thanks for the reply @Florian Bonniec .
Did you mean try replacing
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).name == "Yes")
with
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).get value()
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think he meant '.getValue()' which should return the string representation of the option.
Option customfields normally return a LazyLoadedOption: https://docs.atlassian.com/software/jira/docs/api/8.20.12/com/atlassian/jira/issue/customfields/option/LazyLoadedOption.html#getValue--
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.
@Florian Bonniec @Radek Dostál okay, got it - thanks for the clarification and help to this point!
Here's entire script including classes and methods with made changes highlighted in bold/italic:
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
def CUSTOM_FIELD_ID = 10405L
def MESSAGE_ERROR = "Field ${getCustomFieldObject(CUSTOM_FIELD_ID)} is required"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
def value = customFieldMananger.getCustomFieldObjectByName("Require Design")
//Block transition if "Yes" option returned
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).get value() == "Yes"){
throw new InvalidInputException("Response cannot be Yes, click Cancel")
}
//Block transition if "None" option returned
if(!getCustomFieldValue(issue, CUSTOM_FIELD_ID)){
throw new InvalidInputException(MESSAGE_ERROR)
}
def getCustomFieldValue(issue, Long fieldId) {
issue.getCustomFieldValue(getCustomFieldObject(fieldId))
}
def getCustomFieldObject(Long fieldId) {
ComponentAccessor.customFieldManager.getCustomFieldObject(fieldId)
}
Initially testing of script does not stop workflow transition when I choose "Yes" option, but will keep researching and testing more solutions.
Before testing script, there was this warning for what it's worth.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Use .getValue(),
You have a space and lower case v
Regards
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Used .getValue() without comma behind.
getCustomFieldValue(issue, CUSTOM_FIELD_ID).getValue()
Changing to .getValue() at the end did not show behaviour change on workflow, but did generate another couple errors prior to running script tests on an existing issue.
Script snippet with 1st error (bolded/italicized) "variable CustomFieldManager undeclared".
def CUSTOM_FIELD_ID = 10405L
def MESSAGE_ERROR = "Field ${getCustomFieldObject(CUSTOM_FIELD_ID)} is required"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
def value = customFieldMananger.getCustomFieldObjectByName("Require Design")
Definition is there in script, which I believe I have appropriately declared:
def customFieldManager = ComponentAccessor.getCustomFieldManager()
Script snippet with 2nd error (bolded/italicized) "Cannot find matching method java.lang.Object#getvalue()"
def CUSTOM_FIELD_ID = 10405L
def MESSAGE_ERROR = "Field ${getCustomFieldObject(CUSTOM_FIELD_ID)} is required"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
def value = customFieldMananger.getCustomFieldObjectByName("Require Design")
//Block transition if "Yes" option returned
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).getValue() == "Yes"){
throw new InvalidInputException("Response cannot be Yes, click Cancel")
}
After returning custom field's option, script checks if equal to "Yes" after the getValue().
== "Yes"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
1st - customFieldManager isn't the same as customFieldMananger
2nd - static type checking is not an error, it's just a preemptive way of warning you about potential problems, not that there necessarily are any
But here we are getting into more java related topics. In a nutshell, Issue#getCustomFieldValue() returns an Object. Everything in java extends Object, everything is an instance of Object.
What this also means, and what is happening, is that you can return any data type - because again, everything is an Object. If you return a String or an Integer - they are instances of Object.
However, Object does not have a #getValue() method. Hence the warning.
The LazyLoadedOption does - which is what is the data type you will get out of that issue.getCustomFieldValue() method.
Static type checking however has no idea what the return object will be - it sees it simply as an Object, that is why you get the static type checking warning.
What will happen in reality is that the data type of issue.getCustomFieldValue() will be LazyLoadedOption, and so .getValue() will work on it - provided it's not null, because you cannot call methods on a null.
It's just that static type checking has no clue about what the "real" class is, it only knows it's an Object but that's all it can know, so from STC perspective you are trying to call a non-existing method on an Object.
You can tell STC what data type it is
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
..
def value = ((LazyLoadedOption) issue.getCustomFieldValue(myCustomField))?.getValue()
in which case 'value' will be either null (no option selected), or String - the string representation of that option
And yes I added ? before .getValue() because that is a nullsafe check, or whatever it's called. Basically it means getValue() will not be executed if the value is null. If it's not null - meaning the issue actually has a value in that custom field - then it will execute getValue() on it. Hence, either get the option name, or null. Without ? you will probably get runtime errors because it would be trying to call getValue() on a null - if the issue currently has no custom field value.
Of course, LazyLoadedOption will only be the data type for single select fields. The return data type of issue.getCustomFieldValue() will vary depending on the custom field type. It can be a Double (number field), String (text field), List (multi select), Map (cascading) - all of which is dependent on the custom field type.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Radek Dostál thank you for that expanded explanation on STC, objects, instances, etc.
added lazyloadedoption into script like so (thinking this is sufficient syntax/placement):
def value = ((LazyLoadedOption) issue.getCustomFieldValue(myCustomField))?.getValue()
CustomField myCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(CUSTOM_FIELD_ID)
Above snippet within larger script:
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
def CUSTOM_FIELD_ID = 10405L
def MESSAGE_ERROR = "Field ${getCustomFieldObject(CUSTOM_FIELD_ID)} is required"
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
def value = ((LazyLoadedOption) issue.getCustomFieldValue(myCustomField))?.getValue()
CustomField myCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(CUSTOM_FIELD_ID)
//Block transition if "Yes" option returned
if(getCustomFieldValue(issue, CUSTOM_FIELD_ID).getValue() == "Yes"){
throw new InvalidInputException("Response cannot be Yes, click Cancel")
}
//Block transition if "None" option returned
if(!getCustomFieldValue(issue, CUSTOM_FIELD_ID)){
throw new InvalidInputException(MESSAGE_ERROR)
}
def getCustomFieldValue(issue, Long fieldId) {
issue.getCustomFieldValue(getCustomFieldObject(fieldId))
}
def getCustomFieldObject(Long fieldId) {
ComponentAccessor.customFieldManager.getCustomFieldObject(fieldId)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
This script below should work.
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
def CUSTOM_FIELD_ID = 10405
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
CustomField myCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(CUSTOM_FIELD_ID)
def value = ((LazyLoadedOption) issue.getCustomFieldValue(myCustomField))?.getValue()
def MESSAGE_ERROR = "Field ${myCustomField.getName()} is required"
//Block transition if "Yes" option returned
if(value == "Yes"){
throw new InvalidInputException("Response cannot be Yes, click Cancel")
}
//Block transition if "None" option returned
if(!value){
throw new InvalidInputException(MESSAGE_ERROR)
}
Make sure to use Custom Script validator and not Simple Script Validator.
Also when creating a script make sure to define a variable before using it.
If you need more explanation about this script let me know.
Regards
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Florian Bonniec , thanks will give above script a try and test, thank you very much for putting together and time committed!
Using mygroovy plugin for jira software, and chose inline script which looked like a simple script validator. Seems main difference between custom and simple script validator, in layman terms, is one allows more complex and accommodates use of file - again, high-level view.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Florian Bonniec , have not yet tested yet but would it make a difference to define custom field (Require Design aka 10405L - note: added "L' to end since that's exactly how it shows in Jira instance) differently?
Considering use of getCustomFieldObject(String id), like so bolded/italicized:
CustomField myCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject('customfield_10405L')
And possibly, this line goes away if above is changed:
def CUSTOM_FIELD_ID = 10405
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It should work the same, not sure le L is required.
I was thinking you was using Scriptrunner, not MyGroovy app. This app is not compatible with Jira version > 8.25.2
Regards
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Daniel McCollum use Groovy Inline Script in your case.
It should work even if not compatible but you may have issue in the future as the app is not updated anymore to work with newest Jira version.
Regards
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Florian Bonniec ,
Your script listed on 10/20/2022 is more efficient, so will need to spend some time comparing against what was written initially on my end - really appreciate your efforts and input!
Script below (from @Florian Bonniec) in Groovy inline script for Jira is without warnings and works successfully, meeting intended purpose of what I was trying to accomplish - see screenshots below script...
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
//custom field id (update "00000")
def CUSTOM_FIELD_ID = 00000
def customFieldManager = ComponentAccessor.getCustomFieldManager()
//Custom field name called Require Design with options yes no none
CustomField myCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(CUSTOM_FIELD_ID)
//Custom field value retrieved
def value = ((LazyLoadedOption) issue.getCustomFieldValue(myCustomField))?.getValue()
//Message error for "None"
def MESSAGE_ERROR = "Field ${myCustomField.getName()} is required"
//Block workflow transition if "Yes" option returned
if(value == "Yes"){
throw new InvalidInputException("Response cannot be Yes, click Cancel")
}
//Block transition if "None" option returned
if(!value){
throw new InvalidInputException(MESSAGE_ERROR)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online 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.