JIRA - bulk delete attachments

Is there any way to safely delete attachments from several JIRA issues? Attachments of issues in our JIRA take a lot of space on disk. To save some space my boss asked me to delete attachments of older issues of one specific project in that way JIRA is not damaged. The problem is there are hundreds of issues whose attachments should be erased and it would take ages to do it one-by-one.

I've been looking for an hour for solution, but JIRA seems not to support bulk deletion of attachments. I may manage to do it with Run CLI Actions in JIRA, however I am not sure about the solution

  1. Search for issues in JIRA (specific project, specific update time), export the list of issue keys to Excel. Open XLS file and save it as CSV. Only column is Key.
  2. Use Run CLI Actions in JIRA, functions runFromCsv and getAttachmentList to list Issue and attachments ID's. Save output to another CSV.
  3. Use Run CLI Actions in JIRA, functions runFromCsv and removeAttachment to remove attachments from all desired tasks.

Is that right workaround? What about Closed issues? Will JIRA allow to erase attachments from them?

Leos

3 answers

1 accepted

Finaly I got it. Here's my workaround. (Project and domain names are fictional.)

There are some conditions that form a subset of affected issues:

- issues of specific project (here LIBFREX)

- closed issues

- issues that were resolved before 1.1.2013 (i.e. on 13 Aug 2014 it's 588 days ago)

- only attachments with extensions zip, 7z, log

1) Ensure sufficient permission

- User who is going to perform deletion must be allowed to do "Delete All Attachments" in Permission scheme of project LIBFREX

- There must be no property "jira.issue.editable=false" for Closed Issues in Workflow of project LIBFREX

2) Listing of all attachments of issues specified above

Auxiliary JQL queries designed by try-and-error principle to produce less than 1000 results (larger results could not be shown)

project = LIBFREX AND status = Closed AND resolved >= -900d AND resolved <= -588d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_900-588.1

project = LIBFREX AND status = Closed AND resolved >= -1000d AND resolved <= -901d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1100-901.1

project = LIBFREX AND status = Closed AND resolved >= -1200d AND resolved <= -1001d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1400-1101.1

project = LIBFREX AND status = Closed AND resolved >= -1500d AND resolved <= -1201d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1700-1401.1

project = LIBFREX AND status = Closed AND resolved >= -1800d AND resolved <= -1501d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_3000-1701.1

project = LIBFREX AND status = Closed AND resolved >= -2700d AND resolved <= -1801d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_3000-1701.1

Command of Atlassian JIRA CLI

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -900d AND resolved <= -588d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_900-588.1

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -1000d AND resolved <= -901d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1000-901.1

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -1200d AND resolved <= -1001d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1200-1001.1

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -1500d AND resolved <= -1201d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1500-1201.1

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -1800d AND resolved <= -1501d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_1800-1501.1

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromIssueList --search "project = LIBFREX AND status = Closed AND resolved >= -2700d AND resolved <= -1801d" --common "--action getAttachmentList --issue @issue@" > JIRA_LIBFREX_2700-1801.1

========== first 26 lines of file JIRA_LIBFREX_900-578.1 ==========

Run: --action getAttachmentList --issue LIBFREX-5500
4 attachments for issue: LIBFREX-5500
"Id","Name","MIME Type","Size","Date Created","Author"
"45687","SERVISNI_ZASAH_OKCTAB-OKC_(okcdt)_2012-12-28_14-52-28.LOG","text/plain","15421","12/28/12 2:53 PM","dunaj"
"45682","SERVISNI_ZASAH_OKCTAB-OKC_(sdsok.datcen.isacoon.cz)_2012-12-28_14-14-29.LOG","text/plain","15436","12/28/12 2:25 PM","dunaj"
"45683","SERVISNI_ZASAH_OKCTAB-OKCZ_(okcdz)_2012-12-28_14-21-08.LOG","text/plain","15421","12/28/12 2:25 PM","dunaj"
"45686","SERVISNI_ZASAH_OKCTAB_SKOL-OKCS_(okcds)_2012-12-28_14-29-19.LOG","text/plain","15426","12/28/12 2:53 PM","dunaj"


Run: --action getAttachmentList --issue LIBFREX-5499
0 attachments for issue: LIBFREX-5499


Run: --action getAttachmentList --issue LIBFREX-5498
1 attachments for issue: LIBFREX-5498
"Id","Name","MIME Type","Size","Date Created","Author"
"45653","upgrade_615.log","text/plain","834","12/27/12 7:05 PM","dunaj"


Run: --action getAttachmentList --issue LIBFREX-5496
4 attachments for issue: LIBFREX-5496
"Id","Name","MIME Type","Size","Date Created","Author"
"45630","SERVISNI_ZASAH_OKCTAB-OKCT2_(dbcentrumtest.isacoon.local)_2012-12-21_12-22-23.LOG","text/plain","89260","12/21/12 12:27 PM","dunaj"
"45639","SERVISNI_ZASAH_OKCTAB_PROD-OKCV10_(exadata3.isacoon.local)_2012-12-21_12-23-07.LOG","text/plain","89109","12/21/12 2:16 PM","dunaj"
"45632","SERVISNI_ZASAH_OKCTAB_PROD-OKCV2_(exadata4.isacoon.local)_2012-12-21_11-13-24.LOG","text/plain","89108","12/21/12 12:46 PM","dunaj"
"45631","SERVISNI_ZASAH_OKCTAB_VYVOJ_1-OKCV3_(hpbl22db.isacoon.local)_2012-12-21_12-24-43.LOG","text/plain","89510","12/21/12 12:27 PM","dunaj"

========== END of example lines from JIRA_LIBFREX_900-578.1 ==========

For each auxiliary JQL query perform that command and produce JIRA_LIBFREX_xxx-yyy.1 file. Perform steps 3-6 for each produced file.

3) Restriction to files with specified extensions

- ZIP/zip

- 7Z/7z

- LOG/log

grep -Ei 'LIBFREX-|.LOG"|.7z"|.zip"' JIRA_LIBFREX_900-588.1 | grep -v 'Run:' > JIRA_LIBFREX_900-588.2
grep -Ei 'LIBFREX-|.LOG"|.7z"|.zip"' JIRA_LIBFREX_1000-901.1 | grep -v 'Run:' > JIRA_LIBFREX_1000-901.2
etc.

========== first 26 lines of file JIRA_LIBFREX_900-578.2 ==========

4 attachments for issue: LIBFREX-5500
"45687","SERVISNI_ZASAH_OKCTAB-OKC_(okcdt)_2012-12-28_14-52-28.LOG","text/plain","15421","12/28/12 2:53 PM","dunaj"
"45682","SERVISNI_ZASAH_OKCTAB-OKC_(sdsok.datcen.isacoon.cz)_2012-12-28_14-14-29.LOG","text/plain","15436","12/28/12 2:25 PM","dunaj"
"45683","SERVISNI_ZASAH_OKCTAB-OKCZ_(okcdz)_2012-12-28_14-21-08.LOG","text/plain","15421","12/28/12 2:25 PM","dunaj"
"45686","SERVISNI_ZASAH_OKCTAB_SKOL-OKCS_(okcds)_2012-12-28_14-29-19.LOG","text/plain","15426","12/28/12 2:53 PM","dunaj"
0 attachments for issue: LIBFREX-5499
1 attachments for issue: LIBFREX-5498
"45653","upgrade_615.log","text/plain","834","12/27/12 7:05 PM","dunaj"
4 attachments for issue: LIBFREX-5496
"45630","SERVISNI_ZASAH_OKCTAB-OKCT2_(dbcentrumtest.isacoon.local)_2012-12-21_12-22-23.LOG","text/plain","89260","12/21/12 12:27 PM","dunaj"
"45639","SERVISNI_ZASAH_OKCTAB_PROD-OKCV10_(exadata3.isacoon.local)_2012-12-21_12-23-07.LOG","text/plain","89109","12/21/12 2:16 PM","dunaj"
"45632","SERVISNI_ZASAH_OKCTAB_PROD-OKCV2_(exadata4.isacoon.local)_2012-12-21_11-13-24.LOG","text/plain","89108","12/21/12 12:46 PM","dunaj"
"45631","SERVISNI_ZASAH_OKCTAB_VYVOJ_1-OKCV3_(hpbl22db.isacoon.local)_2012-12-21_12-24-43.LOG","text/plain","89510","12/21/12 12:27 PM","dunaj"
0 attachments for issue: LIBFREX-5495
0 attachments for issue: LIBFREX-5493
4 attachments for issue: LIBFREX-5492
"45620","UPG_DB-215_OKCTAB_SKOL-OKCS_(okcds)_2012-12-21_06-27-32.7z","application/octet-stream","984648","12/21/12 7:12 AM","brozek"
"45609","UPG_DB-220_OKCTAB_SKOL-OKCS_(okcds)_2012-12-20_15-24-53.LOG","text/plain","3291","12/20/12 3:27 PM","bernhard"
"45621","UPG_DB-220_OKCTAB_SKOL-OKCS_(okcds)_2012-12-21_07-14-59.7z","application/octet-stream","1158490","12/21/12 7:57 AM","brozek"
"45623","UPG_DB-230_OKCTAB_SKOL-OKCS_(okcds)_2012-12-21_07-56-54.7z","application/octet-stream","1089864","12/21/12 8:46 AM","brozek"
2 attachments for issue: LIBFREX-5491
"45618","UPG_DB-220_OKCTAB_PROD-OKCV2_(exadata4.isacoon.local)_2012-12-20_15-38-55.7z","application/octet-stream","2191306","12/21/12 6:13 AM","brozek"
"45619","UPG_DB-230_OKCTAB_PROD-OKCV2_(exadata4.isacoon.local)_2012-12-21_06-17-01.7z","application/octet-stream","1083761","12/21/12 7:04 AM","brozek"
0 attachments for issue: LIBFREX-5490
0 attachments for issue: LIBFREX-5489

========== END of example lines from JIRA_LIBFREX_900-578.2 ==========

4) Modification of JIRA CLI output to sufficient form for other usage

=== script modifyAttachList.sh ===

#!/bin/bash
# Converts output file of Atlassian CLI to another format

inputFile=$1
outputFile=$2
inputFileLength=$(wc -l $inputFile | cut -d ' ' -f 1);
headString='attachments for issue:'
projectCode="LIBFREX-"
line=""
issueKey=""
idAttachment=""

echo "Issue, Id" > $outputFile

for ((i=1; i<=$inputFileLength; i++)); do
  line=$(head -n ${i} $inputFile | tail -n 1)  # Get current line
  if echo $line | grep -q "$headString"; then
    issueKey=$(echo $line | sed 's/.*\('$projectCode'[0-9]*\)/\1/')
  else
    idAttachment=$(echo $line | cut -d '"' -f 2);
    echo "$issueKey, $idAttachment" >> $outputFile
  fi
done

=== END of script modifyAttachList.sh ===

Commands

./modifyAttachList.sh JIRA_LIBFREX_900-588.2   JIRA_LIBFREX_900-588.3
./modifyAttachList.sh JIRA_LIBFREX_1000-901.2  JIRA_LIBFREX_1000-901.3
etc.

Example of a few lines from outputfile JIRA_LIBFREX_900-588.3

Issue, Id
LIBFREX-5500, 45687
LIBFREX-5500, 45682
LIBFREX-5500, 45683
LIBFREX-5500, 45686
LIBFREX-5498, 45653
LIBFREX-5496, 45630
LIBFREX-5496, 45639
LIBFREX-5496, 45632
LIBFREX-5496, 45631

5) Deletion of attachments

Ensure, that attachment folder $JIRA_HOME/data/attachments is recursively RW accessible by user running Tomcat.

Perform commands

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromCSV --common "--action removeAttachment" --file JIRA_LIBFREX_900-588.3
/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromCSV --common "--action removeAttachment" --file JIRA_LIBFREX_1000-901.3
etc.

Example output
Run: --action removeAttachment --issue "LIBFREX-5500" --id "45687"
Attachment with id 45687 removed from issue LIBFREX-5500.

Run: --action removeAttachment --issue "LIBFREX-5500" --id "45682"
Attachment with id 45682 removed from issue LIBFREX-5500.

6) (optional) Add comment to each affected issue

Modify bash script to create a list of comments - add those lines

outputFileComment=$3
echo "Issue, Comment" > $outputFileComment
comment=$(echo $line | cut -d '"' -f 4);
echo "$issueKey, File \"$comment\" was deleted because of ..." >> $outputFileComment

Then run script

./modifyAttachList.sh JIRA_LIBFREX_900-578.2 JIRA_LIBFREX_900-578.del JIRA_LIBFREX_900-588.com

and perform Atlassian CLI command (both for each subset, as noticed above in step 2)

/opt/programs/jiraCLI/atlassian-cli-3.9.0/jira.sh -a runFromCSV --common "--action addComment" --file JIRA_LIBFREX_900-588.com

WARN: Do not forget to disable outgoing mail or to disable notification about issue updates before running this command.

7) Change permission back to original settings

If some permisssion was modified at step 1) just for this case of deletion attachments, now its the right time to take it back and restore original settings.

Hi, all.

You can try Smart Attachments. It allows you to remove a bulk of attachments from one issue. In plans we have your feature too.

Other features also include categorization of attachments, access permissions per category, drag-n-drop upload of files to the category and other improvements.

Best Regards,

Vadim Rutkevich

1. instead of atlassian CLI you can run a script with script runner and do the deletion during search

2. If you cannot edit closed issues manually (try to delete attachment from one of them) - that means that the Closed status is not editable inside your workflow. You should change the workflow and remove edit restriction from the Closed status on the time of script execution.

Hello Alexey. Thanks for your suggestion. I have not any experience with writing Groovy scripts, till today I only used build-in ones. It would take me too much time to learn it and to create appropriate script to find & delete attachments. That's way using Atlassian CLI would be easier for me.

Good comment on closed issues - yes, it must be set by workflow settings.

I think you can do the same with atlassian cli - search for issues and process response immediately without convertation to Csv. But in general - any automation script is good solution of this problem.

Suggest an answer

Log in or Join to answer
Community showcase
Sarah Schuster
Posted Jan 29, 2018 in Jira

What are common themes you've seen across successful & failed Jira Software implementations?

Hey everyone! My name is Sarah Schuster, and I'm a Customer Success Manager in Atlassian specializing in Jira Software Cloud. Over the next few weeks I will be posting discussion topics (8 total) to ...

3,323 views 14 20
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
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