It's me again.
I'm sharing a helpful Python script to streamline attaching multiple files to Jira Cloud issues. This script automates the process of uploading files, saving you time and effort, especially when dealing with many attachments.
The script uses the Jira Cloud REST API (this endpoint specifically) and reads data from a CSV file to attach files to specific Jira issues. The CSV file should contain two columns: "Issue Key" and "Filename". The "Filename" column should contain the paths to your attachment files (either relative paths from where you run the script or absolute paths).
Example:
Issue Key,Filename PROJ-001,/Users/user1/Desktop/attachments/attachment1.png PROJ-002,/Users/user1/Desktop/attachments/attachmend2.txt PROJ-003,/Users/user1/Desktop/attachments/attachment3.pdf
1) Make sure that the user acting on this script has the necessary project permissions to "Browse Projects", "Edit Issues", and "Create Attachments".
2) Ensure the destination issues (issue types) have the "Attachments Field" in their edit screen
3) Considerations: There's a character limit of 256 for file names, also check your attachment size limit to avoid related errors
4) Install the necessary Python libraries by running:
pip install requests
Prepare your Jira Cloud site URL (your-domain.atlassian.net), email address, and API token. You can generate an API token from Atlassian's account security page.
import requests from requests.auth import HTTPBasicAuth from getpass import getpass import logging import os import csv import json logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def get_jira_auth(): jira_domain = input("Enter your Jira Cloud domain (e.g., your-domain.atlassian.net): ") email = input("Enter your Jira email: ") api_token = getpass("Enter your Jira API token: ") return jira_domain, HTTPBasicAuth(email, api_token) def attach_files_to_issues(jira_domain, auth, csv_filepath): """Attaches files to Jira issues based on data from a CSV file.""" base_url = f"https://{jira_domain}/rest/api/2/issue/" try: with open(csv_filepath, 'r', newline='', encoding='utf-8-sig') as csvfile: reader = csv.DictReader(csvfile) for row in reader: issue_key = row['Issue Key'] filepath = row['Filename'] url = f"{base_url}{issue_key}/attachments" headers = { "Accept": "application/json", "X-Atlassian-Token": "no-check" } try: with open(filepath, 'rb') as file_content: files = {"file": (os.path.basename(filepath), file_content)} response = requests.post(url, headers=headers, auth=auth, files=files) response.raise_for_status() logging.info(f"Attachment {filepath} added to issue {issue_key} successfully:") except requests.exceptions.RequestException as e: logging.error(f"Error attaching {filepath} to {issue_key}: {e}") if response.status_code == 404: logging.error(f"Issue {issue_key} might not exist or you might not have permission.") elif response.status_code == 403: logging.error(f"Authentication failed, please verify your email and API token.") except FileNotFoundError: logging.error(f"Error: File '{filepath}' not found. Please double-check the file path.") except KeyError as e: logging.error(f"Error: CSV file is missing a required column: {e}") except Exception as e: logging.exception(f"An unexpected error occurred during attachment upload: {e}") except FileNotFoundError: logging.error(f"Error: CSV file '{csv_filepath}' not found. Please double-check the file path.") except Exception as e: logging.exception(f"An unexpected error occurred during CSV processing: {e}") def main(): jira_domain, auth = get_jira_auth() while True: csv_filepath = input(""" Enter the path to your CSV file. The CSV must have columns named "Issue Key" and "Filename". The "Filename" column must contain valid paths to your attachment files (either relative or absolute). Examples: 1. CSV in the same directory as the script: attachments.csv 2. CSV in a subdirectory called "data": data/attachments.csv 3. Full path to the CSV: /path/to/your/attachments.csv CSV File Path: """) if csv_filepath.lower().endswith(".csv"): break else: print("Invalid file type. Please enter a CSV file.") attach_files_to_issues(jira_domain, auth, csv_filepath) if __name__ == "__main__": main()
Disclaimer:
While this script is designed to facilitate certain interactions with JIRA Software Cloud as a convenience, it is essential to understand that its functionality is subject to change due to updates to JIRA Software Cloud’s API or other conditions that could affect its operation.
Please note that this script is provided on an "as is" and "as available" basis without any warranties of any kind. This script is not officially supported or endorsed by Atlassian, and its use is at your own discretion and risk.
Cheers!
Delfino Rosales
Senior Cloud Support Engineer
Amsterdam, NL
2 comments