Forums

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

Failing to transition my Epic story

Shelton Adams August 20, 2024

I am writing a script in Jira using ScriptRunner to transition our Epic based on the status of its child tasks I.E Story, Task, Sub Task. I believe I have my script the way I want it but my version of Jira 8.1.0 is not allowing me to utilize issueService or WorkflowTransitionUtil. I keep getting this error. I am in the process of moving us over to a newer version of Data Center but we are currently on a old standalone server version. My system info tells me i am using 8.1.0 so I believe IssueService and WorkflowTransitionUtil should work. 

Here is the error I am getting:


2024-08-20 16:32:17,478 ERROR [runner.ScriptBindingsManager]: Failed to transition Epic TESTGLE-3 to Design (SDP): No such property: issueService for class: Script398

I just feel it has something to do with my imports and maybe this outdated version possibly. 

Here is my Script:


import com.atlassian.jira.component.ComponentAccessor

import com.atlassian.jira.issue.Issue

import com.atlassian.jira.issue.MutableIssue

import com.atlassian.jira.issue.link.IssueLinkManager

import com.atlassian.jira.issue.CustomFieldManager

import com.atlassian.jira.issue.IssueManager

import com.atlassian.jira.workflow.IssueWorkflowManager

import com.atlassian.jira.workflow.WorkflowManager

import com.atlassian.jira.workflow.TransitionOptions

import org.apache.log4j.Logger

 

// Logger for debugging

def log = Logger.getLogger("com.example.TransitionScript")

 

// Initialize managers and components

def issueManager = ComponentAccessor.getIssueManager()

def issueLinkManager = ComponentAccessor.getIssueLinkManager()

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def issueService = ComponentAccessor.getIssueService()

def workflowManager = ComponentAccessor.getWorkflowManager()

def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

 

// Get the issue and its type

def issue = event.issue as MutableIssue

def issueType = issue.issueType.name

 

// Get the Epic Link custom field

def epicLinkField = customFieldManager.getCustomFieldObjectByName("Epic Link")

 

// Check if the issue is a Story, Task, or Sub-task and has an Epic Link

if (["Story", "Task", "Sub-task"].contains(issueType) && issue.getCustomFieldValue(epicLinkField)) {

    def epicLink = issue.getCustomFieldValue(epicLinkField) as Issue

    if (epicLink) {

        // Get all child issues linked to the Epic

        def childIssues = issueLinkManager.getOutwardLinks(epicLink.id)

            .findAll { it.issueLinkType.name == "Epic-Story Link" }

            .collect { it.destinationObject }

 

        // Get the status of all child issues

        def allStatuses = childIssues.collect { it.status.name }

 

        // Determine the lowest status

        def lowestStatus = allStatuses.min { status -> getStatusOrder(status) }

 

        // Transition the Epic to the lowest status

        if (lowestStatus) {

            transitionEpicToStatus(epicLink, lowestStatus)

        }

    }

}

 

// Helper function to map statuses to their order

def getStatusOrder(String status) {

    def statusMap = [

        "To Do (SDP)": 1,

        "Design (SDP)": 2,

        "Design Hold (SDP)": 3,

        "Design Review (SDP)": 4,

        "Working (SDP)": 5,

        "Working Hold (SDP)": 6,

        "Development Testing (SDP)": 7,

        "DevTest Hold (SDP)": 8,

        "Code Review (SDP)": 9,

        "CR Hold (SDP)": 10,

        "Integration Testing (SDP)": 11,

        "Integration Hold (SDP)": 12,

        "LWR in Progress (SDP)": 13,

        "LWR Hold (SDP)": 14,

        "Night Drive in Progress (SDP)": 15,

        "ND Hold (SDP)": 16,

        "Project Lead Review (SDP)": 17,

        "Done (SDP)": 18,

        "Requirement Scrub (SDP)": 19,

        "Rejected (SDP)": 20

    ]

    return statusMap[status] ?: 999 // Default high value for unknown statuses

}

 

// Function to transition the Epic to the desired status

def transitionEpicToStatus(Issue epic, String targetStatus) {

    def transitionMap = [

        "To Do (SDP)": 16,

        "Design (SDP)": 27,

        "Design Hold (SDP)": 29,

        "Design Review (SDP)": 26,

        "Working (SDP)": 5,

        "Working Hold (SDP)": 20,

        "Development Testing (SDP)": 18,

        "DevTest Hold (SDP)": 21,

        "Code Review (SDP)": 8,

        "CR Hold (SDP)": 23,

        "Integration Testing (SDP)": 6,

        "Integration Hold (SDP)": 22,

        "LWR in Progress (SDP)": 9,

        "LWR Hold (SDP)": 24,

        "Night Drive in Progress (SDP)": 10,

        "ND Hold (SDP)": 25,

        "Project Lead Review (SDP)": 11,

        "Done (SDP)": 15,

        "Requirement Scrub (SDP)": 28,

        "Rejected (SDP)": 14

    ]

 

    def transitionId = transitionMap[targetStatus]

 

    if (transitionId) {

        try {

            def transitionValidationResult = issueService.validateTransition(user, epic.id, transitionId, new HashMap<>())

            if (transitionValidationResult.isValid()) {

                def transitionResult = issueService.transition(user, transitionValidationResult)

                if (transitionResult.isValid()) {

                    log.info("Transitioned Epic ${epic.key} to ${targetStatus}.")

                } else {

                    log.error("Failed to transition Epic ${epic.key} to ${targetStatus}: ${transitionResult.errorCollection}")

                }

            } else {

                log.error("Transition validation failed for Epic ${epic.key} to ${targetStatus}: ${transitionValidationResult.errorCollection}")

            }

        } catch (Exception e) {

            log.error("Failed to transition Epic ${epic.key} to ${targetStatus}: ${e.message}")

        }

    } else {

        log.warn("No transition ID found for target status ${targetStatus}.")

    }

}

 

import com.atlassian.jira.component.ComponentAccessor

import com.atlassian.jira.issue.Issue

import com.atlassian.jira.issue.MutableIssue

import com.atlassian.jira.issue.link.IssueLinkManager

import com.atlassian.jira.issue.CustomFieldManager

import com.atlassian.jira.issue.IssueManager

import com.atlassian.jira.workflow.IssueWorkflowManager

import com.atlassian.jira.workflow.WorkflowManager

import com.atlassian.jira.workflow.TransitionOptions

import org.apache.log4j.Logger

 

// Logger for debugging

def log = Logger.getLogger("com.example.TransitionScript")

 

// Initialize managers and components

def issueManager = ComponentAccessor.getIssueManager()

def issueLinkManager = ComponentAccessor.getIssueLinkManager()

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def issueService = ComponentAccessor.getIssueService()

def workflowManager = ComponentAccessor.getWorkflowManager()

def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

 

// Get the issue and its type

def issue = event.issue as MutableIssue

def issueType = issue.issueType.name

 

// Get the Epic Link custom field

def epicLinkField = customFieldManager.getCustomFieldObjectByName("Epic Link")

 

// Check if the issue is a Story, Task, or Sub-task and has an Epic Link

if (["Story", "Task", "Sub-task"].contains(issueType) && issue.getCustomFieldValue(epicLinkField)) {

    def epicLink = issue.getCustomFieldValue(epicLinkField) as Issue

    if (epicLink) {

        // Get all child issues linked to the Epic

        def childIssues = issueLinkManager.getOutwardLinks(epicLink.id)

            .findAll { it.issueLinkType.name == "Epic-Story Link" }

            .collect { it.destinationObject }

 

        // Get the status of all child issues

        def allStatuses = childIssues.collect { it.status.name }

 

        // Determine the lowest status

        def lowestStatus = allStatuses.min { status -> getStatusOrder(status) }

 

        // Transition the Epic to the lowest status

        if (lowestStatus) {

            transitionEpicToStatus(epicLink, lowestStatus)

        }

    }

}

 

// Helper function to map statuses to their order

def getStatusOrder(String status) {

    def statusMap = [

        "To Do (SDP)": 1,

        "Design (SDP)": 2,

        "Design Hold (SDP)": 3,

        "Design Review (SDP)": 4,

        "Working (SDP)": 5,

        "Working Hold (SDP)": 6,

        "Development Testing (SDP)": 7,

        "DevTest Hold (SDP)": 8,

        "Code Review (SDP)": 9,

        "CR Hold (SDP)": 10,

        "Integration Testing (SDP)": 11,

        "Integration Hold (SDP)": 12,

        "LWR in Progress (SDP)": 13,

        "LWR Hold (SDP)": 14,

        "Night Drive in Progress (SDP)": 15,

        "ND Hold (SDP)": 16,

        "Project Lead Review (SDP)": 17,

        "Done (SDP)": 18,

        "Requirement Scrub (SDP)": 19,

        "Rejected (SDP)": 20

    ]

    return statusMap[status] ?: 999 // Default high value for unknown statuses

}

 

// Function to transition the Epic to the desired status

def transitionEpicToStatus(Issue epic, String targetStatus) {

    def transitionMap = [

        "To Do (SDP)": 16,

        "Design (SDP)": 27,

        "Design Hold (SDP)": 29,

        "Design Review (SDP)": 26,

        "Working (SDP)": 5,

        "Working Hold (SDP)": 20,

        "Development Testing (SDP)": 18,

        "DevTest Hold (SDP)": 21,

        "Code Review (SDP)": 8,

        "CR Hold (SDP)": 23,

        "Integration Testing (SDP)": 6,

        "Integration Hold (SDP)": 22,

        "LWR in Progress (SDP)": 9,

        "LWR Hold (SDP)": 24,

        "Night Drive in Progress (SDP)": 10,

        "ND Hold (SDP)": 25,

        "Project Lead Review (SDP)": 11,

        "Done (SDP)": 15,

        "Requirement Scrub (SDP)": 28,

        "Rejected (SDP)": 14

    ]

 

    def transitionId = transitionMap[targetStatus]

 

    if (transitionId) {

        try {

            def transitionValidationResult = issueService.validateTransition(user, epic.id, transitionId, new HashMap<>())

            if (transitionValidationResult.isValid()) {

                def transitionResult = issueService.transition(user, transitionValidationResult)

                if (transitionResult.isValid()) {

                    log.info("Transitioned Epic ${epic.key} to ${targetStatus}.")

                } else {

                    log.error("Failed to transition Epic ${epic.key} to ${targetStatus}: ${transitionResult.errorCollection}")

                }

            } else {

                log.error("Transition validation failed for Epic ${epic.key} to ${targetStatus}: ${transitionValidationResult.errorCollection}")

            }

        } catch (Exception e) {

            log.error("Failed to transition Epic ${epic.key} to ${targetStatus}: ${e.message}")

        }

    } else {

        log.warn("No transition ID found for target status ${targetStatus}.")

    }

}

0 answers

Suggest an answer

Log in or Sign up to answer