Recently, we started using Jira at work to track some IT related things. Thus, I have quickly had to learn how to administer Jira. One thing that I really wanted to get set up and working well was the ability to respond to an email sent by the system via a reply email and have that filed in the ticket. That wasn’t too terribly hard to set up. First I created a mailbox for Jira to check in our mail system. Then I set up a mail handler to pull the reply emails in. I settled for using a “Add a comment before a specified marker or separator in the email body” handler so that I could provide a regular expression to define how to extract just the reply. The below screenshots show my setup for this.
The Split Regex field below is this /[Ff]{1}rom:[^\n]+{myuser}@{mydomain}\.{extention}/. Replace the {myuser}, {mydomain}, and {extention} parts with the email address of the account that Jira mails as. So, if your Jira system sends email as jira@coolstuff.org the above expressions would look like this /[Ff]{1}rom:[^\n]+jira@coolstuff\.org/. This will split the email where it sees the first line that looks something like this From: Jira [mailto:jira@coolstuff.org] or from: Jira [mailto:jira@coolstuff.org] … which is how Outlook formats its replies.
So, I got that part working great now I can go get a doughnut right? Nope! Turns out every time I would reply the issue icon and the image attachment in my email signature would get attached to the issue … over and over and over. So, before long I had a veritable glut of the same images attached to the issue. Grrrr!! So, I asked myself “Self, what can we do about this?” To which I so helpfully replied to myself, “Go check the Atlassian Marketplace, Atlassian Community, and Google for an answer.” After a couple grueling hours of trying to find the answer I came to the stark conclusion that there wasn’t one. Double grrrr!!
After a bit of thinking I decided I could just scan the images against a set of MD5 hashes to exclude when the issue is updated and here is the fruit of my labor. This solution requires having ScriptRunner for Jira installed. If you don’t have it … well, you should. The possibilities are pretty endless with what you can do with it. I created a Script Listener that would respond to the “Issue Updated” event.
And the actual contents of the script file.
import java.security.*; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.component.ComponentAccessor; import com.atlassian.jira.issue.AttachmentManager; import com.atlassian.jira.util.AttachmentUtils; // Add new MD5 hashes to the below array to auto remove them when they are attached to the ticket. // This is helpful to get rid of things like images in email signatures, JIRA issue type icons in the email, etc. def deleteHashes = [ "eaf938ae5025889b60029d6d839d19db", //JIRA blue check mark "f370264d9a3d1b92666419e6ecc102ef", //email signature logo v1 "662b051e6082e4499079ddc18e5eb302", //email signature logo v2 "a4ab3c522859297084064502477effd8" //Pulse line icon ]; def issue = event.getIssue(); def attachments = issue.getAttachments(); def attachmentFile = null; def bytes = null; def md = MessageDigest.getInstance("MD5"); def digest = null; def hash = ""; def manager = ComponentAccessor.getComponent(AttachmentManager) for(a in attachments) { attachmentFile = AttachmentUtils.getAttachmentFile(a); bytes = getBytesFromFile(attachmentFile); digest = md.digest(bytes); hash = String.format("%032x", new BigInteger(1, digest)); for(h in deleteHashes) { if(hash == h) { manager.deleteAttachment(a); break; } } } public byte[] getBytesFromFile(File file) throws IOException { // Get the size of the file long length = file.length(); // You cannot create an array using a long type. // It needs to be an int type. // Before converting to an int type, check // to ensure that file is not larger than Integer.MAX_VALUE. if (length > Integer.MAX_VALUE) { log.info("File is too large!"); // File is too large throw new IOException("File is too large!"); } // Create the byte array to hold the data byte[] bytes = new byte[(int)length]; // Read in the bytes int offset = 0; int numRead = 0; InputStream is = new FileInputStream(file); try { while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { offset += numRead; } } finally { is.close(); } // Ensure all the bytes have been read in if (offset < bytes.length) { log.info("Could not completely read file " + file.getName()); throw new IOException("Could not completely read file " + file.getName()); } return bytes; }
Now, when I respond to an issue via email if any of the attachments on the issue match any of the MD5 hashes at the top of the script that attachment will get deleted from the issue. And if I find that there are other attachments we start seeing like this on a regular basis all I have to do is add the MD5 hash to the list and save the script … problem solved.
Now, about that doughnut.
Update: So, the whole editing the script and having others put in MD5 hashes part … yeah, that went over like a lead balloon. Here is an updated version that is much easier to administer.
Pingback: Remove Jira Issue Attachments by MD5 Hash Redux - I am Davin