Copy attachments to one issue to another with Scriptrunner Cloud

Andrew Lipscomb December 8, 2016

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

6 answers

1 accepted

6 votes
Answer accepted
Jon Bevan [Adaptavist]
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.
December 12, 2016

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

Rudy Holtkamp
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
February 20, 2017

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

Jon Bevan [Adaptavist]
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, 2017

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

Rudy Holtkamp
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
February 20, 2017

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?

Rudy Holtkamp
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
February 21, 2017

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

Rudy Holtkamp
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
February 21, 2017

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.

Jon Bevan [Adaptavist]
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 21, 2017

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

1 vote
andrewd May 31, 2020

Can this be done in Server as opposed to Cloud?

0 votes
Abhishek Singh January 10, 2020

Hello All,

@Jon Bevan [Adaptavist] 

I need to copy attachments from one of the issue in project to new issue using post function. I am using on-demand jira and have script runner.  Please help me !!!.

Thanks in advance.

 

Regards,

Abhi

Jon Bevan [Adaptavist]
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 10, 2020

Hi Abhi, what have you tried?

Like Abhishek Singh likes this
Abhishek Singh January 14, 2020

Hello Jon, 

I got the solution. Thanks 

I have new query if you can help. 

I want to achieve that if the value in checkbox is others then attachment will be mandatory. I am using on-demand instance and have script runner plugin.

 

Regards,

Abhi

Jon Bevan [Adaptavist]
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 14, 2020

Do you mean on a create issue screen? Unfortunately this isn't possible with Jira Cloud.

Abhishek Singh February 11, 2020

@Jon Bevan [Adaptavist]  Yes on create screen. If any workaround then please suggest. 

Reagrds,

Abhi

0 votes
Andrew Lipscomb December 11, 2016

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

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.
December 9, 2016

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?

0 votes
Volodymyr Krupach
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.
December 8, 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
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.
December 9, 2016

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

Suggest an answer

Log in or Sign up to answer