Skip to content

mona-actions/gh-migration-validator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

GitHub Migration Validator

A GitHub CLI extension for validating GitHub organization and repository migrations by comparing key metrics between source and target repositories. Supports GitHub-to-GitHub and Bitbucket Server (Data Center) to GitHub migrations.

Overview

The GitHub Migration Validator helps ensure that your migration to GitHub 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.

Supported sources:

  • GitHub (organization/repository) — full validation including migration archives
  • Bitbucket Server / Data Center — API-based validation

Documentation

Install

gh extension install mona-actions/gh-migration-validator

Usage

Basic Usage

gh migration-validator \
  --github-source-org "source-org" \
  --github-target-org "target-org" \
  --source-repo "my-repo" \
  --target-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --github-target-pat "ghp_yyy"

With Markdown Output

gh migration-validator \
  --github-source-org "source-org" \
  --github-target-org "target-org" \
  --source-repo "my-repo" \
  --target-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --github-target-pat "ghp_yyy" \
  --markdown-table \
  --markdown-file "validation-report.md"

Skipping LFS Validation

If you want to skip LFS object validation (useful for large repositories or when LFS is not used), use the --no-lfs flag:

gh migration-validator \
  --github-source-org "source-org" \
  --github-target-org "target-org" \
  --source-repo "my-repo" \
  --target-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --github-target-pat "ghp_yyy" \
  --no-lfs

Environment Variables

You can use environment variables instead of flags. All environment variables use the GHMV_ prefix.

Source (GitHub-to-GitHub)

export GHMV_SOURCE_ORGANIZATION="source-org"
export GHMV_SOURCE_TOKEN="ghp_xxx"
export GHMV_SOURCE_REPO="my-repo"
export GHMV_SOURCE_HOSTNAME="https://github.example.com"  # Optional: GitHub Enterprise Server

Target (shared across all subcommands)

export GHMV_TARGET_ORGANIZATION="target-org"
export GHMV_TARGET_TOKEN="ghp_yyy"
export GHMV_TARGET_REPO="my-repo"
export GHMV_TARGET_HOSTNAME="https://github.example.com"  # Optional: GitHub Enterprise Server

Output & Behavior

export GHMV_MARKDOWN_TABLE="true"                  # Output as markdown table
export GHMV_MARKDOWN_FILE="validation-report.md"   # Write markdown to file
export GHMV_NO_LFS="true"                          # Skip LFS validation
export GHMV_STRICT_EXIT="true"                     # Exit code 2 on validation failures
export GHMV_RATE_LIMIT_THRESHOLD="100"             # GitHub API rate limit warning threshold (default: 50, 0 to disable)

Basic Run

gh migration-validator

Strict Exit Mode

Use strict exit mode when you need shell pipelines to detect validation failures. Enable it with the --strict-exit flag or set GHMV_STRICT_EXIT=true to return exit code 2 whenever any validation fails. Without this option the command exits 0 while still reporting failures in the output.

gh migration-validator \
  --github-source-org "source-org" \
  --github-target-org "target-org" \
  --source-repo "my-repo" \
  --target-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --github-target-pat "ghp_yyy" \
  --strict-exit

GitHub App Authentication

For 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"

Enterprise Server Support

For GitHub Enterprise Server:

export GHMV_SOURCE_HOSTNAME="https://github.example.com"

Export and Validation Workflow

The tool provides both export and validation capabilities that work together to enable point-in-time migration validation:

  1. Export: Capture repository data at a specific point in time
  2. 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

Export Usage

gh migration-validator export \
  --github-source-org "source-org" \
  --source-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --format json \
  --output ".exports/my-export.json"

Export with Migration Archive

The tool can also download and analyze migration archives to include additional validation metrics. See the Migration Archive Documentation for detailed information.

Export Options

  • --github-source-org (required): Source organization name
  • --source-repo (required): Source repository name
  • --github-source-pat (required): GitHub token with read permissions
  • --source-hostname (optional): GitHub Enterprise Server URL
  • --format (optional): Export format - json or csv (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
  • --no-lfs (optional): Skip LFS object validation

Note: --download and --archive-path are mutually exclusive. For detailed migration archive usage, see Migration Archive Documentation.

Export Output Formats

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.

Default Export Location

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

Validate-from-Export

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.

Validate-from-Export Usage

gh migration-validator validate-from-export \
  --export-file ".exports/mona-actions_my-repo_export_20251002_144908.json" \
  --github-target-org "target-org" \
  --target-repo "my-repo" \
  --github-target-pat "ghp_yyy"

Using Existing Archive Directory

If you already have an extracted migration archive directory:

gh migration-validator export \
  --github-source-org "source-org" \
  --source-repo "my-repo" \
  --github-source-pat "ghp_xxx" \
  --archive-path "path/to/extracted/migration-archive"

Validate-from-Export Options

  • --export-file (required): Path to the exported JSON file containing source data
  • --github-target-org (required): Target organization name
  • --target-repo (required): Target repository name
  • --github-target-pat (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
  • --markdown-file (optional): Write markdown output to the specified file; uses the same content without the surrounding ```markdown fences
  • --no-lfs (optional): Skip LFS object validation
  • --strict-exit (optional): Exit with status 2 on validation failures

Environment Variables for Validate-from-Export

export GHMV_TARGET_ORGANIZATION="target-org"
export GHMV_TARGET_TOKEN="ghp_yyy"
export GHMV_TARGET_REPO="my-repo"
export GHMV_MARKDOWN_TABLE="true"
export GHMV_MARKDOWN_FILE="validation-report.md"
export GHMV_NO_LFS="true"  # Optional: skip LFS validation

gh migration-validator validate-from-export --export-file "path/to/export.json"

Complete Export and Validation Workflow

  1. Export source data before migration:

    gh migration-validator export \
      --github-source-org "source-org" \
      --source-repo "my-repo" \
      --github-source-pat "ghp_xxx"
  2. Perform your migration (using GitHub's migration tools)

  3. Validate against the export:

    gh migration-validator validate-from-export \
      --export-file ".exports/source-org_my-repo_export_20251002_144908.json" \
      --github-target-org "target-org" \
      --target-repo "my-repo" \
      --github-target-pat "ghp_yyy"

This ensures you're validating against the exact state of the source repository when the migration occurred, regardless of any subsequent changes.

Bitbucket Validation

The bitbucket subcommand validates migrations from Bitbucket (Server / Data Center) to GitHub by comparing API metrics between the source Bitbucket instance and the target GitHub repository. This is useful for verifying that repository data was migrated correctly when moving from Bitbucket to GitHub.

Bitbucket Usage

gh migration-validator bitbucket \
  --bbs-server-url "https://bitbucket.example.com" \
  --bbs-project "PROJ" \
  --bbs-repo "my-repo" \
  --bbs-token "your-bbs-token" \
  --github-target-org "target-org" \
  --target-repo "my-repo" \
  --github-target-pat "ghp_yyy"

Environment Variables for Bitbucket

export GHMV_BBS_SERVER_URL="https://bitbucket.example.com"
export GHMV_BBS_PROJECT="PROJ"
export GHMV_BBS_REPO="my-repo"
export GHMV_BBS_TOKEN="your-bbs-token"
export GHMV_TARGET_ORGANIZATION="target-org"
export GHMV_TARGET_TOKEN="ghp_yyy"
export GHMV_TARGET_REPO="my-repo"
gh migration-validator bitbucket

Bitbucket Options

Bitbucket Source Flags

  • --bbs-server-url / -H (required): Bitbucket Server URL (aligned with GEI bbs2gh)
  • --bbs-project / -p (required): Project key (use ~username for personal repos)
  • --bbs-repo / -r (required): Repository slug
  • --bbs-token / -k (required): Personal access token (or GHMV_BBS_TOKEN)

Shared Target Flags (inherited from root)

  • --github-target-org / -t (required): Target GitHub organization
  • --github-target-pat / -b (required): Target GitHub token (or GHMV_TARGET_TOKEN)
  • --target-repo (required): Target repository name
  • --target-hostname / -v: GitHub Enterprise Server URL (optional)
  • --markdown-table / -m: Output results in markdown format
  • --markdown-file: Write markdown output to the specified file
  • --no-lfs: Skip LFS object validation
  • --strict-exit: Exit with status 2 on validation failures

What Gets Validated (Bitbucket → GitHub)

Metric Status Notes
Pull Requests (Total, Open, Merged, Declined→Closed) ✅ Compared Bitbucket "Declined" maps to GitHub "Closed"
Tags ✅ Compared
Commits ✅ Compared Default branch only
Latest Commit SHA ✅ Compared
Branch Permissions vs Branch Protection Rules ℹ️ Advisory Different concepts — shown for reference only
Webhooks ✅ Compared
Issues ⏭️ Skipped Bitbucket uses Jira, not native issues
Releases ⏭️ Skipped Bitbucket has no equivalent
LFS Objects ⏭️ Skipped TODO

Bitbucket Notes

  • Requires Bitbucket Server 5.5+ (uses Bearer token PAT authentication)
  • The branch permissions comparison is advisory only (ℹ️ INFO) since Bitbucket branch permissions and GitHub branch protection rules are fundamentally different concepts

Migration Archive Support

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.

What Gets Validated

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
  • LFS Objects: Total count of Git LFS (Large File Storage) objects referenced in the repository (can be skipped with --no-lfs flag)
  • Latest Commit SHA: Ensures both repositories have the same latest commit in default branch

Validation Results

  • PASS: Metrics match expected values
  • FAIL: Target is missing data from source
  • ⚠️ WARN: Target has more data than source (usually acceptable)
  • ℹ️ INFO: Advisory comparison only (e.g., Bitbucket branch permissions vs GitHub branch protection)

Output Formats

Console Output

The tool provides a formatted table with colored status indicators and a summary.

Example:

📊 Migration Validation Report

🔄 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
LFS Objects                            | ✅ PASS | 15                                       | 15                                       | 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

❌ Migration validation FAILED - Some data is missing in target

Markdown Output

Use the --markdown-table flag to generate copy-paste ready markdown for documentation.

Dependencies

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT © Mona-Actions

About

CLI Extension that helps validate repository migrations between GitHub products

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages