Skip to content

Instantly share code, notes, and snippets.

@klokie
Last active April 19, 2024 21:53
Show Gist options
  • Save klokie/2cca58329a64aa2371e673aa196aff32 to your computer and use it in GitHub Desktop.
Save klokie/2cca58329a64aa2371e673aa196aff32 to your computer and use it in GitHub Desktop.
Transform a Jira "Back up for cloud" export into a directory of Markdown files including metadata
"""
**Title:** JIRA XML to Markdown Converter
**Description:**
This script processes an XML file exported from JIRA to extract issue details and
generates markdown files for each issue. It specifically handles attributes and
linked nodes to gather comprehensive issue metadata, including project details,
priorities, statuses, and more. The script:
- Maps `CustomFieldOption` values by their IDs to resolve human-readable values
for issue statuses and types.
- Retrieves metadata from `IssueView` nodes linked by issue IDs, such as
assignee, reporter, creation, and update dates.
- Handles variations in the storage of issue descriptions (either as attributes
or child nodes).
- Outputs markdown files organized by project keys, with filenames that include
project keys and slugified titles for easy identification.
**Usage:**
Update the `file_path` variable with the path to your XML file and run the script.
Ensure that all dependencies are installed and the XML structure corresponds to
the expected format used in the script.
"""
import xml.etree.ElementTree as ET
import re
# Helper function to convert strings to kebab-case
def slugify(text):
return re.sub(r"\W+", "-", text).strip("-").lower()
# Load the XML data
FILE_PATH = "path_to_your_file.xml" # Update this path to your actual XML file location
tree = ET.parse(FILE_PATH)
root = tree.getroot()
# Mapping CustomFieldOption values by their IDs
custom_field_options = {}
for option in root.findall(".//CustomFieldOption"):
option_id = option.get("id")
option_value = option.get("value")
if option_id and option_value:
custom_field_options[option_id] = option_value
# Mapping IssueView details by their issue IDs
issue_view_map = {}
for issue_view in root.findall(".//IssueView"):
issue_id = issue_view.get("issue")
if issue_id:
issue_view_map[issue_id] = {
"assignee": issue_view.find("assignee").text
if issue_view.find("assignee") is not None
else "Assignee not specified",
"created": issue_view.find("created").text
if issue_view.find("created") is not None
else "Creation date not specified",
"reporter": issue_view.find("reporter").text
if issue_view.find("reporter") is not None
else "Reporter not specified",
"updated": issue_view.find("updated").text
if issue_view.find("updated") is not None
else "Update date not specified",
}
# Create markdown files with extracted and mapped details
markdown_files = []
for issue in root.findall(".//Issue"):
issue_id = issue.get("id")
project_key = issue.get("projectKey", "Unknown Project")
title = issue.get("summary", "Untitled Issue")
priority = issue.get("priority", "No priority assigned")
status_id = issue.get("status")
type_id = issue.get("type")
status = custom_field_options.get(status_id, "Status not found")
type_issue = custom_field_options.get(type_id, "Type not found")
description = (
issue.get("description")
if "description" in issue.attrib
else (
issue.find("description").text
if issue.find("description") is not None
else "Description not provided"
)
)
issue_view_details = issue_view_map.get(issue_id, {})
assignee = issue_view_details.get("assignee", "Assignee not specified")
reporter = issue_view_details.get("reporter", "Reporter not specified")
created = issue_view_details.get("created", "Creation date not specified")
updated = issue_view_details.get("updated", "Update date not specified")
markdown_content = (
f"## {title}\n\n"
f"**Project:** {project_key}\n"
f"**Priority:** {priority}\n"
f"**Status:** {status}\n"
f"**Type:** {type_issue}\n"
f"**Assignee:** {assignee}\n"
f"**Reporter:** {reporter}\n"
f"**Created:** {created}\n"
f"**Updated:** {updated}\n\n"
f"**Description:**\n{description}\n"
)
markdown_files.append(
{
"filename": f"{project_key}/{project_key}-{issue_id}-{slugify(title)}.md",
"content": markdown_content,
}
)
# Optionally, save these markdown files to disk
for file in markdown_files:
directory = os.path.dirname(file["filename"])
if not os.path.exists(directory):
os.makedirs(directory)
with open(file["filename"], "w", encoding="utf-8") as f:
f.write(file["content"])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment