Forums

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

Scriptrunner not identifying changes in custom dropdown fields.

NSEU DevOps March 26, 2025 edited

Hello,

I am developing a piece of code to take three inputs. This is then applied to a listener that looks at "Issue Created" or "Issue Updated" events.


The inputs are as follows:
Original Estimate (from the time tracking field)
Impact (Dropdown list with options "Low" and "High")
Severity (Dropdown list with three options "Minor", "Major" and "Critical")

The output is as follows:
Revised Estimate (Text (Single Line)).

What I want it to do:
Takes original estimate
Depending on value of Impact and Severity - Apply a frig factor 
Output Estimate + impact and Severity hours to a field called "Revised Estimate"

What I've got working:
Original estimate is captured and then converted to a string (By changing the seconds value of Original estimate into h,m,d,m,y format). This works on its own. Yes I probably did this quite inefficently... But its the only way I could work out how to get this to work on one coffee :).

What I can't get to work:
Impact and Severity fields applying the frig factor and add them to "Revised Estimate"

I have pasted my code below. Please bear in mind, I am relatively inexperienced with Scriptrunner.

import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger

def log = Logger.getLogger("com.onresolve.scriptrunner.canned.jira.workflow.listeners.CustomListener")

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def originalEstimateField = customFieldManager.getCustomFieldObjectByName('Original Estimate')
def revisedEstimateField = customFieldManager.getCustomFieldObjectByName('Revised Estimate')
def impactField = customFieldManager.getCustomFieldObjectByName('Impact')
def severityField = customFieldManager.getCustomFieldObjectByName('Severity')

def originalEstimate = event.issue.getOriginalEstimate() // Original Estimate in seconds
def revisedEstimateStr = event.issue.getCustomFieldValue(revisedEstimateField) as String
def impactOption = event.issue.getCustomFieldValue(impactField)
def severityOption = event.issue.getCustomFieldValue(severityField)

log.info("Original Estimate: ${originalEstimate}")
log.info("Revised Estimate (String): ${revisedEstimateStr}")
log.info("Impact Option: ${impactOption}")
log.info("Severity Option: ${severityOption}")

// Extract the actual values from the options
def impact = impactOption ? impactOption.getValue() : null
def severity = severityOption ? severityOption.getValue() : null

log.info("Impact: ${impact}")
log.info("Severity: ${severity}")

// Convert revised estimate string to numeric value (seconds)
def revisedEstimate = revisedEstimateStr ? revisedEstimateStr.toDouble() : 0

log.info("Revised Estimate (Numeric): ${revisedEstimate}")

// Ensure original estimate is not null
if (originalEstimate != null && impact != null && severity != null) {
    def impactCoefficient = 1.6
    def severityCoefficient = 2.4

    def additionalEstimate = (impactCoefficient * impact.toInteger() + severityCoefficient * severity.toInteger()) * 3600 // Convert hours to seconds
    def newRevisedEstimate = originalEstimate + additionalEstimate

    log.info("New Revised Estimate: ${newRevisedEstimate}")

    def issueManager = ComponentAccessor.getIssueManager()
    def mutableIssue = issueManager.getIssueObject(event.issue.id)
    mutableIssue.setCustomFieldValue(revisedEstimateField, formatTime(newRevisedEstimate))
    issueManager.updateIssue(event.user, mutableIssue, com.atlassian.jira.event.type.EventDispatchOption.DO_NOT_DISPATCH, false)

    // Log the updated value
    def updatedRevisedEstimateStr = mutableIssue.getCustomFieldValue(revisedEstimateField) as String
    log.info("Updated Revised Estimate (String): ${updatedRevisedEstimateStr}")
} else {
    log.warn("Original Estimate is null: ${originalEstimate == null}")
    log.warn("Impact is null: ${impact == null}")
    log.warn("Severity is null: ${severity == null}")
}

// Helper function to format time in seconds to human-readable format
def formatTime(seconds) {
    def units = [
        [unit: 'y', value: 60 * 60 * 24 * 365],
        [unit: 'm', value: 60 * 60 * 24 * 30],
        [unit: 'd', value: 60 * 60 * 24],
        [unit: 'h', value: 60 * 60],
        [unit: 'm', value: 60]
    ]

    def result = []
    def remainingSeconds = seconds

    units.each { unit ->
        def unitValue = (remainingSeconds / unit.value).intValue()
        if (unitValue > 0) {
            result << "${unitValue}${unit.unit}"
            remainingSeconds -= unitValue * unit.value
        }
    }

    if (remainingSeconds > 0) {
        result << "${remainingSeconds}s"
    }

    return result.join(' ')
}

Test Case:
Ticket created and Original Estimate is added (2hrs).
Ticket then processed through the workflow until "Impact" and "Severity" fields need to be set.

Result:

Remaining Estimate remains at "none"

What to the logs say:
 
2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Original Estimate is null: false

2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Impact is null: true


2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Severity is null: true

The script is clearly ignoring the "Impact" and "Severity" fields. 

Any help would be appreciated.

Thanks

1 answer

1 vote
Stefan Stadler
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.
March 28, 2025

Hi @NSEU DevOps

It appears that there is something just not 100% correct and therefore some operation is failing. 

You mentioned, this reacts on Issue Created and Issue Updated events. However, you have also mentioned that you passed the issue through the workflow. When is the custom field value set? Do you do it manually in the Edit screen? 

Anyway: I would like to see the output of the listener first logging statements. They are set to Info, so they might not be shown. I have therefore adjusted the statements slightly (just for testing purposes and also added the event for debugging:

log.warn("Event: ${event.toString()}")
log.warn("Original Estimate: ${originalEstimate}") log.warn("Revised Estimate (String): ${revisedEstimateStr}") log.warn("Impact Option: ${impactOption}") log.warn("Severity Option: ${severityOption}")

 Can you please let us know the output of this?

This might help us better understand the root cause here.

Thanks!

Stefan

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
SERVER
VERSION
9.12.14
TAGS
atlassian, atlassian government cloud, fedramp, webinar, register for webinar, atlassian cloud webinar, fedramp moderate offering, work faster with cloud

Unlocking the future with Atlassian Government Cloud ☁️

Atlassian Government Cloud has achieved FedRAMP Authorization at the Moderate level! Join our webinar to learn how you can accelerate mission success and move work forward faster in cloud, all while ensuring your critical data is secure.

Register Now
AUG Leaders

Atlassian Community Events