Extract Project Information using Python and Atlassian API
Platform Notice: Cloud - This article applies to Atlassian products on the cloud platform.
Disclaimer
Atlassian does not support this code below, which is provided "AS IS". The goal of this article is to provide a piece of code that illustrates one way to achieve the desired goal.
Feedback provided at the bottom of the page is appreciated, but won't be handled as support.
Summary
The Python script on this page retrieves specific project information:
- Project ID
- Project Name
- Project Key
- Project Lead
- Workflow scheme associated to the project
- Total Issue Count per project
- Last Issue Update per project
- Issue Types per project
Environment
- Jira Cloud
- This script requires Python 3 to be installed
- The script uses the Jira Cloud Platform API
Usage
The Python script requires a API_TOKEN: Manage API tokens for your Atlassian account
User with Administrative Access to the instance: Permissions
For large instances, the process can take a while, since there is a execution delay of 1 second between the calls, to avoid timeout/Too Many Request error
import requests
from requests.auth import HTTPBasicAuth
import csv
import json
import time # Import time module to use for adding delays
# Replace with your Jira credentials and URL
JIRA_URL = "https://<instance>.atlassian.net"
API_PROJECTS_ENDPOINT = "/rest/api/3/project/search"
API_WORKFLOW_ENDPOINT = "/rest/api/3/workflowscheme/project"
USERNAME = "<email_address>"
API_TOKEN = "<API_TOKEN>"
# Delay time in seconds (customize as needed)
DELAY_TIME = 1 # 2-second delay between API calls
# Jira API headers
headers = {
"Accept": "application/json"
}
# Function to get the workflow scheme for a project by project ID
def get_workflow_for_project(project_id):
url = f"{JIRA_URL}{API_WORKFLOW_ENDPOINT}?projectId={project_id}"
response = requests.get(url, headers=headers, auth=HTTPBasicAuth(USERNAME, API_TOKEN))
if response.status_code != 200:
print(f"Failed to fetch workflow for project ID {project_id}. Status code: {response.status_code}")
return "N/A"
data = response.json()
# Ensure "values" exist and has at least one item
if "values" in data and len(data['values']) > 0:
workflow_scheme = data['values'][0].get('workflowScheme', {})
return workflow_scheme.get('name', 'N/A') # Get the workflow scheme name
else:
return "N/A"
# Function to extract issue types for a project
def get_issue_types_for_project(project):
issue_types = project.get('issueTypes', [])
# Extract the names of all issue types and join them with commas
issue_type_names = [issue_type.get('name') for issue_type in issue_types]
return ", ".join(issue_type_names) if issue_type_names else "N/A"
# Function to get paginated projects
def get_paginated_projects():
start_at = 0
max_results = 50 # Adjust as needed
all_projects = []
total_projects = None # Initialize total projects as None initially
while True:
# Set the API URL with pagination and expand parameters
url = f"{JIRA_URL}{API_PROJECTS_ENDPOINT}?expand=lead,insight,issueTypes&startAt={start_at}&maxResults={max_results}"
# Send a GET request to the Jira API
response = requests.get(url, headers=headers, auth=HTTPBasicAuth(USERNAME, API_TOKEN))
if response.status_code != 200:
print(f"Failed to fetch projects. Status code: {response.status_code}, Response: {response.text}")
break
# Parse the response JSON
data = response.json()
# Set total projects on the first API call
if total_projects is None:
total_projects = data['total']
print(f"Total number of projects to fetch: {total_projects}")
# Extract the required fields and fetch workflow scheme and issue types
for project in data['values']:
project_id = project.get('id') # Get the project ID
workflow_name = get_workflow_for_project(project_id) # Get the workflow scheme for this project
insight = project.get('insight', {})
issue_types = get_issue_types_for_project(project) # Get the issue types for this project
project_info = {
"Project Key": project.get('key'),
"Project ID": project.get('id'),
"Project Name": project.get('name'),
"Project Lead": project.get('lead', {}).get('displayName', 'N/A'),
"totalIssueCount": insight.get('totalIssueCount', 'N/A'),
"lastIssueUpdateTime": insight.get('lastIssueUpdateTime', 'N/A'),
"Assigned Workflow": workflow_name, # Add the workflow scheme name
"issueTypes": issue_types # Add the issue types
}
all_projects.append(project_info)
# Print progress after each API call
print(f"Fetched {len(all_projects)} projects out of {total_projects} so far.")
# Check if there are more results to fetch
if len(data['values']) < max_results:
break # No more pages to fetch
# Increment the starting index for pagination
start_at += max_results
# Add delay between consecutive API requests
time.sleep(DELAY_TIME) # Delay between requests
return all_projects
# Function to export data to CSV
def export_to_csv(projects, file_name="projects_with_lead_insight_workflow_issuetypes.csv"):
# Define the CSV file headers
headers = ["Project Key", "Project ID", "Project Name", "Project Lead", "totalIssueCount", "lastIssueUpdateTime", "Assigned Workflow", "issueTypes"]
# Write to CSV
with open(file_name, mode='w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=headers)
# Write the header row
writer.writeheader()
# Write project data rows
for project in projects:
writer.writerow(project)
# Fetch all paginated projects
projects = get_paginated_projects()
# Export the data to a CSV file
export_to_csv(projects, "jira_projects_with_lead_insight_workflow_issuetypes.csv")
print(f"Exported {len(projects)} projects to 'jira_projects_with_lead_insight_workflow_issuetypes.csv'")