Copy attachments to one issue to another with Scriptrunner Cloud

Is it possible to run a post function which creates a subtask and copies all attachments from the parent issue to the subtask; with the obvious restriction that everything is done via the REST APIs? Editmeta for an issue shows that the attachments key has no operations; and that leaves this as the only method for attachment addition. 

I found this answer (https://answers.atlassian.com/questions/41813368) but it relies on copying the file to disk temporarily. I'm assuming that the ScriptRunner Cloud containers do not allow you to do this; or that it would be unreliable for larger files given the 30sec timeout. 

The ideal way would be to simply add attachment IDs from Issue A to Subtask B, but I get the feeling each Issue needs its own copy of an attachment. 

Edit: Fixed link

4 answers

1 accepted

You should be able to clone attachments using the following code in a post function:

import org.apache.http.entity.ContentType;
 
def createReq = Unirest.post("/rest/api/2/issue")
        .header("Content-Type", "application/json")
        .body([
            summary: "Cloned issue"
        ])
        .asObject(Map)

assert createReq.status >= 200 && createReq.status < 300

def clonedIssue = createReq.body

// copy attachments

if (issue.fields.attachment) {
    issue.fields.attachment.collect { attachment ->
        def url = attachment.content as String
        url = url.substring(url.indexOf("/secure"))
        def fileBody = Unirest.get("${url}").asBinary().body
        def resp = Unirest.post("/rest/api/2/issue/${clonedIssue.id}/attachments")
                .header("X-Atlassian-Token", "no-check")
                .field("file", fileBody, ContentType.create(attachment['mimeType'] as String), attachment['filename'] as String)
                .asObject(List)
        assert resp.status >=200 && resp.status < 300
    }
}

EDIT: added package import and other code fixes from comments below

Hi @Jon Bevan [Adaptavist], I've tried your code in a post-function on a transition, but I get an error on this line:

def fileBody = Unirest.get("${url}").asBinary().body

body: {"error": "Add-on 'com.onresolve.jira.groovy.groovyrunner' blocked from impersonating the user because the access token does not have the required scope(s)"}
It is running as 'Initiating user'. I also tried running it as add-on user, but then it gives me an error code: status: 401 - Unauthorized
Do you have any idea how to resolve this?

 

Thanks

Hi Rudy,

The 401 Unauthorized gives me the impression that the Initiating user might not have permission to view the attachment (or perhaps the issue its attached to).

Thanks, Jon

I'm running it as myself and when I directly go to https://company.atlassian.net/secure/attachment/10004/company-logo.png in my browser the logo loads. So I don't think I have a permission issue from that perspective.

Any other thoughts?

Hi @Jon Bevan [Adaptavist],

I've got ride of the 401 error, by adding the add-on user to the correct project role.

Unfortunately it still does not work.

I get a compile error on: ContentType.create(attachment.mimeType)

Because it is not declared. When I try to import the class with: 
import groovyx.net.http.ContentType 

ScriptRunner cannot resolve the class. 

What am I missing here?

Thanks,
Rudy

Ok, I found out that it was not the correct library to import.

For future reference use:

import org.apache.http.entity.ContentType;

And casting to String will also help

.field("file", fileBody, ContentType.create(attachment['mimeType'] as String), attachment['filename'] as String)


Ciao and thanks Jon for pointing me in the right direction.

Glad you got it working Rudy, and thanks for the correct import - I've updated the code above to reflect your fixes smile

0 vote
Volodymyr Krupach Community Champion Dec 08, 2016

> The ideal way would be to simply add attachment IDs from Issue A to Subtask B, but I get the feeling each Issue needs its own copy of an attachment
You have the right feeling smile. Each issue needs own copy of the attachment.

>  Is it possible to run a post function... with the obvious restriction that everything is done via the REST APIs 

Calling REST API from the post-function looks strange for me. Once you are coding the post-function it's better to rely on JIRA Java API.

Volodymyr Krupach Community Champion Dec 09, 2016

Missed the script-runner tag. Apologies. Please refer to Jamie's comment.

0 vote

It should certainly be possible from the perspective of whether the rest apis can do it. I'm not sure if you can write to local disk to be honest, but anyway, you should be able to stream the output of one call to the input of another. Or just hold the entire attachment file in memory. @Jon Mort (Adaptavist) - any ideas?

Holding in memory was my initial idea, but I worry about failure when the Script times out if we are looking at larger files (not likely in my use case, but I figure make this a relevant question for people who come back to this question with bigger files)

Also, doesn't the blocking aspect of the HTTP calls prevent you directly streaming from one input call to an output? I would have thought that you would need to do:

Input-A starts=>block execution=>read all the attachments to file/memory=>Input-A Closes

and then

Output-B starts=>block execution=>write all data to stream=>Output-B closes

Suggest an answer

Log in or Join to answer
Community showcase
Teodora [Botron]
Published Feb 15, 2018 in Marketplace Apps

Jira Inferno: The Nine Circles of Jira Administration Hell

If you spend enough time as a Jira admin - whether you are managing a single, mid-sized instance, a large enterprise one or juggling multiple instances at once - you will eventually find yourself in ...

1,239 views 6 19
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you
Atlassian Team Tour

Join us on the Team Tour

We're bringing product updates and pro tips on teamwork to ten cities around the world.

Save your spot