Validator to enforce all linked issues in Epic to be closed before closing the Epic

Etai Leers
Contributor
June 26, 2022

Hi,
I got the following script (works) that makes sure all the linked issues to epic are closed.
If not the Epic cant get closed.
I want to limit it to a specific link type: ("Issues in Epic").

Does anyone know how to make it happen?

 

The code:

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.link.IssueLinkManager
import com.opensymphony.workflow.InvalidInputException
     
// Allow logging for debug and tracking purposes
import org.apache.log4j.Level
import org.apache.log4j.Logger
     
// Script code for easy log identification
String scriptCode = "Check all issues in Epics are Done -"
     
// Setup the log and leave a message to show what we're doing
Logger logger = log
logger.setLevel( Level.ERROR )
logger.debug( "$scriptCode Triggered by $issue.key" )

def passesCondition = true
if (issue.issueType.name == 'Epic')
   {
     IssueLinkManager issueLinkManager = ComponentAccessor.issueLinkManager
     def found = issueLinkManager.getOutwardLinks(issue.id).any
       {
       it?.destinationObject?.getStatus().getName() != 'Done' &&
           it?.destinationObject?.getIssueType().getName()  != 'Epic'
       }
       logger.debug( "$scriptCode Found =  $found " )
       if (found) {
           logger.debug( "$scriptCode return false" )
           passesCondition = false
           invalidInputException = new InvalidInputException("Please make sure all linked issues are in 'Done' status")
       } else {
           logger.debug( "$scriptCode return true" )
       passesCondition = true
       }
   }
// Always allow all other issue types to execute this transition
   else
   {
       logger.debug( "$scriptCode Not Epic return true")
       passesCondition = true
   }

 

2 answers

1 accepted

1 vote
Answer accepted
Andrea Pannitti
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.
June 26, 2022

Hi @Etai Leers,

from your last feedback, I think you could try changing in your original code the line:

def found = issueLinkManager.getOutwardLinks(issue.id).any

 with this:

def found = issueLinkManager.getOutwardLinks(issue.id).findAll { it.issueLinkType.name == 'Epic-Story Link' }.any
Etai Leers
Contributor
June 26, 2022

Unfortunately not working..

Andrea Pannitti
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.
June 26, 2022

Please could you run this in ScriptRunner Console:

import com.atlassian.jira.component.ComponentAccessor

def issue = ComponentAccessor.issueManager.getIssueObject("SAM-36")
ComponentAccessor.issueLinkManager.getOutwardLinks(issue.id).each { log.error it.issueLinkType.name }
and report here the logs?
Thanks
0 votes
Andrea Pannitti
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.
June 26, 2022

Hi @Etai Leers,

you could try changing this code:

{
it?.destinationObject?.getStatus().getName() != 'Done' &&
it?.destinationObject?.getIssueType().getName() != 'Epic'
}

with the following:

{
it?.destinationObject?.status.name != 'Done' &&
it?.destinationObject?.issueType.name != 'Epic' &&
it?.destinationObject?.description == 'Issues in Epic'
}

 

Etai Leers
Contributor
June 26, 2022

Now its not working it all :) 
(When I replace between the code snippets).

Andrea Pannitti
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.
June 26, 2022

Ok, and what happens if you replace with this:

{
it?.destinationObject?.status.name != 'Done' &&
it?.destinationObject?.issueType.name != 'Epic' &&
it?.sourceObject?.description == 'Issues in Epic'
}

?

Etai Leers
Contributor
June 26, 2022

Still not doing the desired behavior.

Andrea Pannitti
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.
June 26, 2022

Ok, I need more elements to help you.

Please, could you report what you see in the Issue Linking page (YOUR_JIRA_BASE_URL/secure/admin/ViewLinkTypes!default.jspa)?

In particular, the rows where you see 'Issues in Epic' (better if you attach an image).

Thanks

Etai Leers
Contributor
June 26, 2022

Actually, I don't see the link type in the Jira Issue Linking page.

Its that one:

image.png

Etai Leers
Contributor
June 28, 2022

@Andrea Pannitti knows how to make it works for "Issues in Epic"?

Andrea Pannitti
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.
June 28, 2022

@Etai Leers , yes, it's an outwardlink of type: 'Epic-Story Link'; for this reason, I asked you to report here the result of this script:

import com.atlassian.jira.component.ComponentAccessor

def issue = ComponentAccessor.issueManager.getIssueObject("SAM-36")
ComponentAccessor.issueLinkManager.getOutwardLinks(issue.id).each { log.error it.issueLinkType.name }

 

Etai Leers
Contributor
June 28, 2022

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Creating instance of bean 'com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Returning cached instance of singleton bean 'scriptRunnerImpl'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Returning cached instance of singleton bean 'configuredValidatorFactory' 2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Returning cached instance of singleton bean 'configuredObjectMapper'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Autowiring by type from bean name 'com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator' via constructor to bean named 'scriptRunnerImpl'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Autowiring by type from bean name 'com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator' via constructor to bean named 'configuredValidatorFactory'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Autowiring by type from bean name 'com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator' via constructor to bean named 'configuredObjectMapper'

2022-06-28 13:06:52,046 DEBUG [support.DefaultListableBeanFactory]: Finished creating instance of bean 'com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator'

2022-06-28 13:06:52,069 DEBUG [acme.ListLinks]: TEST

Etai Leers
Contributor
June 28, 2022

Payload:

@Andrea Pannitti 

{"canned-script""com.onresolve.scriptrunner.canned.jira.workflow.validators.CustomScriptValidator (java.lang.String)", "class.name": "com.onresolve.jira.groovy.GroovyValidator (java.lang.String)", "issue": "SAM-35 (com.atlassian.jira.issue.IssueImpl)", "transientVars": { "issue": "SAM-35 (com.atlassian.jira.issue.IssueImpl)", "configuration": "com.opensymphony.workflow.config.DefaultConfiguration@66b1b2fb", "proj": "Project: SAM (com.atlassian.jira.project.ProjectImpl)", "project": "[GenericEntity:Project][name,Sample][assigneetype,3][description,][projecttype,software][id,10600][counter,26][avatar,10324][originalkey,SAM][url,null][lead,automation4jira][key,SAM] (org.ofbiz.core.entity.GenericValue)", "currentSteps": "[SimpleStep@6[owner=, actionId=0, status=Done]] (java.util.ArrayList)", "store": "com.opensymphony.workflow.spi.ofbiz.OfbizWorkflowStore@e97f036", "descriptor": "com.atlassian.jira.workflow.ImmutableWorkflowDescriptor@48aede84", "userKey": "etai.leers (java.lang.String)", "originalAssigneeId": "null (org.codehaus.groovy.runtime.NullObject)", "entry": "com.opensymphony.workflow.spi.SimpleWorkflowEntry@20490f0c", "context": "com.opensymphony.workflow.basic.BasicWorkflowContext@d83d385", "originalissueobject": "SAM-35 (com.atlassian.jira.issue.IssueImpl)", "actionId": "31 (java.lang.Integer)", "pkey": "SAM (java.lang.String)", "transaction": "com.atlassian.jira.transaction.TransactionSupportImpl$TransactionImpl@7a95eec6" }, "log": "org.apache.log4j.Logger@2c8b3cf0", "originalIssue": "SAM-35 (com.atlassian.jira.issue.IssueImpl)", "invalidInputException": "null (org.codehaus.groovy.runtime.NullObject)", "\u00a3beanContext": "com.onresolve.scriptrunner.beans.BeanFactoryBackedBeanContext@698c9822" }

Andrea Pannitti
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.
June 28, 2022

@Etai Leers,

sorry, I meant what the reported script prints, once run from Script console?

Etai Leers
Contributor
June 28, 2022

Nope it runs from a workflow validator.
Once trying to make a transition from "In progress" status to "Done" status. 😊

@Andrea Pannitti 

Andrea Pannitti
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.
June 28, 2022

@Etai Leers,

The test I proposed above was to understand whether or not an issuelinktype called Epic-Story Link is present on the issue you try to validate.

Etai Leers
Contributor
June 29, 2022

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events