How can I copy the last attachment from a Jira issue to another?


I have a workflow where in each step a file is attached to the issue. At the end I want to copy the LAST attached file only from this issue to another issue. How can I do that?

to be more clear: I know how to copy A file, but I don't know how to copy the LAST one only.

I have tried to do that with JJUPIN SIL, but I could not because SIL stores the attachments in alphabetical order and does not store any date-time info about them. So you can not determine which file was attached last. (I have discovered that by testing only. So, please correct if I am mistaken!)

Any help would be appreciated.

6 answers

1 accepted

1 vote
Accepted answer

Hi Sadek,

You may use the sql() routine of JJUPIN to directly query the attachment table FILEATTACHMENT and sort it by created.



Hi Eric, Thanks for the suggested solution. I think this should work for me. But I have faced one problem: finding the datasource JNDI name that I should use. I am using my Jira server (6.4.9) with MySQL DB and I don't know from where should I get the datasource JNDI name. Can you help me with that. can I use the datasource name stated in the dbconfig.xml file. The content of the file is as follows: <?xml version="1.0" encoding="UTF-8" ?> <jira-database-config> <name>defaultDS</name> <delegator-name>default</delegator-name> <database-type>mysql</database-type> <jdbc-datasource> <url>jdbc:mysql://localhost:3306/jiradb?useUnicode=true&characterEncoding=UTF8&sessionVariables=storage_engine=InnoDB</url> <driver-class>com.mysql.jdbc.Driver</driver-class> <username>jirauser</username> <password>jirapass</password> <pool-min-size>20</pool-min-size> <pool-max-size>20</pool-max-size> <pool-max-wait>30000</pool-max-wait> <validation-query>select 1</validation-query> <min-evictable-idle-time-millis>60000</min-evictable-idle-time-millis> <time-between-eviction-runs-millis>300000</time-between-eviction-runs-millis> <pool-max-idle>20</pool-max-idle> <pool-remove-abandoned>true</pool-remove-abandoned> <pool-remove-abandoned-timeout>300</pool-remove-abandoned-timeout> <pool-test-while-idle>true</pool-test-while-idle> <validation-query-timeout>3</validation-query-timeout> </jdbc-datasource> </jira-database-config> or I must add a datasource in context.xml as instructed in the documentation of SIL ? Many thanks, Sadek

Hi Sadek, Yes you have to define it on context.html

Ok. I have added the following code to context.xml: <Resource name="JiraDBsql" auth="Container" type="javax.sql.DataSource" username="jiradbuser" password="jiradbpass" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://" /> and now it DOES work. I will try the attachment manipulations I need now. :) Thanks for the help and for the great plug in.

I have used this to re-order the attachments successfully. Moreover, I have just learned from Alexandra Topoloaga from Kepler-Rominfo that you can use the same method to re-name the attached files. Simply edit the FILENAME field of the fileattachment table and the file name is changed. I mean there is no need to edit anything on the hard disk of the server !

Hi Sadek,

I have enclosed a Script Runner solution below of how you can copy the previous attachment from an issue over to another issue.

This code can be edited if needed to automatically specify the issue key of the issue that the attachment should be copied to.

import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Category
import com.atlassian.jira.issue.Issue;

def Category log = Category.getInstance("com.onresolve.jira.groovy.PostFunction");

// Get the current issue key
Issue issueKey = issue
def id = issueKey.getId()

// Get the current logged in user
def user = ComponentAccessor.getJiraAuthenticationContext().getUser().name

// Get a manager to handle the copying of attachments
def attachmentManager = ComponentAccessor.getAttachmentManager()

// Get the default attachment path from its manager 
def attachmentPathManager = ComponentAccessor.getAttachmentPathManager().attachmentPath.toString()

// Get the current date
def today = new Date()

// Get the last attachments file properties needed by the attachment manager to copy it.

def fileName = issueKey.attachments.last()?.filename.toString()
def fileType = issueKey.attachments.last()?.mimetype.toString()

// Construct the key of the next Subtask
def currentIssue = issue.toString()

// Extract the project key from the issue
def projectKey = currentIssue.replaceAll("[^A-Z]", "").toString();

// Get the ID that jira has used to store the last attachment
def fileId = issueKey.attachments.last()?.id

// Construct the file path of the attachment to copy
def path = attachmentPathManager + "/" + projectKey + "/" + currentIssue + "/" + fileId + "/"

// Construct a pointer to the file that will be copied
File filePath = new File(path.toString())

// Specify the issue to copy the attachment to here. This could be defined in code.
Issue subIssue = ComponentAccessor.getIssueManager().getIssueObject("KDP-100")

// If there is a previous attachment
if (fileName != null) {
// Attach the file to the new issue
    attachmentManager.createAttachmentCopySourceFile(filePath, fileName, fileType, user, subIssue, null, today)


I hope this helps



Thank you Kristian. This a big effort you have made here. I am sure it will be helpful for me and others. Sadek

You are welcome Sadek. Please let me know if helps you to solve your issue. Kristian



doesn't take the latest attachment since the list is sorted alphabetically.

With SIL (in JJuping or BlitzActions) you may iterate through the attachments of an issue and get the file path therefore...


string temp = "";
for(string attachment in attachments) {
    string [] filePaths = getAttachmentPath(key, attachment);
    for (string fileName in filePaths) {
        temp = temp + "--- " + attachment + " -&gt; " + fileName;
return isNull(temp) ? "Sorry, no attachments in " + key : temp;

As I use a similiar function with SIL (JJupin) I wrote the following function which I share with you. Todo would be a better error handling and there's currently no way I know to remove the directory created in "SIL tmp"; the files get deleted after attaching to target issue:

function copyAttachments(string sourceKey, string targetKey)
    const string _targetPath = replace(silEnv("sil.home"), "\\", "/") + "/../tmp/" + sourceKey;
    string [] _attachmentList;
    // unique array of attachments
    for(string attachment in sourceKey.attachments) {
        _attachmentList = arrayAddElementIfNotExist(_attachmentList, attachment);
    for(string attachment in _attachmentList) {
        string [] filePaths = getAttachmentPath(sourceKey, attachment);
        if(arraySize(filePaths) &gt; 1) {
            for(int i=0; i &lt; arraySize(filePaths); i++) {
                string sourceFilePath = replace(filePaths[i], "\\", "/");
                string targetFile = replace(attachment, ".", "_" + (i+1) + ".");
                string targetFilePath = _targetPath + "/" + targetFile;
                if(createDirectory(_targetPath)) {
                    fileCopy(sourceFilePath, targetFilePath);
                    attachFile(targetFilePath, targetKey);
        else {
            string sourceFilePath = replace(filePaths[0], "\\", "/");
            string targetFile = attachment;
            string targetFilePath = _targetPath + "/" + targetFile;
            if(createDirectory(_targetPath)) {
                fileCopy(sourceFilePath, targetFilePath);
                attachFile(targetFilePath, targetKey);
copyAttachments("SPIKS-70", "SPIKS-71");
return "OK";

Hi Sadek,

I have a similar requirement to copy the attachments in one issue to other issue. As you have mentioned "I know how to copy a file" Could you please tell how did you achieve this with SIL. I just want to copy all the attachments in an issue.

The best would be to use the attachmentManager.copyAttachments method to achieve this task.


Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Tuesday in Statuspage

Introducing Statuspage Getting Started guides! First up: What is Statuspage?

Over the next several weeks we'll be sharing some of our Getting Started guides here in the community. Throughout this series of posts, we'd love to hear from customers and non-customers ab...

191 views 4 1
Join discussion

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