Trying to get a way to copy an attachment from one issue to another issue as part of a group of issues.
Using REST API we have a tool for finalizing our test component and it grabs the test documentation (attachment on Company Issue in Jira) and downloads it then uploads it to the related client issue (Issue for client project in JIRA) to share the completed testing documentation.
Both projects are in the same JIRA instance but the clients cannot see the company project based on permissions. But we still want to be able to share this documentation when we compile our build output.
The problem comes in having to download then upload the attachment, as it sometimes times out and that prevents that issue from being updated with the proper test documentation.
Is there a REST API call that would allow me to copy the attachment and associate it with the client issue without having to download and then upload it?
If you don't want to download and upload attachments to issue you can create REST Endpoint by ScriptRunner which copy attachments from source issue to destination issue.
https://scriptrunner.adaptavist.com/latest/jira/rest-endpoints.html
@Alex Cumberland old issue but if needed I can share the code for this
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes I would love to see the code. We ended up having to do the whole copy down and the reupload. It is extremely time consuming.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK, so I think I have the same resolution as you:
Script checks if there was some value selected for the attachments on the original screen and then this:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
cool - thanks -
Does anyone has the scriptrunner example for Jira Cloud ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
As an alternative we use Jira Automation to copy the Attachment information to the new ticket including the download link. This allows to keep the attachments on one place and just provide a download link in the destination issue.
Automation rule
1. CLONE Issue action
2. Edit Description Field
{{issue.description}}
----
*Attachments links from Original Ticket*
{{#issue.attachment}}
- [ {{filename}} | {{content}} ] - {{size}} Bytes - {{author.displayName}} - {{created.jiraDate}}
{{/issue.attachment}}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The one I've posted is for Cloud. If you want, I have one for server as well
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Lukasz Grobelny upps sorry - Cloud code is perfect - Thanks
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you! Your post was very helpful.
Could you please post the server one here as well? I think I might go that route.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Lukasz Grobelny man, that was exactly what I needed.
Had to modify it a bit for my tests but this is ready to be integrated with my stuff
Leaving my edited code here so maybe someone else needs it
def issueKey = "TEST-1"
def issueFields = get('/rest/api/2/issue/' + issueKey)
.header('Content-Type', 'application/json')
.asObject(Map)
.body.fields
def targetIssueKey = "TEST-2"
def attaches = issueFields.attachment as List <String,String>
attaches.each{ it ->
def attId = it.id
def att = Unirest.get('/rest/api/2/attachment/' + attId).asObject(Map).body
def downloadUrl = it.content
def readFileResp = Unirest.get(downloadUrl).asBinary()
logger.info("${downloadUrl}")
def response = Unirest.post('/rest/api/2/issue/' + targetIssueKey + '/attachments')
.header("Accept", "application/json")
.header("X-Atlassian-Token", "nocheck")
.field("file", readFileResp.body, att.filename.toString())
.asObject(Map)
}
Thank you @!!!!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am not aware of any publicly available REST API call to allow the copy of attachments between issues.
However, you might consider changing the time out for your API calls.
Usually, the REST API uses the default_socket_timeout parameter which defaults to 300 seconds, however, this parameter can be changed in some consoles like CURL.
You can check the link below to know exactly what parameters you can use to change the timeout:
Hope this helps
Phill
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
So this is code to move entire issue between projects - comments included
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.context.IssueContext
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.fields.config.manager.PrioritySchemeManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import org.apache.log4j.Logger
def summarytest = issue.getSummary()
def assignee = issue.getAssignee().getDisplayName()
def projetPickerValue = ""
def issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def cField = customFieldManager.getCustomFieldObject("customfield_10201")
def originalIssueType = issue.getIssueType().getName()
def additionalFieldsSelector = customFieldManager.getCustomFieldObject("customfield_10300")
def additionalFields = issue.getCustomFieldValue(additionalFieldsSelector) as List
def value = (String) issue.getCustomFieldValue(cField)
def projectKeyFromPicker = value.minus("Project: ")
log.warn(additionalFields.getAt(0))
//log.warn(assignee)
def commentManager = ComponentAccessor.getCommentManager()
def existngComments = commentManager.getComments(issue);
log.warn(summarytest)
log.warn(existngComments.getAt(0).getBody())
//Czesc peirwsza pobieranie issue key
// the project key under which the issue will get created
final projectKey = 'TEST'
// the issue type for the new issue
final issueTypeName = 'Bug'
// user with that user key will be the reporter of the issue
final reporterKey = 'auser'
// the summary of the new issue
final summary = 'Test'
// the priority of the new issue
final priorityName = 'Major'
def issueService = ComponentAccessor.issueService
def constantsManager = ComponentAccessor.constantsManager
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def prioritySchemeManager = ComponentAccessor.getComponent(PrioritySchemeManager)
def project = ComponentAccessor.projectManager.getProjectObjByKey(projectKeyFromPicker)
assert project : "Could not find project with key $projectKey"
def issueType = constantsManager.allIssueTypeObjects.findByName(originalIssueType)
assert issueType : "Could not find issue type with name $issueTypeName"
// if we cannot find user with the specified key or this is null, then set as a reporter the logged in user
def reporter = ComponentAccessor.userManager.getUserByKey(reporterKey) ?: loggedInUser
def tet = ComponentAccessor.userManager.getUserByName(assignee) ?: loggedInUser
log.warn(reporter)
log.warn(tet)
// if we cannot find the priority with the given name or if this is null, then set the default priority
def issueContext = new IssueContextImpl(project, issueType) as IssueContext
def priorityId = constantsManager.priorities.findByName(priorityName)?.id ?: prioritySchemeManager.getDefaultOption(issueContext)
def issueInputParameters = issueService.newIssueInputParameters().with {
setProjectId(project.id)
setIssueTypeId(issueType.id)
setReporterId(reporter.name)
setSummary(summarytest)
setPriorityId(priorityId)
setAssigneeId(tet.name)
}
def validationResult = issueService.validateCreate(loggedInUser, issueInputParameters)
assert validationResult.valid : validationResult.errorCollection
def result = issueService.create(loggedInUser, validationResult)
assert result.valid : result.errorCollection
log.warn(result.getIssue())
//Przenosimy komentarze
if(additionalFields.contains("Komentarze")){
log.warn("Komentarze")
if(existngComments.size() > 0){
for(int i = 0; i < existngComments.size(); i++){
def commentAuthor = existngComments.getAt(i)getAuthorApplicationUser()
def newIssue = result.getIssue()
def newBody = existngComments.getAt(i).getBody()
commentManager.create(newIssue,commentAuthor,newBody,true)
log.warn(existngComments.getAt(i).getBody())
}
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.