Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Need help with Scriprunner (workflow) script , for validating a field value

Aisha M
Contributor
April 17, 2019

I have the below fields,

a) Bug environment 

Value 1 - Production

Value 2 - Non - production

b) Root Cause

a few drop-down values

 

I wanna use a script that says, if Bug environment is 'production' and Root cause is NULL/empty. Then the bug cannot be moved to DONE , if its Non-production, then don't bother.

 

Sample code :

def rootcause = GetCustomFieldValue(issue, "customfield_10107");
if (issueType == "Bug")
{
if (rootcause == null || rootcause.isEmpty())
{
errors.add("Root Cause is required to accept this ${issueType}");
}
}

 

 

Any help on this, please. Thanks

2 answers

1 accepted

2 votes
Answer accepted
Antoine Berry
Community Champion
April 17, 2019

Hi @Aisha M ,

My advice is to add a script validator in the transition to Done. Assuming bug environnement is a single select custom field and root cause is a multi select custom field, this should do the trick : 

import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException

def customFieldManager = ComponentAccessor.getCustomFieldManager()

int bugEnvironmentId = 10000
def bugEnvironment = customFieldManager.getCustomFieldObject(bugEnvironmentId)
def bugEnvironmentValue = issue.getCustomFieldValue(bugEnvironment)

int rootCauseId = 10001
def rootCause = customFieldManager.getCustomFieldObject(rootCauseId)
def rootCauseValue = issue.getCustomFieldValue(rootCause)

if (bugEnvironmentValue != null && bugEnvironmentValue.getValue() == "Production" && rootCauseValue == null){
invalidInputException = new InvalidInputException("Root Cause is required to accept this " + issue.getIssueType().getName())
throw invalidInputException
}

Just update the custom field IDs.

Antoine

PD Sheehan
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.
April 17, 2019

To add to this answer, if you want the error to appear next to the root cause field rather than at the top of the transition form, you can use a different signature for new InvalidInputException

def invalidInputException = new InvalidInputException(rootCauseId, "Root Cause is required to accept this " + issue.getIssueType().getName())
Like Antoine Berry likes this
Aisha M
Contributor
May 13, 2019

@Antoine Berry  Thank you so much for the comment.

But for some reason, when I try to execute this, does not work, keeps loading and the status of the Bug remains as 'Ready to Accept" without showing a prompt that "Root cause required to accept a Bug in Production" (I filled as production and skipped the root cause, to test this out)

Antoine Berry
Community Champion
May 13, 2019

Hi @Aisha M ,

I just tried this script and it is working fine on my instance. Could you please tell me the exact types of these custom fields ? I am using Select List (single choice).

Also what are the logs displaying if you add 

log.error("bugEnvironmentValue.getValue() : " + bugEnvironmentValue.getValue()  )
log.error("rootCauseValue : " + rootCauseValue)

Antoine 

Aisha M
Contributor
May 13, 2019

@Antoine Berry  My instance keep loading when I change the status of the Bug. And then the page gets timed out.

So, I tried adding the below simplified script in my already existing validator SCRIPT(Scriptrunner)

def defectRootCause = GetCustomFieldValue(issue, "customfield_10107");
if (issueType == "Bug")
{
if (defectRootCause == null || defectRootCause.isEmpty())
{
errors.add("Defect Root Cause is required to accept this ${issueType}")
}
}

Can you please help with the code inclusion, for adding if Bug environment (ID 13098) is PRODUCTION then defect root cause is required. 

Aisha M
Contributor
May 13, 2019

@Antoine Berry  In addition to my above comment, The Bug environment is a radio button field of values - Production & Non-Production , and the Defect root cause is a drop down field 

Antoine Berry
Community Champion
May 14, 2019

Hi @Aisha M ,

Radio buttons returns the same object as single select list, so you should be able to use getValue(). What do you mean by drop down ? Could you please go into Custom Fields and tell me the type of defect root cause ?

Also, may you please provide your full script so I can debug more easily ? 

GetCustomFieldValue(issue, "customfield_10107");

is unlikely to work unless you have created a method inside your script.

Antoine

Aisha M
Contributor
May 14, 2019

@Antoine Berry  Defect root cause is a select list (single choice).

Below is a half of the code, hope it helps . . We just keep required field validators in the middle of the script & go on 

import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import org.apache.http.entity.StringEntity
import org.apache.log4j.Logger
import org.apache.log4j.Level
import groovy.json.*
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.CustomFieldManager
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue

import com.atlassian.jira.issue.customfields.view.CustomFieldParams
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.customfields.impl.CascadingSelectCFType

def log = Logger.getLogger("Shackles");
log.setLevel(Level.DEBUG);

def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
String currentUserId = "${currentUser.name}";
String currentUserRole = "";
String user = "Automation";
String pass = "noadminforsup";
String authHeader = "${user}:${pass}".bytes.encodeBase64();
def projectObject = issue.getProjectObject();

String projectName = projectObject.getName();
String projectKey = projectObject.getKey();
String issueType = issue.getIssueType().getName();

if (issueType == "Sub-task")
return;

def teamId = FindTeamId(projectKey, projectName, authHeader);
def map = new HashMap<String, String>();
def productOwners = new ArrayList<String>();
List<String> errors = new ArrayList<String>();

map = GetTeamMembers(teamId, authHeader);

for(item in map)
{
if (item.key == currentUserId)
currentUserRole = item.value;

if (item.value.contains("Product Owner"))
productOwners.add(GetUserDisplayName(item.key));
}

def acceptanceCriteria = GetCustomFieldValue(issue, "customfield_11800");
if (issueType == "Story")
{
if (acceptanceCriteria == null || acceptanceCriteria.isEmpty())
{
errors.add("Acceptance Criteria is required to accept this ${issueType}");
}
}

def defectRootCause = GetCustomFieldValue(issue, "customfield_10107");
if (issueType == "Bug")
{
if (defectRootCause == null || defectRootCause.isEmpty())
{
errors.add("Defect Root Cause is required to accept this ${issueType}")
}
}

Aisha M
Contributor
May 14, 2019

@Antoine Berry I hope the above snippet helps .  . I just want help with adding an ADD statement to the simplified script I had posted,

Like, If Bug Environment is PRODUCTION AND Defect Root Cause is EMPTY, then don't allow the bug to be Accepted (a status we have before DONE), if its NON PRODUCTION then no problem. 

Antoine Berry
Community Champion
May 14, 2019

I am a bit confused with your script. I guess you have created your own methods such as 

GetCustomFieldValue(issue, "customfield_10107");
GetTeamMembers(teamId, authHeader);

? Because out of the box it does not exist. I am not sure what you are doing with your productOwners object but I guess it you are using it later in the script. 

Anyway my advice would be to create a new validator in the transition for that part only (don't forget to replace the bug environment custom field id) : 

import com.atlassian.jira.component.ComponentAccessor
import com.opensymphony.workflow.InvalidInputException

def customFieldManager = ComponentAccessor.getCustomFieldManager()

int bugEnvironmentId = 10000
def bugEnvironment = customFieldManager.getCustomFieldObject(bugEnvironmentId)
def bugEnvironmentValue = issue.getCustomFieldValue(bugEnvironment)

int rootCauseId = 10107
def rootCause = customFieldManager.getCustomFieldObject(rootCauseId)
def rootCauseValue = issue.getCustomFieldValue(rootCause)
String issuetype = issue.getIssueType().getName()

if (issuetype == "Bug" && bugEnvironmentValue?.getValue() == "Production" && rootCauseValue == null){
def invalidInputException = new InvalidInputException("Root Cause is required to accept this " + issue.getIssueType().getName())
throw invalidInputException
}

And check in the transition that it executed without error. Also you can add some logs as I suggested above and check the log file when you are triggering the transition.

Antoine

Aisha M
Contributor
May 15, 2019

@Antoine Berry  Thank you so much for your constant help ! They didn't want the "If Production check", so I m just gonna be using the simplified script I had posted, as its working okay . .  Anyway, Will be marking your reply as an ANSWER for helping someone with a similar requirement. 

Like Antoine Berry likes this
Antoine Berry
Community Champion
May 15, 2019

You are very welcome ! Glad to know that the problem was fixed to your likings.

Like Aisha M likes this
Aisha M
Contributor
May 16, 2019

@Antoine Berry  Hi . .  Can you pleaseee have a look at my another query and give me your thoughts on that question. That would be so helpful. 

https://community.atlassian.com/t5/Marketplace-Apps-Integrations/How-to-update-Epic-link-based-on-a-custom-field-value-using-CLI/qaq-p/937258#M50096

0 votes
Tomas Gustavsson
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.
April 17, 2019

Below you have something similar to what you are asking for.
please also check https://community.atlassian.com/t5/Jira-questions/Re-How-to-copy-a-custom-field-to-all-linkedissues-based/qaq-p/1020043/comment-id/326946#M326946

 

 

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.event.type.EventDispatchOption

 

// Get a pointer to the issue
Issue issueKey = issue
// Get the current logged in user
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() as ApplicationUser
// Get access to the Jira comment and component manager
CommentManager commentManager = ComponentAccessor.getCommentManager()

// Get the customField Escalation level and it's value
def myCustomField = customFieldManager.getCustomFieldObject("customfield_12500")


// Get the last comment entered in on the issue to a String
def comment = "This issue is: " + myCustomField.getValue(issue)

def issueManager = ComponentAccessor.getIssueManager()
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def issueLinks = issueLinkManager.getInwardLinks(issueKey.getId())
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def subOutwardElements = issueLinks.findAll { it.issueLinkType.any()}

//def subOutwardElements = outwardIssueLinks.findAll { it.issueLinkType.inward.concat("is blocked by")}

//log.warn("Before for loop issueLinks.size() " + issueLinks.size())
log.warn("Before for loop myCustomField.toString( " + myCustomField.toString())

// Check if the issue is not null
if(issueKey){
// if customField Escalation level has a value
if (myCustomField.getValue(issue) != null && myCustomField.toString() == 'Escalation level' ) {
if (subOutwardElements.size() >= 0) {
for (def i = 0; i < subOutwardElements.size(); i++ ) {
log.warn("sourceId: ${i} ")
def linkedIssue = issueManager.getIssueObject(subOutwardElements[i].sourceId)
log.warn("Issue link type with name linkedIssue: ${linkedIssue} ")
log.warn("Issue link type with name myCustomField: ${myCustomField.getValue(issue)} ")

// Create a comment on the issue
// commentManager.create(issueKey, CurrentUser,comment, true)
// Set the value of the custom field
linkedIssue.setCustomFieldValue(myCustomField, myCustomField.getValue(issue))
// Update the issue
ComponentAccessor.getIssueManager().updateIssue(user, linkedIssue, EventDispatchOption.ISSUE_UPDATED, false)

}

}
}
}

Suggest an answer

Log in or Sign up to answer