Clones an Issue and Links

Clones the current issue to a new one. User can select between copying, All the fields, None of them or certain fields, from source to the new issue.

There is also the possibility to select the user whom on behalf the issue will be cloned (As User field), it affects the creator and the reporter of the new cloned issue. If empty the currently logged in user will be used.

You can specify an issue type and/or target project, but if you leave them blank the clone will have the same project and type as the cloner.

Specify also the link type and direction…​ this will normally be Clones, but doesn’t have to be.

If you want to override some of the field values rather than have them inherited from the source issue you can specify that in the Additional Code field. For example the following snippet will set the summary field, and a custom field called MyCustomFieldType to "my value":

issue.summary = 'Cloned issue' def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'MyCustomFieldType'} issue.setCustomFieldValue(cf, "my value")

As of 2.1, outward and inward links are also copied. So if issue A depends on issue B, after cloning to issue C then issue C will also depend on issue B. And similarly if issue B was depended on by issue A.

You can override this behaviour to copy links selectively or disable altogether by providing a callback (a closure) called checkLink in the Additional Code field. The callback will be called for every link found and should return true or false. This is passed one parameter, the IssueLink object. For example, to disable the cloning of links altogether use this code:

checkLink = {link -> false};

To enable cloning of all links except links of the type Clones use:

checkLink = {link -> link.issueLinkType.name != "Clones"}

Control of cloning attachments

In a similar way, you can control which attachments are copied. To disable attachment copying completely:

checkAttachment = {attachment -> false}

To clone only the attachments added by the user jbloggs:

checkAttachment = {attachment -> attachment.authorKey == 'jbloggs'}

Due to indexing changes in Jira 5.1, this post-function should be placed immediate after the function: Re-index an issue to keep indexes in sync with the database. If you don’t do this, the parent issue will not be indexed correctly.

After Create actions

There are some actions that can take place only after the creation of the issue (add watcher, create issue links etc), in this case you can apply additional actions after the creation of the new issue, using the doAfterCreate callback (closure).

For example, add watchers to the new issue:

import com.atlassian.jira.component.ComponentAccessor

def watcherManager = ComponentAccessor.getWatcherManager()
def userManager = ComponentAccessor.getUserManager()

doAfterCreate = {
    def userKeyToAddAsWatcher = "anuser"
    def watcher = userManager.getUserByKey(userKeyToAddAsWatcher)

    if (watcher) {
        watcherManager.startWatching(watcher, issue)
    } else {
        log.warn("User with key: ${userKeyToAddAsWatcher} does not exist therefore would not be added as a watcher")
    }
}

Another use of it could be, linking the new issue to another one. For example create a 'duplicates' issue link between the new issue and an issue with key JRA-24:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.link.IssueLinkTypeManager

def issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)
def issueManager = ComponentAccessor.getIssueManager()

doAfterCreate = {
    def issueToLinkTo = issueManager.getIssueByCurrentKey("JRA-24")
    def duplicateLinkTypeName = "Duplicate"

    def duplicateLinkType = issueLinkTypeManager.getIssueLinkTypesByName(duplicateLinkTypeName)

    if (!duplicateLinkType) {
        log.warn("Issue link type with name: ${duplicateLinkTypeName} does not exist")
    } else {
        issueLinkManager.createIssueLink(issue.id, issueToLinkTo.id, duplicateLinkType[0].id, 1, currentUser)
    }
}

The variable issue outside the doAfterCreate closure is not yet created and trying to access it will result to an error (the issue.getKey() will throw a NullPointerException). On the other hand the issue inside the doAfterCreate callback is created and exists (therefore the issue.getKey() will return the key of the new issue).