Automating CMJ Migrations at Scale: An Open-Source Python Toolkit
TL;DR: After managing multiple large-scale Jira migrations using Configuration Manager for Jira (CMJ), I built a Python toolkit that automates the tedious parts—mapping validation, conflict detection, template generation, and post-migration cleanup. The code is open source on GitHub. This article shares the approach and lessons learned.
The Problem: CMJ Migrations at Scale
If you’ve ever done a Jira Data Center migration using CMJ, you know the pain:
- Hundreds of objects to map: Statuses, custom fields, issue types, resolutions, link types—each needs a decision
- Customer coordination: Someone has to review spreadsheets and make mapping decisions
- Human error: Typos, copy-paste mistakes, and inconsistent naming can silently break a migration
- Post-migration cleanup: CMJ creates objects that need to be deleted, but which ones are safe to remove?
- No audit trail: What got mapped where? What was created vs. deleted?
For a single small project, this is manageable. For enterprise migrations with thousands of objects across multiple projects, it becomes a full-time job.
The Solution: An 11-Step Automated Pipeline
I built a Python toolkit that wraps around CMJ to automate the repetitive work while keeping humans in the loop for decisions that matter.
The Pipeline at a Glance
Phase | Steps | What Happens |
Pre-Deployment | 1–6 | Convert data, process mappings, validate, generate CMJ templates |
Customer Review | Between 3–4 | Customer reviews and approves mapping decisions |
CMJ Deployment | Manual | Import templates, deploy snapshot |
Post-Deployment | 7–11 | Generate cleanup scripts, validate before/after deletion |
Key Automation Features
The toolkit handles four categories of work that are tedious and error-prone when done manually:
- Intelligent Matching
The toolkit automatically matches source objects to target objects using:
- Exact name matching
- Fuzzy matching with confidence scores (e.g., “In Progress” → “InProgress” at 92%)
- Type validation for custom fields (Text → Text, not Text → Number)
Match Results:
EXACT_MATCH: 234 objects (auto-mapped)
FUZZY_MATCH: 45 objects (suggested, needs review)
NO_MATCH: 28 objects (will be created)
- Conflict Detection
Multiple source objects mapping to the same target? The toolkit catches it before it reaches CMJ:
CONFLICTS DETECTED:
Target 'Approved' ← Sources: ['Approved', 'APPROVED', 'approved']
Target 'In Progress' ← Sources: ['In Progress', 'InProgress']
- Customer Review Validation
Before generating CMJ templates, the toolkit validates the customer-reviewed spreadsheet:
Check | Example Error |
Leading/trailing spaces | " Status Name " → trim it |
Copied suggestion text | "Status Name (85%)" → remove percentage |
Invalid actions | "map" → should be "MAP" |
Typos in target names | "Aproved" vs "Approved" in target |
Duplicate targets | Two sources → same target (conflict) |
- Safe Cleanup with JQL Validation
The generated Groovy cleanup script doesn’t blindly delete. It verifies first:
// Before deleting a status, verify no issues use it
def jql = "status = \"Old Status Name\""
def issueCount = countIssues(jql)
if (issueCount > 0) {
println "SKIPPED: ${statusName} - ${issueCount} issues use this status"
} else {
// Safe to delete
statusManager.removeStatus(statusId)
}
Real-World Results
On a recent migration project:
Metric | Manual Approach | With Toolkit |
Objects processed | 500+ | 500+ |
Time to generate mappings | ~8 hours | ~10 minutes |
Human errors caught | Found in UAT | Found before CMJ import |
Cleanup confidence | “Hope nothing breaks” | JQL-validated, audited |
Getting Started
The toolkit is open source and available at GitHub.
Prerequisites
- Python 3.8+
- CMJ installed in target Jira
- ScriptRunner for target data export and cleanup execution
- Access to source and target Jira REST APIs
Quick Start
# Clone the toolkit
git clone <repository-url>
cd cmj_template
# Install dependencies
pip install -r requirements.txt
# Validate your setup
python3 scripts/run_migration.py --validate
# Run interactively
python3 scripts/run_migration.py
The Workflow in Practice
Pre-Deployment: Data Collection (Steps 1–2)
Export data from source and target Jira instances, converting to Excel for the audit trail:
python3 run_migration.py --step 1 # Convert source data
python3 run_migration.py --step 2 # Convert target data
Output: Excel workbooks with all objects, IDs, and metadata—easy to review and share.
Pre-Deployment: Process & Validate (Steps 3–5)
python3 run_migration.py --step 3 # Process customer mapping
# → Customer reviews the PROCESSED.xlsx file
python3 run_migration.py --step 4 # Validate reviewed file
python3 run_migration.py --step 5 # Filter for CMJ template
The validation step is critical. It catches mistakes before they become CMJ import failures.
Pre-Deployment: Generate CMJ Templates (Step 6)
python3 run_migration.py --step 6 # Generate CMJ XML templates
Output: Two CMJ template files ready for import:
- global_cmj_template.cmj — Statuses, Resolutions, Link Types, and Issue Types
- custom_field_cmj_template.cmj — Custom Fields (imported separately due to size)
These templates are generated directly from the validated mapping spreadsheet, ensuring every MAP operation has been reviewed and approved before it touches CMJ. No more manual XML editing or copy-paste errors.
CMJ Deployment
Import both templates into CMJ and deploy your snapshot. This step remains manual—the toolkit hands off cleanly-formatted, validated input so the CMJ deployment itself is straightforward.
Post-Deployment Cleanup (Steps 7–11)
After CMJ deployment, export the new target state and generate the cleanup script:
python3 run_migration.py --step 7 # Convert post-import data
python3 run_migration.py --step 8 # Generate cleanup report
python3 run_migration.py --step 9 # Generate Groovy cleanup script
python3 run_migration.py --step 10 # Validate dryrun output
python3 run_migration.py --step 11 # Validate liverun output
The two-phase validation (dryrun then liverun) ensures nothing gets deleted that shouldn’t be.
Lessons Learned
- Validate Early, Validate Often
The #1 cause of CMJ failures in our experience: bad input data. A typo in a target name, an extra space, a copied suggestion with “(85%)” still attached. Catching these before CMJ import saves hours of debugging.
- Protect What Existed Before
Objects that existed in the target before migration should never be deleted. The toolkit tracks pre-import state and protects those objects during cleanup.
- Trust but Verify (JQL Checks)
Even after careful planning, always verify with JQL before deleting:
- status = "StatusName" → Any issues using this status?
- "FieldName" is not EMPTY → Any issues with data in this field?
- issuetype = "TypeName" → Any issues of this type?
- Keep the Human in the Loop
Automation handles the tedious work. Humans make the decisions:
- Should this source status map to “Done” or “Closed”?
- Is this fuzzy match correct, or should we create a new object?
- Which of these conflicting mappings wins?
None of This Works Without the Right Customer
Tools like this don’t get built—or validated—in a vacuum. A critical ingredient in making this toolkit production-ready was having a customer who was genuinely invested in getting it right.
Ryan Stroup dedicated real time and attention to this effort: reviewing mapping spreadsheets, testing the pipeline against his projects’ actual data, surfacing edge cases that only appear in production environments, and validating that every requirement was met before sign-off. That kind of engaged partnership is what separates a toolkit that works in theory from one you can trust on a live migration.
If you’re planning to adopt this approach, I’d strongly encourage the same model: identify a customer stakeholder who will roll up their sleeves and test alongside you. The automation handles the tedious work—but a willing, thorough collaborator on the customer side is what gives you confidence the output is actually correct.
Built with AI: A Claude Code Story
Full disclosure: this toolkit was built collaboratively with Claude Code, Anthropic’s AI-powered CLI assistant.
What started as a few helper scripts evolved into a comprehensive 11-step pipeline through iterative development with AI assistance. Claude Code helped with:
- Rapid prototyping — Describing what I needed and getting working code in minutes
- Edge case handling — “What if the customer copies the suggestion text with the percentage?” became a validation rule
- Refactoring at scale — Restructuring the entire pipeline from 8 steps to 11 steps with proper validation
- Documentation — Generating consistent docstrings, README updates, and yes, even this article draft
The experience reinforced something important: AI doesn’t replace domain expertise—it amplifies it. I knew what CMJ migrations needed; Claude Code helped me build it faster and with fewer bugs than I could have alone.
If you’re on the fence about using AI tools for Jira administration work, I’d encourage you to try it. The combination of your Jira knowledge and AI’s coding assistance is genuinely powerful.
Conclusion
CMJ is a powerful tool, but it’s only as good as the data you feed it. This toolkit fills the gap between “we have a mapping spreadsheet” and “CMJ templates are ready to import” with:
- Automated matching and validation
- Conflict detection before it’s too late
- Production-ready CMJ XML templates
- Safe, audited post-migration cleanup with JQL validation
- Excel audit trails for everything
Whether you’re migrating one project or fifty, having a repeatable, validated process makes all the difference.
The code is on GitHub. If you run into issues or have improvements, feel free to open an issue or PR.
Questions or feedback? Drop a comment below or reach out directly. I’m always interested in hearing how others are tackling Jira migrations—and whether you’re using AI to help.