Skip to content

Jira API Tips and Tricks

This document provides useful tips and code snippets for working with the Jira API using Python.

Use Cases

Here are some common use cases for the provided Jira API scripts:

  1. Find several subtasks with descriptions containing specific links:
    * This can be useful for identifying subtasks that need to be processed or analyzed based on the links provided in their descriptions. For example, you might need to find all subtasks that have a link to a particular document or system.

  2. Automatically close several tasks in Jira:
    * This is helpful for automating the process of closing multiple tasks that meet certain criteria. For example, you might want to close all subtasks associated with a completed project, or close a batch of tickets that were created in error. The script allows you to set the status, add a comment (optionally mentioning the reporter), and assign the closed tasks to a specific user.

Prerequisites

Before you begin, ensure you have the following installed and configured:

  1. Python:
    * Install the latest version of Python from the official website: https://www.python.org/downloads/
    * This guide has been tested with Python version 3.13.3.

  2. Jira Python Library:
    * Install the jira module using pip:

      ```bash
      py -m pip install jira
      ```
    
  3. Jira API Token:
    * Generate an API token in your Jira account.
    * You can create an API token here: https://id.atlassian.com/manage-profile/security/api-tokens
    * When creating the token, you might need to configure the scopes, or you can create a token without any specific scopes, depending on your Jira setup and the required permissions.
    * Store this token securely, as it grants access to your Jira account.

How to Export Subtask Descriptions to CSV

This script exports the "Ticket Name," "Link," and "Description" of all subtasks for a given parent issue to a CSV file.

How to Configure and Use the Script

  1. Import Libraries: Imports the csv and JIRA libraries.
  2. Jira Connection:
    * server: Set this to your Jira instance URL (e.g., 'https://majority.atlassian.net').
    * basic_auth: Replace <YOUR_FIRST_NAME.YOUR_SECOND_NAME>@majority.com and <YOUR_API_TOKEN> with your Jira email address and the API token you generated.
  3. Parent Issue Key:
    * issue_key: Replace <ISSUE_NUMBER> with the key of the parent Jira issue (e.g., 'COI-123').
  4. Base URL:
    * base_url: This is used to construct the links to the subtasks. It should match your Jira instance URL.
  5. Run the script: Execute the python script.
  6. Check the output: A file named "subtasks.csv" will be created in the same directory as the script.
import csv
from jira import JIRA

# JIRA credentials and setup
jira = JIRA(
    server='https://majority.atlassian.net',
    basic_auth=('<YOUR_FIRST_NAME.YOUR_SECOND_NAME>@majority.com', '<YOUR_API_TOKEN>')
)

# Parent issue key
issue_key = '<ISSUE_NUMBER>'  # Please
base_url = '[https://majority.atlassian.net/browse/](https://majority.atlassian.net/browse/)'

# Fetch parent issue
issue = jira.issue(issue_key)

# Prepare data
subtask_data = []

for subtask in issue.fields.subtasks:
    sub_issue = jira.issue(subtask.key)
    subtask_data.append({
        'Ticket Name': subtask.key,
        'Link': f"{base_url}{subtask.key}",
        'Description': sub_issue.fields.description or ''
    })

# Write to CSV
with open('subtasks.csv', mode='w', newline='', encoding='utf-8') as file:
    writer = csv.DictWriter(file, fieldnames=['Ticket Name', 'Link', 'Description'])
    writer.writeheader()
    writer.writerows(subtask_data)

print("CSV export complete: subtasks.csv")

How to Automatically Close Several Tasks in Jira

This script reads a CSV file containing a list of Jira ticket names and automatically transitions those tickets to the "Done" status, but only if they are currently in the "Backlog" status. It also adds a comment to each closed ticket, mentioning the reporter.

How to Configure and Use the Script

  1. Import Libraries: Imports the csv and JIRA libraries.
  2. Jira Connection:
    * JIRA_URL: Replace 'https://majority.atlassian.net' with your Jira instance URL.
    * JIRA_USERNAME: Replace '<YOUR_FIRST_NAME.YOUR_SECOND_NAME>@majority.com' with your Jira username (email address).
    * JIRA_PASSWORD: Replace '<YOUR_API_OR_PASSWORD>' with your Jira API token.
    * CSV_FILE_PATH: Replace '<PATH_TO_CSV_FILE>' with the path to your CSV file (e.g., 'jira_tasks_to_close - Sheet1.csv').
    * ASSIGNEE_USERNAME: Replace '<ASSIGNEE_FIRST_NAME.ASSIGNEE_SECOND_NAME>@majority.com' with the username to assign the closed issues to.
    * DONE_STATUS_NAME: Set this to the name of your "Done" status in Jira (e.g., 'Done', 'Closed', etc.).
    * BACKLOG_STATUS_NAME: Set this to the name of your "Backlog" status in Jira.
    * TICKET_NAME_COLUMN: Replace '<THE_COLUMN_NAME_IN_CSV>' with the name of the column in your CSV file that contains the Jira ticket names (e.g., 'Ticket Name', 'Issue Key', etc.).
  3. CSV File:
    * Create a CSV file containing the Jira ticket names you want to close.
    * Ensure the CSV file has a header row, and that the column containing the ticket names matches the value you set for TICKET_NAME_COLUMN.
    * The script assumes the ticket names start with "COI-".
  4. Run the script: Execute the python script.
  5. Check the output: The script will print its progress to the console, indicating which tickets are being processed, skipped, or closed. It will also log any errors that occur.
import csv
from jira import JIRA

# --- Configuration ---
JIRA_URL = 'https://majority.atlassian.net'  # Replace with your Jira instance URL
JIRA_USERNAME = '<YOUR_FIRST_NAME.YOUR_SECOND_NAME>@majority.com'  # Replace with your Jira username
JIRA_PASSWORD = '<YOUR_API_OR_PASSWORD>'  # Replace with your Jira API token or password
CSV_FILE_PATH = '<PATH_TO_CSV_FILE>'  # Replace with the path to your CSV file
ASSIGNEE_USERNAME = '<ASSIGNEE_FIRST_NAME.ASSIGNEE_SECOND_NAME>@majority.com'  # Replace with your Jira username
DONE_STATUS_NAME = 'Done'
BACKLOG_STATUS_NAME = 'Backlog'
TICKET_NAME_COLUMN = '<THE_COLUMN_NAME_IN_CSV>'  # Define the column name for ticket names from the CSV

# --- Initialize Jira API ---
try:
    jira = JIRA(server=JIRA_URL, basic_auth=(JIRA_USERNAME, JIRA_PASSWORD))
    print("Successfully connected to Jira.")
except Exception as e:
    print(f"Error connecting to Jira: {e}")
    exit()

# --- Function to find Jira issue ---
def find_jira_issue(issue_key):
    try:
        issue = jira.issue(issue_key)
        return issue
    except Exception as e:
        print(f"Error finding issue {issue_key}: e")
        return None

# --- Function to change assignee ---
def change_assignee(issue, assignee_username):
    try:
        jira.assign_issue(issue, assignee_username)
        print(f"Successfully assigned {issue.key} to {assignee_username}.")
    except Exception as e:
        print(f"Error assigning {issue.key} to {assignee_username}: e")

# --- Function to add comment ---
def add_comment(issue, comment_text, reporter_account_id=None):
    comment = comment_text
    if reporter_account_id:
        comment = f"{comment} [~accountid:{reporter_account_id}]"
    try:
        jira.add_comment(issue, comment)
        print(f"Successfully added comment to {issue.key}.")
    except Exception as e:
        print(f"Error adding comment to {issue.key}: e")

# --- Function to transition issue to 'Done' ---
def transition_to_done(issue, done_status_name):
    transitions = jira.transitions(issue)
    done_transition = None

    for transition in transitions:
        if transition['name'] == done_status_name:
            done_transition = transition['id']
            break

    if done_transition:
        try:
            jira.transition_issue(issue, done_transition)
            print(f"Successfully transitioned {issue.key} to '{done_status_name}'.")
        except Exception as e:
            print(f"Error transitioning {issue.key}: e")
    else:
        print(f"Could not find '{done_status_name}' transition for {issue.key}.")

# --- Main script ---
with open(CSV_FILE_PATH, 'r', newline='', encoding='utf-8') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        if TICKET_NAME_COLUMN in row:
            ticket_name = row[TICKET_NAME_COLUMN].strip()
            if ticket_name.startswith("COI-"):
                print(f"\nProcessing ticket name: {ticket_name}")
                jira_issue = find_jira_issue(ticket_name)
                if jira_issue:
                    current_status = jira_issue.fields.status.name
                    if current_status == BACKLOG_STATUS_NAME:
                        print(f"{ticket_name} is in '{BACKLOG_STATUS_NAME}' status. Proceeding with actions.")
                        change_assignee(jira_issue, ASSIGNEE_USERNAME)
                        # Get reporter account ID from Jira issue
                        reporter_account_id = jira_issue.fields.reporter.accountId
                        add_comment(jira_issue, "Transaction is canceled", reporter_account_id)
                        transition_to_done(jira_issue, DONE_STATUS_NAME)
                    else:
                        print(f"Skipping {ticket_name} as it is in '{current_status}' status, not '{BACKLOG_STATUS_NAME}'.")
                else:
                    print(f"Could not find Jira issue for {ticket_name}.")
            else:
                print(f"Skipping '{ticket_name}' as it does not start with 'COI-'.")
        else:
            print(f"Error: '{TICKET_NAME_COLUMN}' column not found in the CSV file.")
            break

print("\nScript execution finished.")