A GitHub CLI extension for validating GitHub organization and repository migrations by comparing key metrics between source and target repositories.
The GitHub Migration Validator helps ensure that your migration from one GitHub organization/repository to another has been completed successfully. It compares various repository metrics (issues, pull requests, tags, releases, commits) between source and target repositories and provides a detailed validation report.
- Migration Archive Support - Comprehensive guide for enhanced validation using GitHub migration archives
gh extension install mona-actions/gh-migration-validatorgh migration-validator \
--source-organization "source-org" \
--target-organization "target-org" \
--source-repo "my-repo" \
--target-repo "my-repo" \
--source-token "ghp_xxx" \
--target-token "ghp_yyy"gh migration-validator \
--source-organization "source-org" \
--target-organization "target-org" \
--source-repo "my-repo" \
--target-repo "my-repo" \
--source-token "ghp_xxx" \
--target-token "ghp_yyy" \
--markdown-tableYou can use environment variables instead of flags:
export GHMV_SOURCE_ORGANIZATION="source-org"
export GHMV_TARGET_ORGANIZATION="target-org"
export GHMV_SOURCE_TOKEN="ghp_xxx"
export GHMV_TARGET_TOKEN="ghp_yyy"
export GHMV_SOURCE_REPO="my-repo"
export GHMV_TARGET_REPO="my-repo"
export GHMV_MARKDOWN_TABLE="true"
gh migration-validatorFor GitHub App authentication, use environment variables:
# Source GitHub App
export GHMV_SOURCE_APP_ID="123456"
export GHMV_SOURCE_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
export GHMV_SOURCE_INSTALLATION_ID="987654"
# Target GitHub App
export GHMV_TARGET_APP_ID="123457"
export GHMV_TARGET_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
export GHMV_TARGET_INSTALLATION_ID="987655"For GitHub Enterprise Server:
export GHMV_SOURCE_HOSTNAME="https://github.example.com"The tool provides both export and validation capabilities that work together to enable point-in-time migration validation:
- Export: Capture repository data at a specific point in time
- Validate-from-Export: Validate target repositories against exported snapshots
This workflow is particularly useful when:
- The source repository continues to receive changes during migration
- You need to validate against the exact state when migration occurred
- You want to create audit trails of migration validation
gh migration-validator export \
--source-organization "source-org" \
--source-repo "my-repo" \
--source-token "ghp_xxx" \
--format json \
--output ".exports/my-export.json"The tool can also download and analyze migration archives to include additional validation metrics. See the Migration Archive Documentation for detailed information.
--source-organization(required): Source organization name--source-repo(required): Source repository name--source-token(required): GitHub token with read permissions--source-hostname(optional): GitHub Enterprise Server URL--format(optional): Export format -jsonorcsv(default:json)--output(optional): Output file path (auto-generated if not specified)--download(optional): Download and analyze migration archive automatically--download-path(optional): Directory to download migration archives to (default: ./migration-archives)--archive-path(optional): Path to an existing extracted migration archive directory
Note: --download and --archive-path are mutually exclusive. For detailed migration archive usage, see Migration Archive Documentation.
JSON Format:
{
"export_timestamp": "2025-10-13T14:49:08Z",
"repository_data": {
"owner": "source-org",
"name": "my-repo",
"issues": 42,
"pull_requests": {
"open": 5,
"closed": 10,
"merged": 15,
"total": 30
},
"tags": 8,
"releases": 3,
"commits": 150,
"latest_commit_sha": "abc123def456",
"branch_protection_rules": 4,
"webhooks": 2
},
"migration_archive": {
"issues": 42,
"pull_requests": 30,
"protected_branches" : 1,
"releases": 3
}
}When migration archive data is included, the export will contain additional migration_archive metrics. See Migration Archive Documentation for details.
CSV Format:
Contains the same data in CSV format with headers for easy analysis in spreadsheet applications.
When no output file is specified, exports are automatically saved to .exports/ directory with timestamped filenames:
.exports/{owner}_{repo}_export_{timestamp}.{format}
Example: .exports/mona-actions_my-repo_export_20251002_144908.json
The validate-from-export command allows you to validate a target repository against a previously exported snapshot of source repository data. This is essential for validating migrations when the source repository may have changed since the migration occurred.
gh migration-validator validate-from-export \
--export-file ".exports/mona-actions_my-repo_export_20251002_144908.json" \
--target-organization "target-org" \
--target-repo "my-repo" \
--target-token "ghp_yyy"If you already have an extracted migration archive directory:
gh migration-validator export \
--source-organization "source-org" \
--source-repo "my-repo" \
--source-token "ghp_xxx" \
--archive-path "path/to/extracted/migration-archive"--export-file(required): Path to the exported JSON file containing source data--target-organization(required): Target organization name--target-repo(required): Target repository name--target-token(required): GitHub token with read permissions for target--target-hostname(optional): GitHub Enterprise Server URL for target--markdown-table(optional): Output results in markdown format
export GHMV_TARGET_ORGANIZATION="target-org"
export GHMV_TARGET_TOKEN="ghp_yyy"
export GHMV_TARGET_REPO="my-repo"
export GHMV_MARKDOWN_TABLE="true"
gh migration-validator validate-from-export --export-file "path/to/export.json"-
Export source data before migration:
gh migration-validator export \ --source-organization "source-org" \ --source-repo "my-repo" \ --source-token "ghp_xxx"
-
Perform your migration (using GitHub's migration tools)
-
Validate against the export:
gh migration-validator validate-from-export \ --export-file ".exports/source-org_my-repo_export_20251002_144908.json" \ --target-organization "target-org" \ --target-repo "my-repo" \ --target-token "ghp_yyy"
This ensures you're validating against the exact state of the source repository when the migration occurred, regardless of any subsequent changes.
The tool supports working with GitHub migration archives for enhanced validation capabilities. Migration archives provide three-way validation comparing Source API ↔ Archive ↔ Target API data.
For comprehensive documentation on migration archive features, workflow, and usage examples, see Migration Archive Documentation.
The tool compares the following metrics between source and target repositories:
- Issues: Total count (expects +1 in target for migration log issue)
- Pull Requests: Total, Open, Merged, and Closed counts
- Tags: Total count of Git tags
- Releases: Total count of GitHub releases
- Commits: Total commit count on default branch
- Branch Protection Rules: Total count of branch protection rules configured for the repository
- Webhooks: Total count of active repository webhooks
- Latest Commit SHA: Ensures both repositories have the same latest commit in default branch
- ✅ PASS: Metrics match expected values
- ❌ FAIL: Target is missing data from source
⚠️ WARN: Target has more data than source (usually acceptable)
The tool provides a formatted table with colored status indicators and a summary.
Example:
# 🔄 Source vs Target Validation
Metric | Status | Source Value | Target Value | Difference
Issues (expected +1 for migration log) | ⚠️ WARN | 2 (expected target: 3) | 7 | Extra: 4
Pull Requests (Total) | ✅ PASS | 29 | 29 | Perfect match
Pull Requests (Open) | ✅ PASS | 0 | 0 | Perfect match
Pull Requests (Merged) | ✅ PASS | 27 | 27 | Perfect match
Tags | ✅ PASS | 25 | 25 | Perfect match
Releases | ✅ PASS | 25 | 25 | Perfect match
Commits | ✅ PASS | 64 | 64 | Perfect match
Branch Protection Rules | ✅ PASS | 1 | 1 | Perfect match
Webhooks | ✅ PASS | 0 | 0 | Perfect match
Latest Commit SHA | ✅ PASS | d11552345ad4ffea894b59d9a4145a5119d77dba | d11552345ad4ffea894b59d9a4145a5119d77dba | N/A
# 📦 Migration Archive vs Source Validation
Metric | Status | Source API Value | Archive Value | Difference
Archive vs Source Issues | ❌ FAIL | 2 | 6 | Missing: 4
Archive vs Source Pull Requests | ✅ PASS | 29 | 29 | Perfect match
Archive vs Source Protected Branches | ✅ PASS | 1 | 1 | Perfect match
Archive vs Source Releases | ✅ PASS | 25 | 25 | Perfect match
# 🎯 Migration Archive vs Target Validation
Metric | Status | Archive Value | Target Value | Difference
Archive vs Target Issues (expected +1 for migration log) | ✅ PASS | 6 (expected target: 7) | 7 | Perfect match
Archive vs Target Pull Requests | ✅ PASS | 29 | 29 | Perfect match
Archive vs Target Protected Branches | ✅ PASS | 1 | 1 | Perfect match
Archive vs Target Releases | ✅ PASS | 25 | 25 | Perfect match
📊 Passed: 16
📊 Failed: 1
📊 Warnings: 1
ERROR ❌ Migration validation FAILED - Some data is missing in targetUse the --markdown-table flag to generate copy-paste ready markdown for documentation.
- Go 1.20 or higher
- Key dependencies:
- Cobra - CLI framework
- Viper - Configuration management
- go-github - GitHub REST API client
- githubv4 - GitHub GraphQL API client
- go-githubauth - GitHub App authentication
- go-github-ratelimit - Rate limit handling
- pterm - Terminal styling and formatting
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.