Forums

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

Unable to transition linked issue even when passing in correct parameter. (logs included)

Chris P_ July 9, 2020

Hello,

I'm trying to automatically transition issues that are:

- Are in the blocked status

- Has a linked issue blocking them that gets a "result" filled in

 

I'm running this as a listener on the update event.

 

Everything seems to be working fine except for the last step where it simply does not want to allow the transition.

Is the transition not happening for some reason due to it's not the event.issue? Figured I could pass in the right info and transition any issue.

Hoping someone has a simple solution.

 

 

2020-07-09 11:18:20,576 DEBUG [Script1935]: FieldName = Result
2020-07-09 11:18:20,578 DEBUG [Script1935]: 
            issueUpdatedTime = 09-7-2020 11:18:20
            fieldUpdateTime  = 09-7-2020 11:18:20
            Comparison Logic check:      true
2020-07-09 11:18:20,578 DEBUG [Script1935]: Result Field Change Detected so will begin checking if this issue was blocking anything.
2020-07-09 11:18:20,578 DEBUG [Script1935]: Started Check for Issues that are no longer blocked
2020-07-09 11:18:20,578 DEBUG [Script1935]: Issue result valid for checking to unblock issues. Value = Resolved
2020-07-09 11:18:20,580 DEBUG [Script1935]: Inward Links Found = [com.atlassian.jira.issue.link.IssueLinkImpl@3afca1e6[id=377833,sourceId=283954,destinationId=328050,issueLinkType=10200]]
2020-07-09 11:18:20,580 DEBUG [Script1935]: Outward Links Found = [com.atlassian.jira.issue.link.IssueLinkImpl@1a53e353[id=377834,sourceId=328050,destinationId=328041,issueLinkType=10001], com.atlassian.jira.issue.link.IssueLinkImpl@4703c4ed[id=377835,sourceId=328050,destinationId=328033,issueLinkType=10201]]
2020-07-09 11:18:20,582 DEBUG [Script1935]: Link Type ID found on blocked issue.
2020-07-09 11:18:20,583 DEBUG [Script1935]: blockedIssues = MAD-490
2020-07-09 11:18:20,583 DEBUG [Script1935]: Blocked issues found.
2020-07-09 11:18:20,584 DEBUG [Script1935]: Blocked Dest Issue Key = MAD-490 
2020-07-09 11:18:20,584 DEBUG [Script1935]: Blocked issue in blocked status, attempting to move it to Review.
2020-07-09 11:18:20,588 DEBUG [Script1935]: issueToTransition = MAD-490 
2020-07-09 11:18:20,588 DEBUG [Script1935]: currentUser = cpentz@ea.com(cpentz@ea.com) 
2020-07-09 11:18:20,588 DEBUG [Script1935]: issueToTransition.id = 328033 
2020-07-09 11:18:20,588 DEBUG [Script1935]: actionId = 261 
2020-07-09 11:18:20,591 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2020-07-09 11:18:20,591 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null
groovy.lang.MissingPropertyException: No such property: issueService for class: Script1935
	at Script1935$_checkForIssuesThatAreNoLongerBlocked_closure2.doCall(Script1935.groovy:171)
	at Script1935.checkForIssuesThatAreNoLongerBlocked(Script1935.groovy:136)
	at Script1935.run(Script1935.groovy:62)

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.changehistory.ChangeHistoryManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.history.ChangeItemBean
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.issue.IssueInputParametersImpl
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.IssueInputParametersImpl
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.workflow.WorkflowTransitionUtil
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.util.JiraUtils
import com.atlassian.jira.bc.issue.IssueService
import org.apache.log4j.Logger
import org.apache.log4j.Level
import java.text.SimpleDateFormat

def log = Logger.getLogger(getClass())
log.setLevel(Level.DEBUG)

// access the custom field manager & issue service
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
IssueService issueService = ComponentAccessor.getIssueService()
def optionsManager = ComponentAccessor.getOptionsManager()

 

/**
* Use as a listener with the "ISSUE UPDATED" event to copy the cl fixed field to critieria
*
* 1 - Check if the issue that was updated has links to criteria as is depended on by
* 2 - Check that the field we want to sync the value for was updated on this issue update event
* 3 - Find the relevant link types to either the parent or the child and then push the updated field value to the linked issue
* 4 - Make sure we only update the issues linked under a given link type and issue type
*/


Issue issue = event.issue as Issue
CustomField resultField = customFieldManager.getCustomFieldObject("customfield_14504")

if(! resultField){
log.debug("The Result Field you are looking for does not exist, check the id.")
return
}

Boolean hasFieldChanged = checkFieldHasBeenChanged(issue,resultField)

if(hasFieldChanged){

log.debug("Result Field Change Detected so will begin checking if this issue was blocking anything.")

checkForIssuesThatAreNoLongerBlocked(issue,resultField)
}

/**
*
* @Param issue - Issue that triggered Listener
* @Param customField - customField object we want to check if it was changed on this update
* @return boolean true if the field value was updated
*
*/
Boolean checkFieldHasBeenChanged(Issue issue, CustomField customField){

def log = Logger.getLogger(getClass())
log.setLevel(Level.DEBUG)

ChangeHistoryManager changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

String fieldName = customField.getName()
log.debug("FieldName = " + fieldName)

ChangeItemBean changeItem = changeHistoryManager.getChangeItemsForField(issue,fieldName).last()

// we will compare change issue update and field update times to the second, change the format if you want it to be to the minute
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-M-yyyy hh:mm:ss")

String issueUpdateTime = simpleDateFormat.format(issue.updated)
String fieldUpdateTime = simpleDateFormat.format(changeItem.created)
//defualt value is timestamp like 2019-09-14 20:18:16.823 and the value after the . can differ very slightly for the time the
//issue was updated versus the time the changehistory was updated.

log.debug("""
issueUpdatedTime = $issueUpdateTime
fieldUpdateTime = $fieldUpdateTime
Comparison Logic check: ${issueUpdateTime == fieldUpdateTime}""")

// if the update time of the field and the issue are to the same second then we assume the field was changed
// i do not check the actualy values changed. You would need to get the last change item and the one before to compare this
return issueUpdateTime == fieldUpdateTime

}

/**
* @Param issue - Issue that triggered Listener
* @Param fieldToCheck - CustomField Object for the field you want to update
*/
void checkForIssuesThatAreNoLongerBlocked(Issue issue, CustomField fieldToCheck){

def log = Logger.getLogger(getClass())
log.setLevel(Level.DEBUG)

log.debug("Started Check for Issues that are no longer blocked")

String linkTypeName = "Blocker"

def resultValue = issue.getCustomFieldValue(fieldToCheck)

if(resultValue.toString() == "Resolved" || resultValue == "Duplicate" || resultValue == "Invalid" || resultValue == "As Designed" || resultValue == "Suspect Fixed" || resultValue == "Archived") {
log.debug("Issue result valid for checking to unblock issues. Value = ${resultValue}")

IssueLinkTypeManager issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)
IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager()
ApplicationUser currentUser = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def linkTypes = issueLinkTypeManager.getIssueLinkTypes(false)
Long dependentLinkID = linkTypes.find { linkType ->
linkType.name == linkTypeName
}?.id

Collection<IssueLink> issueToDependentLinks = issueLinkManager.getInwardLinks(issue.id)
log.debug("Inward Links Found = ${issueToDependentLinks}")
Collection<IssueLink> dependentToIssueLinks = issueLinkManager.getOutwardLinks(issue.id)
log.debug("Outward Links Found = ${dependentToIssueLinks}")


dependentToIssueLinks.each { linkObject ->

if (linkObject.linkTypeId == dependentLinkID) {
log.debug("Link Type ID found on blocked issue.")

def blockedIssues = linkObject.destinationObject as MutableIssue
log.debug("blockedIssues = ${blockedIssues}")
if (blockedIssues) {
log.debug("Blocked issues found.")

def destIssueCurrentFieldValue = blockedIssues.getCustomFieldValue(fieldToCheck)

log.debug("Blocked Dest Issue Key = ${blockedIssues.key} ")

def blockedIssueStatus = blockedIssues.getStatusObject().getName();

////detect if destination issue has value already, if the values are already the same, do nothing
if (blockedIssueStatus != "Blocked") {
log.debug("Blocked issue is not in blocked status.")
}
else if (blockedIssueStatus == "Blocked") {
log.debug("Blocked issue in blocked status, attempting to move it to Review.")

// Review Transition ID in the Universal Workflow
def actionId = 261

def transitionValidationResult
def transitionResult
def issueToTransition = issueManager.getIssueObject(blockedIssues.key)
log.debug("issueToTransition = ${issueToTransition} ")
log.debug("currentUser = ${currentUser} ")
log.debug("issueToTransition.id = ${issueToTransition.id} ")
log.debug("actionId = ${actionId} ")

transitionValidationResult = issueService.validateTransition(currentUser, issueToTransition.id, actionId,new IssueInputParametersImpl())


if (transitionValidationResult.isValid()) {
transitionResult = issueService.transition(currentUser, transitionValidationResult)
if (transitionResult.isValid())
{ log.debug("Transitioned issue $issue through action $actionId") }
else
{ log.debug("Transition result is not valid") }
}
else {
log.debug("The transitionValidation is not valid")
}

}
}
}
}

}
else {
log.debug("The current Issue ${issue.key} does not have a value in the chosen custom field ${fieldToCheck.id}")
log.debug("The value of the result field in the current issue is ${resultValue}")
}

}

 



 

 

 

 

 

1 answer

1 accepted

0 votes
Answer accepted
Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 11, 2020

@Chris P_ it looks like you're initializing 

IssueService issueService = ComponentAccessor.getIssueService()

which is not available in method (is created with local visibility). Removal of its "type" IssueService should help. So change mentioned row to

issueService = ComponentAccessor.getIssueService()

Suggest an answer

Log in or Sign up to answer