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}.")
}
}
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.