Just a heads up: On March 24, 2025, starting at 4:30pm CDT / 19:30 UTC, the site will be undergoing scheduled maintenance for a few hours. During this time, the site might be unavailable for a short while. Thanks for your patience.
×Im sure this is something simple that im missing, but my google-fu is failing me.
I would like to force a user to attach a file when the checkbox custom field "BIP Setup Type" checkbox has "NWEA (Requires Comprehensive Data File (CDF) Upload)" checked. I wrote a behavior but it was a bit clunky so I changed it to a validator off of the Create transition. When I set the following validator, the ticket throws the error regardless if "NWEA (Requires Comprehensive Data File (CDF) Upload)" is checked or not.
import com.atlassian.jira.component.ComponentAccessor
cfValues['BIP Setup Type']*.value.contains("NWEA (Requires Comprehensive Data File (CDF) Upload)") || ComponentAccessor.attachmentManager.getAttachments(issue).size() >= 1
import com.atlassian.jira.component.ComponentAccessor
//split into two seperate variables for readability
def containsVal = //checks the checkbox
def hasAttachments = ComponentAccessor.attachmentManager.getAttachments(issue).size() >= 1
if(containsVal)
{
if(hasAttachments)
{
return true
}
else
{
return false
}
}
else
{
return true
}
//return true being allow, return false being deny
I believe there are a couple problems with your original script. Firstly, using ||. || refers to "or", so it would hypothetically allow the ticket to be created if that box was checked regardless of if there was an attachment. I believe the logic in the script above is correct. However, I think the core issue is with the way you are fetching the values from the custom field. I am not sure, but if I had to guess:
cfValues['BIP Setup Type']*.value
is returning an arraylist rather than than the actual values that are checked- something like
[true, false, true, true, false]
So you would have to check the index of that specific item on the list, rather than the list itself. If you could post the output of
cfValues['BIP Setup Type']*.value
that could help narrow it down.
Thanks for your reply Ben, I got the idea to use || from the following use on Scriptrunners Wiki: https://scriptrunner.adaptavist.com/5.4.47/jira/recipes/workflow/validators/simple-scripted-validators.html. It explains the || as only doing the second half if the first half is true. I am setting it up as a script validator so it should work that way right? In any case, I initially made a full custom script similar to what you have above:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def containsField = customFieldManager.getCustomFieldObjectByName("BIP Setup Type")
def containsVal = issue.getCustomFieldValue(containsField)
def hasAttachments = ComponentAccessor.attachmentManager.getAttachments(issue).size()
if(containsVal == "NWEA (Requires Comprehensive Data File (CDF) Attachment)")
{
if(hasAttachments == null)
{
invalidInputException = new InvalidInputException("Please use the Attachements field to add the Comprehensive Data File (CDF) ");
}
else
{
return false
}
}
else
{
return true
}
When I run this, I get the below error still, even though I thought I had accounted for the null value:
2019-03-01 15:00:35,042 ERROR [workflow.ScriptWorkflowFunction]: ************************************************************************************* 2019-03-01 15:00:35,043 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: null, actionId: 1, file: <inline script> java.lang.NullPointerException at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getStoredAttachments(DefaultAttachmentManager.java:193) at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getAttachments(DefaultAttachmentManager.java:187) at com.atlassian.jira.issue.AttachmentManager$getAttachments.call(Unknown Source) at Script105.run(Script105.groovy:8)
Any idea why it still fails on null value?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It explains the || as only doing the second half if the first half is true.
Other way around. It only needs one of the conditions to be true, so if the first condition is, it doesn't bother with the second statement and just proceeds, since both
true || false
and
true || true
resolve to true.
Re: the null error,
The exception occurs on line 8, which is this line:
def hasAttachments = ComponentAccessor.attachmentManager.getAttachments(issue).size()
To break it down:
ComponentAccessor.attachmentManager
Returns the attachmentManager object
attachmentManager.getAttachments(issue)
Returns a List object (with each item in the List being an Attachment object). If the issue has no attachments, this returns null.
getAttachments(issue).size()
This is where the issue is. If the issue has no attachments, getAttachments returns null. If you try to access the .size() method of a null object, you get a nullpointerexception. To get around this, put a ? after getAttachments(issue). The ? is called a Null Safe Operator. Here is a StackOverflow post that explains it very well.
getAttachments(issue)?.size()
However, this will still return null (but not crash) if the issue has no attachments. To sum this up into how you turn all of this into a true/false value:
def hasAttachments = ComponentAccessor.attachmentManager.getAttachments(issue)?.size()
if(hasAttachments != null)
{
hasAttachments = true
}
else
{
hasAttachments = false
}
Alternate way of doing the same thing in less lines:
def hasAttachments = (ComponentAccessor.attachmentManager.getAttachments(issue) != null)
However, I still think the other issue is checking that value in the checkbox field. If you could reply with what shows up in your log files when you include this:
def containsField = customFieldManager.getCustomFieldObjectByName("BIP Setup Type")
def containsVal = issue.getCustomFieldValue(containsField)
log.error(containsVal.toString())
That might shed some light on how those fields work.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It explains the || as only doing the second half if the first half is true.
Other way around. || only needs one condition to be true, so if the first one is, it doesn't bother evaluating the second condition, since both
true || false
and
true || true
both evaluate to true.
It's crashing on this line:
def hasAttachments = ComponentAccessor.attachmentManager.getAttachments(issue).size()
Specifically, it's crashing here:
getAttachments(issue).size()
If the issue has no attachments, getAttachments returns null. If you try to access the .size() method of a null object, you get a NullPointerException.
To get around that, you can just check whether getAttachments returns null (since if it is not null, it is guaranteed to have at least one attachment).
def hasAttachments = (ComponentAccessor.attachmentManager.getAttachments(issue) != null)
I still think their may be an issue with how the value from the checkbox is returned. Could you post what shows up in your log file when you add this line?
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def containsField = customFieldManager.getCustomFieldObjectByName("BIP Setup Type")
def containsVal = issue.getCustomFieldValue(containsField)
log.error("VALUE OF FIELD: ${containsVal.toString()}")//ADD THIS LINE
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I updated the script to account for the attachment field being null and added the log output:
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
//split into two separate variables for readability
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def containsField = customFieldManager.getCustomFieldObjectByName("BIP Setup Type")
def containsVal = issue.getCustomFieldValue(containsField)
def hasAttachments = (ComponentAccessor.attachmentManager.getAttachments(issue) == null)
if(containsVal == "NWEA (Requires Comprehensive Data File (CDF) Attachment)")
{
if(hasAttachments)
{
invalidInputException = new InvalidInputException("Please use the Attachements field to add the Comprehensive Data File (CDF) ");
}
else
{
return false
}
}
else
{
return true
}
//return true being allow, return false being deny
log.error("VALUE OF FIELD: ${containsVal.toString()}")//ADD THIS LINE
However I still get the following error in the log and nothing else:
2019-03-04 14:45:20,129 http-nio-8080-exec-1 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 885x85821x1 1agwjrs 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] Script function failed on issue: null, actionId: 1, file: <inline script>
java.lang.NullPointerException
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getStoredAttachments(DefaultAttachmentManager.java:193)
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getAttachments(DefaultAttachmentManager.java:187)
at com.atlassian.jira.issue.AttachmentManager$getAttachments.call(Unknown Source)
at Script33.run(Script33.groovy:9)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Could you add this to the top of the script (right after the import statements) and post the output?
log.error(issue)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Looks like the output is the content of the issue value in the checkbox:
2019-03-04 16:23:19,721 http-nio-8080-exec-6 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 983x103730x1 17phabx 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] Test Basic Setup Attachments 125
2019-03-04 16:23:19,722 http-nio-8080-exec-6 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 983x103730x1 17phabx 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] VALUE OF FIELD: [NWEA (Requires Comprehensive Data File (CDF) Attachment)]
2019-03-04 16:23:19,727 http-nio-8080-exec-6 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 983x103730x1 17phabx 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] *************************************************************************************
2019-03-04 16:23:19,728 http-nio-8080-exec-6 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 983x103730x1 17phabx 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] Script function failed on issue: null, actionId: 1, file: <inline script>
java.lang.NullPointerException
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getStoredAttachments(DefaultAttachmentManager.java:193)
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getAttachments(DefaultAttachmentManager.java:187)
at com.atlassian.jira.issue.AttachmentManager$getAttachments.call(Unknown Source)
at Script70.run(Script70.groovy:10)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
def containsVal = issue.getCustomFieldValue(containsField)
needs to be
def containsVal = issue.getCustomFieldValue(containsField)[0]
Since getCustomFieldValue is returning an array. If you try to log the issue variable, what shows up?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
When I add the line
def containsVal = issue.getCustomFieldValue(containsField)[0]
It wont work. I get a red "x". I tried to add it like
import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException
log.error(issue)
//split into two seperate variables for readability
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def containsField = customFieldManager.getCustomFieldObjectByName("BIP Setup Type")
//def containsVal = issue.getCustomFieldValue(containsField)
def containsVal = issue.getCustomFieldValue(containsField)
log.error("VALUE OF FIELD: ${containsVal.toString()}")
def hasAttachments = (ComponentAccessor.attachmentManager.getAttachments(issue))
if(containsVal == "NWEA (Requires Comprehensive Data File (CDF) Attachment)")
{
if(hasAttachments != null)
{
return true
}
else
{
invalidInputException = new InvalidInputException("Please use the Attachements field to add the Comprehensive Data File (CDF) ");
}
}
else
{
return true
}
Im not sure what you mean by log the variable, I thought the variable in this custom field was the value, aka "NWEA (Requires Comprehensive Data File (CDF) Attachment)"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
For containsVal, replace
def containsVal = issue.getCustomFieldValue(containsField)
with:
def containsVal = issue.getCustomFieldValue(containsField)[0]
The [0] is indicating the first item in the list (even if the list only contains one item).
Im not sure what you mean by log the variable, I thought the variable in this custom field was the value, aka "NWEA (Requires Comprehensive Data File (CDF) Attachment)"
Referring to the actual issue variable itself. You actually already have it in the script in your last reply- log.error(issue). Could you add these two lines above and below it, then test it again and post the log file?
Above:
log.error("VVVVVVVV")
Below:
log.error("^^^^^^^^^^")
So where the log.error statement is now, you would have:
log.error("VVVVVVVV")
log.error(issue)
log.error("^^^^^^^^^^")
This doesn't actually accomplish anything in terms of functionality, it just helps us narrow down where the problem is.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
When I put in the [0] this is what I get:
As far as the logging is concerned, I added the requested lines above and below log.error(issue) and here is what I got:
2019-03-05 15:25:32,783 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] VVVVVVVV
2019-03-05 15:25:32,783 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] Test Basic Setup Attachments 11
2019-03-05 15:25:32,783 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] ^^^^^^^^^^
2019-03-05 15:25:32,783 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] VALUE OF FIELD: [NWEA (Requires Comprehensive Data File (CDF) Attachment)]
2019-03-05 15:25:32,786 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] *************************************************************************************
2019-03-05 15:25:32,787 http-nio-8080-exec-23 url:/servicedesk/cu...ortal/7/create/146 username:esmith url:/rest/servicede...ortal/7/create/146 username:esmith ERROR esmith 925x84951x1 1avr4db 10.233.231.29,10.231.220.22 /servicedesk/customer/portal/7/create/146 [c.o.s.jira.workflow.ScriptWorkflowFunction] Script function failed on issue: null, actionId: 1, file: <inline script>
java.lang.NullPointerException
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getStoredAttachments(DefaultAttachmentManager.java:193)
at com.atlassian.jira.issue.managers.DefaultAttachmentManager.getAttachments(DefaultAttachmentManager.java:187)
at com.atlassian.jira.issue.AttachmentManager$getAttachments.call(Unknown Source)
at Script75.run(Script75.groovy:13)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Oh, I see why that wasn't working. Replace
def containsVal = issue.getCustomFieldValue(containsField)
with
def listOfVals = issue.getCustomFieldValue(containsField)
def containsVal = listOfVals[0]
Then replace
def hasAttachments = (ComponentAccessor.attachmentManager.getAttachments(issue))
With
def attachmentManager = ComponentAccessor.getAttachmentManager()
def hasAttachments = (attachmentManager.getAttachments(issue).size() > 0)
I believe that should fix it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Still getting an error when values is [0]. See screenshot:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Looks like it's being picky about the type of object. To get around it, we can do this:
Replace
def listOfVals = issue.getCustomFieldValue(containsField)
def containsVal = listOfVals[0]
With
def listOfVals = issue.getCustomFieldValue(containsField)
def containsVal = "temp value"
try
{
containsVal = listOfVals[0]
}
catch (Exception e)
{
log.error(e.getStackTrace().toString())
}
log.error("The value is ${containsVal}")
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Same error, definitely doesnt like the integer at the end:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry, just saw this, been a busy week. Try changing
def listOfVals = issue.getCustomFieldValue(containsField)
to
ArrayList<> listOfVals = (ArrayList<>) issue.getCustomFieldValue(containsField)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Different error, im not sure what you are trying to do with that line:
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.