ScriptRunner Clone Issue - avoid doubles

Simon Krautwig January 13, 2020

Hi Community,

I am using ScriptRunner for the first time, have no previous programming experience and am working on using the function "Clones an Issue, and links". I added the function as a post function in the workflow when a defined status was reached.

The issue should be cloned into the second project, in addition a link to the source issue and a comment added with a defined text and by who the action was triggered.

These actions also work, but I am attached to the problem that if the issue has already been cloned once, a status change of the issue will clone it a second time. But if it has already been cloned once, it cannot be cloned a second time. I want to avoid duplicate clones.

For this I have created a CustomField, which I read out in the condition and, if necessary, set in the Additional issue action. I am stuck here and hope for your support.

I have already searched through some documentation, but have not yet come up with the right result.

Any idea what is wrong here?

 

On the screenshot you can see that whenever the ticket is opened and closed again, a clone is created several times and the custom field is not changed.

CollectionTest.pngcustomfield.png

 

 

The code is as following:

Condition: 

import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.CustomFieldManager;

//cfValues['Clone']?.value != "Yes"
//cfValues['Clone']*.value.contains("Yes")
if (cfValues['Clone']*.value.contains("Yes")) {
return false
} else {
return true
}

def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
! changeHistoryManager.getAllChangeItems(issue).find {
it.field == "Done"
}

 

Additional issue actions:

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.fields.config.FieldConfig

def optionsManager = ComponentAccessor.getComponent(OptionsManager)
def customFieldManager = ComponentAccessor.getCustomFieldManager()


def cf = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Clone")
def fieldConfig = cf.getRelevantConfig(issue)
def value = ComponentAccessor.optionsManager.getOptions(fieldConfig)?.find { it.toString() == 'Yes' }
issue.setCustomFieldValue(cf, [value])

//def cf = customFieldManager.getCustomFieldObjectsByName("Clone") // Checkboxes is the NAME of my custom field
//def fieldConfig = cf.getRelevantConfig(issue)
//def option = optionsManager.getOptions(fieldConfig).getOptionForValue("Yes", null)
//issue.setCustomFieldValue(cf, [option])
//issue.setCustomFieldValue(cf, "Yes")

//Kommentiert den Issue im Ziel Project, dass es sich um einen gecloned Issue handelt
doAfterCreate = {
def commentManager = ComponentAccessor.commentManager
commentManager.create(issue, currentUser, "This is a cloned issue from project HAM by ${currentUser.name}", true)
}

 

3 answers

1 accepted

Suggest an answer

Log in or Sign up to answer
0 votes
Answer accepted
Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
January 13, 2020

First, let's have a look at your condition:

import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.CustomFieldManager;

//cfValues['Clone']?.value != "Yes"
//cfValues['Clone']*.value.contains("Yes")
if (cfValues['Clone']*.value.contains("Yes")) {
return false
} else {
return true
}

def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
! changeHistoryManager.getAllChangeItems(issue).find {
it.field == "Done"
}

I'm not sure what you intended to do with the changeHistoryManager, but since both clauses of the if() statement above include a "return" statement, the changeHistoryManager will never be executed.

In the Additional Issue Action code block "issue" refers to the new clone that is about to be created. So attempting to set the clone customfield value there will not work.

You could write additional code to change sourceIssue as part of Additional Issue Action, but it might be easier to just have a diffferent post function set your custom field value to yes.

But, reading your comment more carefully, I don't think you need the custom field. Your initial attempt to look at the changeHistory in the condition might work. Another option is to use the linkedIssueManager to look for an existing clone.

Try something like this in your condition

import com.atlassian.jira.component.ComponentAccessor;
def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()

!changeHistoryManager.getAllChangeItems(issue).any {
     it.field == "status" && it.tos*.value.contains("Done")
}

You may want to replace "Done" with the actual status name (not transition).

This means, only perform this post function if the current issue has never been in the "Done' state before.

Simon Krautwig January 14, 2020

Hi @Peter-Dave Sheehan .Thank you very much. I was able to solve the problem with your suggestion. That actually helped me a lot and the script was very short.

 

Greetings from Germany,

Simon! 

0 votes
Priyanka Agrawal October 8, 2020

@Peter-Dave Sheehan ,

Is there a way to avoid duplicate cloning without hiding the status from the view screen?

Please suggest. I'm not so good with coding.

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
October 8, 2020

@Priyanka Agrawal I would need a little more info to be able to answer fully. Every case is different. For coding to be effective, one needs to know what's already in place and exactly what's desired.

But in general terms, you can either hide the transition with a condition that looks for existing linked issues (optionally with a certain link type).

Or use the "Condition" script for the post function and skip running the post function when a linked issue already exists.

Like # people like this
Priyanka Agrawal October 8, 2020

Hi @Peter-Dave Sheehan 

Thank you for such a quick response.

I have a project with workflow where when an issue is transitioned from status Build to Test, few automated tasks are created. But when a user realize that oh no the test has failed and i need to go back to status Build. So he transitions the issue back to Build and when from Build it is transitioned to Test the second time, those automated tasks are getting created again. So i would like to avoid these double creation of tasks.

To be specific, the link type is "Issues in Epic"

Your second suggestion :"use the "Condition" script for the post function and skip running the post function when a linked issue already exists" sounds good to me.

Could you please help me with this?

Hope the requirement is clear now?

Your help in this regards would be highly appreciated.

Best regards,

Priyanka

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
October 8, 2020

How are the automated tasks created? Can you share screenshots?

Priyanka Agrawal October 8, 2020

Capture1.JPGCapture2.JPG

@Peter-Dave Sheehan : Attached the screenshots of the workflow Postfunctions through which automated tasks are being created.

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
October 8, 2020

What app is providing this functionality? It does not look like scriptrunner.

Priyanka Agrawal October 9, 2020

@Peter-Dave Sheehan  this is not scriptrunner but a postfunction called "Create / Clone issue(s) (JMWE add-on) Function"

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
October 9, 2020

I don't have JMWE and I'm not familiar with how it implements conditional execution.

You'll need to consult their documentation or post a new question in a topic where experts on that tool can help you.

I'm more of a scriptrunner/groovy/jira api guy (as evidenced by the post title and tag).

But basically, you need the condition to be false when an issue already exists that matches the issue that you would otherwise create.

Like Priyanka Agrawal likes this
Priyanka Agrawal October 9, 2020

@Peter-Dave Sheehan  Many thanks for your support.

0 votes
Dar Kronenblum
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.
January 13, 2020

hi @Simon Krautwig 

not sure that I understood you completely, but it seems like the custom field update didn't store the value in the database.

try to add this line to your code to store the data:

ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser

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

ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)
Simon Krautwig January 14, 2020

Hi @Dar Kronenblum ,

thank you for your reply. But with the solution from @Peter-Dave Sheehan I was able to slim down the whole thing. Thank you very much anyway.

Best regards.

TAGS
AUG Leaders

Atlassian Community Events