Check for duplicates link in Groovy transition validation script

Robert Poldervaart February 19, 2013

I have a transition called "Close as Duplicate" that allows the user to link an issue, and the post function automatically sets the status to closed and resolution to duplicate. I would like to enforce that a link either already exists or is being added in the current transition with the link_type = "duplicates".

I tried this before and found that I can examine already existing links, but the code looking at the existing links didn't find a link that was being added in the current transtion.

Can this be done in a Groovy transition validation script?

Thanks,
Robert

9 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

0 votes
Answer accepted
Robert Poldervaart February 20, 2013

Thank you Henning and Jamie!

Below is the implementation as a simple script validator,.

linkCnt = 0

request = webwork.action.ActionContext.getRequest()
if (request) {
    // check for new duplicates link 
    linktype = request.getParameter('issuelinks-linktype')
    linkedIssue = request.getParameter('issuelinks-issues')
    if (linktype == 'duplicates' && linkedIssue) linkCnt = 1
}

// check for existing duplicates link
if ( issueLinkManager.getOutwardLinks(issue.getId())*.issueLinkType.name.contains('Duplicate') ) linkCnt += 1

// Transition requires one, and only one, duplicates link
(linkCnt==1)

1 vote
Henning Tietgens
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.
February 20, 2013

You could use the request to get the information with this Simple scripted validator condition:

request = webwork.action.ActionContext.getRequest()
linktype = request.getParameter('issuelinks-linktype')
linkedIssue = request.getParameter('issuelinks-issues')
(linktype == 'duplicates' && linkedIssue)

Henning

JamieA
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.
February 20, 2013

Good call but check for nulls! There won't be a request when transition is executed through a service for instance, and possibly not when through the REST API.

JamieA
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.
February 20, 2013

I have blown myself up before assuming there will always be a request... so the above is from bitter experience.

Henning Tietgens
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.
February 20, 2013

Ok, good note. Robert should combine this (incl. null checks) with looking for already existing links and if none of both ways results in an existing link the validator should return false.

Bryan Karsh
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.
April 7, 2014

Hi Henning,

Question -- I am using this validator to verify that there is a link of key "RFC" associated with an issue.

How would I modify your webwork action validator example to include a check for links added during a workflow transition screen?

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.link.IssueLink;
 
Issue issue = issue;

String result = '';
Collection<IssueLink> olinks = ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.getId());
Collection<IssueLink> ilinks = ComponentAccessor.getIssueLinkManager().getInwardLinks(issue.getId());
Collection<IssueLink> links = olinks + ilinks;

for(IssueLink il : links){
  result += il.getSourceObject().getProjectObject().getKey()
  result += il.getDestinationObject().getProjectObject().getKey()
  
  if(result.contains("RFC")){
     return true;

//return result
    }
}

Bryan Karsh
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.
April 8, 2014

Actually, I figured it out -- this works (though suggestions on improving code always welcome!):

import com.atlassian.jira.component.ComponentAccessor
import webwork.action.ActionContext
import com.atlassian.jira.issue.link.IssueLink;


// check for existing RFC links

String result = '';
Collection<IssueLink> olinks = ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.getId());
Collection<IssueLink> ilinks = ComponentAccessor.getIssueLinkManager().getInwardLinks(issue.getId());
Collection<IssueLink> links = olinks + ilinks;

for (IssueLink il : links) {
result += il.getSourceObject().getProjectObject().getKey()
result += il.getDestinationObject().getProjectObject().getKey()

if (result.contains("RFC")) {
return true;
}
}


// check for new RFC link
def request = ActionContext.getRequest()
if (request) {

linkedIssue = request.getParameter('issuelinks-issues')

if (linkedIssue.contains("RFC")) {
return true;
}
}


0 votes
HarryH
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.
February 29, 2016

The validator script doesn't work at create transition because it reads out the null  issueLinkTypes object.

We can use "Boolean validator with math, date-time or text-string terms' Validator for this transitior" validator instead.

For example:

 

count(linkedIssues("Duplicate"))>0

0 votes
Thomas Heidenreich
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.
July 3, 2014

I added some imports and calls not to rely on names, but only on IDs:

import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.link.IssueLinkTypeManager

def typeManager = (IssueLinkTypeManager)ComponentManager.getComponentInstanceOfType(IssueLinkTypeManager.class);
def linkCnt = 0
def duplicateLinkId = '10002'
 
request = webwork.action.ActionContext.getRequest()
if (request) {
    // check for new duplicates link 
    linktype = request.getParameter('issuelinks-linktype')
    linkedIssue = request.getParameter('issuelinks-issues')
    if (typeManager.getIssueLinkTypesByOutwardDescription(linktype).id.toString().contains(duplicateLinkId)  &amp;&amp; linkedIssue) linkCnt = 1
}
 
// check for existing duplicates link
if ( issueLinkManager.getOutwardLinks(issue.getId())*.issueLinkType.id.toString().contains(duplicateLinkId) ) linkCnt += 1
 
// Transition requires one, and only one, duplicates link
(linkCnt&gt;0)

0 votes
Robert Poldervaart February 20, 2013

Thanks for the tweaks. I'm using 4.4.4 and it looks like getIssueLinkManager is not available from ComponentAccessor in 4.4. But I'll keep it in a comment for when we upgrade.

0 votes
JamieA
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.
February 20, 2013

There's no down sides to putting it in a file. You can add it pretty much as you have it already, except add:

def issueLinkManager = ComponentAccessor.getIssueLinkManager()

> what import do I need for webwork getRequest()?

Henning did the fully-qualified class... you could do:
import webwork.action.ActionContext
def request = ActionContext.getRequest()

0 votes
Robert Poldervaart February 20, 2013

And now that I've got the simple scripted validator working, since I have this "close as duplicate" transition in three places in the workflow, I think I'd like to put the script in a file, and put the path in the validator, instead of duplicating the simple script.

What imports do I need to accomplish this? I know I need:

import com.opensymphony.workflow.InvalidInputException

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

import com.atlassian.jira.ComponentManager

what import do I need for webwork getRequest()?

Are there any downsides such as performance to putting the script in a file versus using a simple scripted validator?
Thanks,
Robert
As a script in a file::
import org.apache.log4j.Category
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.ComponentManager
log = Category.getInstance("com.onresolve.jira.groovy.example.testValidator")
log.setLevel(org.apache.log4j.Level.DEBUG)
log.debug("Condition testValidator script running")
ComponentManager componentManager = ComponentManager.getInstance()
IssueLinkManager issueLinkManager = componentManager.getIssueLinkManager()
linkCnt = 0
request = webwork.action.ActionContext.getRequest()
if (request) {
// check for new duplicates link
linktype = request.getParameter('issuelinks-linktype')
linkedIssue = request.getParameter('issuelinks-issues')
if (linktype == 'duplicates' && linkedIssue) linkCnt = 1
}
// check for existing duplicates link
if ( issueLinkManager.getOutwardLinks(issue.getId())*.issueLinkType.name.contains('Duplicate')) linkCnt += 1
// Transition requires one, and only one, duplicates link
if (linkCnt!=1) invalidInputException = new InvalidInputException("Close as Duplicate requires One, and only One, 'duplicates' link type. Do not use 'is duplicated by'.")
0 votes
Robert Poldervaart February 20, 2013

Thank you Henning and Jamie!

I implemented the following as a simple scripted validator in a test transition and it seems to work. I want to require one, and only one, duplicates link during this transition. Please let me know if you see any other null or error checking that I should to do to this. Thanks again!!

linkCnt = 0

request = webwork.action.ActionContext.getRequest()
if (request) {
    // check for new duplicates link 
    linktype = request.getParameter('issuelinks-linktype')
    linkedIssue = request.getParameter('issuelinks-issues')
    if (linktype == 'duplicates' && linkedIssue) linkCnt = 1
}

// check for existing duplicates link
if ( issueLinkManager.getOutwardLinks(issue.getId())*.issueLinkType.name.contains('Duplicate') ) linkCnt += 1

// Transition requires one, and only one, duplicates link
(linkCnt==1)
0 votes
Christian Czaia _Decadis AG_
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.
February 19, 2013

I guess Jamies script runner could accomplish this. It ships with a built-in scripted validator called:

Has at least one outward duplicate link

You should give it a try...Hope that helps

Cheers Christian

Robert Poldervaart February 19, 2013

I can't find my code right now, but I did try this before. I need to try it again to be sure. But I think it worked if the link already existed. But if the link was being added during the transition, then it didn't find the link.

Thanks for the input.

Robert

Christian Czaia _Decadis AG_
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.
February 19, 2013
Robert Poldervaart February 19, 2013

Good link. Basically the same problem I am having. Thier conversation ended about the same point; trying to check for a link that was created created, but not yet committed to the database yet. They were trying to check for a link on the create issue step, so no existing link, but checking for a new link.

Robert Poldervaart February 19, 2013

I'm wondering if I need to do something with transientVars and changeitems to see values before they are committed.

JamieA
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.
February 20, 2013

I'm not sure this is possible... looking at the source of IssueLinkManager, all the methods to get the links involve looking up records in the database. In a validator they're not written yet.

If it's not in the transientVars, then it may not be possible. This would be true of a plugin written in java as well as script runner.

JamieA
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.
February 20, 2013

Yeah... I had a look at this. You need access to the fieldValuesHolder and I'm not sure how you get at this from a validator. I think in the past I may have recommended that you fail validation with a message to the user to add the link before doing the transition. Historically this was never a problem because you couldn't put issue links on the screen, therefore this couldn't happen.

Robert Poldervaart February 20, 2013

Bummer. Thanks Jamie and Christian for the help. Do you think this is possible with the Behaviours plug-in?

AKASHB July 24, 2013

Hey All, what if i want to create link between two issues, After doing research i came to conclusion that, i can use


linkManager.createIssueLink(issue.getId(),opt.getId(),issueLinkTypes.getAt(1),1,currentUser)

but its showing incomptability issues.

So any help or suggestions?

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

TAGS
AUG Leaders

Atlassian Community Events