Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Celebration

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,556,749
Community Members
 
Community Events
184
Community Groups

Scriptrunner post-function script failing intermittently on defect creations - NullPointerException

Hi Adaptavist Gurus,

We created a custom post-function Groovy script a little over a year ago that we use in certain project defect transition workflows.

The script was working consistently to use 2 custom field values to set the defect priority.

It now is failing intermittently on defect creation only. I have tried to reproduce it consistently. On our test server I modified the script version to try to add some logging to help me debug the issue, but I am not a coder and what I added and how/where I did it did end up being helpful. 

The failure rate of the script is higher now than it was before our recent upgrade and is project specific. Some projects it very rarely fails while others, it is failing more than it succeeds.

The update defect post function code is very similar, and it does not ever fail.

Here is a runtime error for a specific issue (defect) and project where the script failed:

2020-05-01 09:59:03,945 WARN [workflow.AbstractScriptWorkflowFunction]: Not able to get priority for new defect. Leaving priority not set (default).
2020-05-01 09:59:03,946 ERROR [workflow.AbstractScriptWorkflowFunction]: *************************************************************************************
2020-05-01 09:59:03,946 ERROR [workflow.AbstractScriptWorkflowFunction]: Script function failed on issue: DFP-3889, actionId: 1, file: /data/jira-home/scripts/CreatePriorityPostScriptPOCv2.groovy
java.lang.NullPointerException: Cannot get property 'id' on null object
	at CreatePriorityPostScriptPOCv2.run(CreatePriorityPostScriptPOCv2.groovy:94)


Here is payload:

{
    "full.module.key": "com.onresolve.jira.groovy.groovyrunnerrungroovy-function (java.lang.String)",
    "canned-script": "com.onresolve.scriptrunner.canned.jira.workflow.postfunctions.CustomScriptFunction (java.lang.String)",
    "class.name": "com.onresolve.jira.groovy.GroovyFunctionPlugin (java.lang.String)",
    "issue": "DFP-3889 (com.atlassian.jira.issue.IssueImpl)",
    "passesCondition": "true (java.lang.Boolean)",
    "transientVars": {
        "entry": "com.opensymphony.workflow.spi.SimpleWorkflowEntry@53a846f6",
        "issue": "DFP-3889 (com.atlassian.jira.issue.IssueImpl)",
        "configuration": "com.opensymphony.workflow.config.DefaultConfiguration@793ce9de",
        "context": "com.opensymphony.workflow.basic.BasicWorkflowContext@43305764",
        "createdStep": "SimpleStep@2[owner=, actionId=0, status=open] (com.opensymphony.workflow.spi.SimpleStep)",
        "originalissueobject": "null (org.codehaus.groovy.runtime.NullObject)",
        "actionId": "1 (java.lang.Integer)",
        "currentSteps": "[SimpleStep@2[owner=, actionId=0, status=open]] (java.util.ArrayList)",
        "store": "com.opensymphony.workflow.spi.ofbiz.OfbizWorkflowStore@db4af2a",
        "descriptor": "com.atlassian.jira.workflow.ImmutableWorkflowDescriptor@348cd251"
    },
    "log": "org.apache.log4j.Logger@2e44aced"
}



Below is the script: Line 94 which is the supposed culprit is in bold. Any help greatly appreciated!

// Set a priority using Post-function script on defect create
// Changes the priority of an issue depending on 2 other custom fields (severity and business impact ("bizimpact") with Script Runner
// Map this to issue creation transition - needs to be LAST post-function
// useful reference: https://community.atlassian.com/t5/Answers-Developer-Questions/How-to-change-issue-priority-with-script-runner-groovy/qaq-p/478700
// last updated: 1/25/2019 based on pilot feedback

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.priority.Priority;
import com.atlassian.jira.issue.IssueInputParametersImpl;
import com.atlassian.jira.issue.customfields.option.Option;


// Get the current Issue
Issue issue = issue

// Get the Manager classes required
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def commentManager = ComponentAccessor.getCommentManager()
def constantsManager = ComponentAccessor.getConstantsManager()
def issueService = ComponentAccessor.getIssueService()


// Get a pointer to the current logged in user
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()


// Get objects and values for relevant fields associated with the specific issue
// Found you have to explicitly cast the field values as strings for script to work

def bizimpactObject = customFieldManager.getCustomFieldObject("customfield_13402")
def severityObject = customFieldManager.getCustomFieldObject("customfield_13402")

def bizimpact = issue.getCustomFieldValue(customFieldManager.getCustomFieldObject("customfield_13402"));
bizimpact = bizimpact.toString()
def severity = issue.getCustomFieldValue(customFieldManager.getCustomFieldObject("customfield_10201"));
severity = severity.toString()

// for debugging get current issue priority values to compare
// def OrigPriority = issue.getPriorityObject().getName()
// OrigPriority = OrigPriority.toString()
// def OrigPriorityID = issue.getPriorityObject().getId()


// use priorityMatrix below as map. Has linked pair value combinations of severity, and business impact values to priority keeping code in for doc purposes only in this version
// Key at far left is severity and second dimension key is the bizimpact. These values as keys and function returns priority name (in quotes)

def priorityMatrix =
[
Blocker: [Highest: "P0 - Urgent", Significant: "P1 - High" , Average: "P1 - High", Minimal: "P2 - Medium-High"],
Major: [Highest: "P1 - High", Significant: "P2 - Medium-High", Average: "P3 - Medium-Low", Minimal: "P4 - Low"],
Minor: [Highest:"P2 - Medium-High" , Significant: "P3 - Medium-Low" , Average: "P4 - Low", Minimal: "P4 - Low"],
Trivial: [Highest:"P3 - Medium-Low" , Significant: "P3 - Medium-Low" , Average: "P4 - Low", Minimal: "P4 - Low"],
]

// use map lookup method to calculate priority and leave default value of Not Set if map is broken
def CalcPriority = "Not Set"
if (priorityMatrix.containsKey(severity) && priorityMatrix.find{bizimpact} != null)
{
CalcPriority = priorityMatrix[severity][bizimpact]
}
else {
log.warn "Business or Severity field selected not in matrix."
}
CalcPriority = CalcPriority.toString()
// once you have looked up the calculated priority name in the matrix, get the associated priority object based on the name

def CalcPriorityObject = constantsManager.priorityObjects.findByName(CalcPriority)

// initialize some messages with default values
def msg1 = "No Special Message."
def errmsg = "No Errors."

// check lookup of priority by name
if (CalcPriorityObject)
{
// msg1 = "Valid priority object found."
log.debug("Able to find priority based on lookup.")
}
else{
// msg1 = "Priority object not found, so leaving priority at current value."
log.warn("Not able to get priority for new defect. Leaving priority not set (default).")
}

// for debugging create a string you can write to issue comments
// def stringbody = "Current Values of Business Impact, Severity, Original Priority, Original Priority ID, New Derived Priority, New Priority ID: \n" + bizimpact + ", " + severity + ", " + OrigPriority + ", " + CalcPriority.toString() + ", " + OrigPriorityID.toString() + ", " + msg1.toString()

// this is start of code to actually set field value based on id of the Calculated priority value on the create transition only.
// first create object to hold all parameters to pass into the issue service for new issue creation
def issueInputParameters = new IssueInputParametersImpl();

issueInputParameters.setPriorityId(CalcPriorityObject.id);
issueInputParameters.setSkipScreenCheck(true);

// validate object

def validationResult = issueService.validateUpdate(user, issue.id, issueInputParameters);

if (validationResult.isValid())
{
// actually update the issue and store to db
issueService.update(user, validationResult)


// next section is for debugging - writes to comments
// errmsg = "validation succeeded. check priority. should be updated. " + issueInputParameters
// stringbody = stringbody + ", " + errmsg.toString()
// commentManager.create(issue,user,stringbody,true)
}
else {
// log warning
log.warn validationResult.errorCollection.errors
// errmsg = "could not update priority field. check logs."
// stringbody = stringbody + ", " + errmsg.toString()
// commentManager.create(issue,user,stringbody,true)
}

1 answer

0 votes
Lasse Langhorn
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 05, 2020

Hi @djohnsoncainc

Please test this code first on your test instance. I did some minor adjustments to the code.

  • Added guard for CalcPriorityObject
  • Used constantsManager.priorities instead of constantsManager.priorityObjects (deprecated) 
// Set a priority using Post-function script on defect create
// Changes the priority of an issue depending on 2 other custom fields (severity and business impact ("bizimpact") with Script Runner
// Map this to issue creation transition - needs to be LAST post-function
// useful reference: https://community.atlassian.com/t5/Answers-Developer-Questions/How-to-change-issue-priority-with-script-runner-groovy/qaq-p/478700
// last updated: 1/25/2019 based on pilot feedback

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.priority.Priority;
import com.atlassian.jira.issue.IssueInputParametersImpl;
import com.atlassian.jira.issue.customfields.option.Option;


// Get the current Issue
Issue issue = issue

// Get the Manager classes required
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def commentManager = ComponentAccessor.getCommentManager()
def constantsManager = ComponentAccessor.getConstantsManager()
def issueService = ComponentAccessor.getIssueService()


// Get a pointer to the current logged in user
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()


// Get objects and values for relevant fields associated with the specific issue
// Found you have to explicitly cast the field values as strings for script to work

def bizimpactObject = customFieldManager.getCustomFieldObject("customfield_13402")
def severityObject = customFieldManager.getCustomFieldObject("customfield_13402")

def bizimpact = issue.getCustomFieldValue(customFieldManager.getCustomFieldObject("customfield_13402"));
bizimpact = bizimpact.toString()
def severity = issue.getCustomFieldValue(customFieldManager.getCustomFieldObject("customfield_10201"));
severity = severity.toString()

// for debugging get current issue priority values to compare
// def OrigPriority = issue.getPriorityObject().getName()
// OrigPriority = OrigPriority.toString()
// def OrigPriorityID = issue.getPriorityObject().getId()


// use priorityMatrix below as map. Has linked pair value combinations of severity, and business impact values to priority keeping code in for doc purposes only in this version
// Key at far left is severity and second dimension key is the bizimpact. These values as keys and function returns priority name (in quotes)

def priorityMatrix =
[
Blocker: [Highest: "P0 - Urgent", Significant: "P1 - High" , Average: "P1 - High", Minimal: "P2 - Medium-High"],
Major: [Highest: "P1 - High", Significant: "P2 - Medium-High", Average: "P3 - Medium-Low", Minimal: "P4 - Low"],
Minor: [Highest:"P2 - Medium-High" , Significant: "P3 - Medium-Low" , Average: "P4 - Low", Minimal: "P4 - Low"],
Trivial: [Highest:"P3 - Medium-Low" , Significant: "P3 - Medium-Low" , Average: "P4 - Low", Minimal: "P4 - Low"],
]

// use map lookup method to calculate priority and leave default value of Not Set if map is broken
def CalcPriority = "Not Set"
if (priorityMatrix.containsKey(severity) && priorityMatrix.find{bizimpact} != null) {
CalcPriority = priorityMatrix[severity][bizimpact]
} else {
log.warn "Business or Severity field selected not in matrix."
}
CalcPriority = CalcPriority.toString()
// once you have looked up the calculated priority name in the matrix, get the associated priority object based on the name

def CalcPriorityObject = constantsManager.priorities.findByName(CalcPriority)

// initialize some messages with default values
def msg1 = "No Special Message."
def errmsg = "No Errors."

// check lookup of priority by name
if (CalcPriorityObject) {
def issueInputParameters = new IssueInputParametersImpl()
issueInputParameters.setPriorityId(CalcPriorityObject.id)
issueInputParameters.setSkipScreenCheck(true)
def validationResult = issueService.validateUpdate(user, issue.id, issueInputParameters)
if (validationResult?.isValid()) {
issueService.update(user, validationResult)
} else {
log.warn("Validation errors: $validationResult?.errorCollection?.errors")
}
log.debug("Able to find priority based on lookup.")
} else {
log.warn("Not able to get priority for new defect. Leaving priority not set (default).")
}

// for debugging create a string you can write to issue comments
// def stringbody = "Current Values of Business Impact, Severity, Original Priority, Original Priority ID, New Derived Priority, New Priority ID: \n" + bizimpact + ", " + severity + ", " + OrigPriority + ", " + CalcPriority.toString() + ", " + OrigPriorityID.toString() + ", " + msg1.toString()

// this is start of code to actually set field value based on id of the Calculated priority value on the create transition only.
// first create object to hold all parameters to pass into the issue service for new issue creation

Regards

Lasse Langhorn

Thank you so very much, Lasse. Will check it out and let you know!
Donna

HI @Lasse Langhorn 
Everything works as expected on our test server after I made suggested changes. I appreciate your improvements. That said, I have not been able recently to recreate the defect condition with current code on our test environment, so will have to wait to see if these changes resolve the issue. I will reply again in another few weeks if problem is no longer observable after we promote change to production server.

Hi @Lasse_Langhorn We have now been running the changed code for several weeks and still have the same issue noted here. It is intermittent and not reproducible under normal usage conditions. Appears to be some kind of race condition. Thank you for the updates, nonetheless, as it was good for me to replace deprecated methods.

Sincerely,

Donna

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events