Use CPMigrate in CI with JSON-only output and stable exit codes
Infrastructure teams do not need another hand-parsed CLI. CPMigrate already supports JSON output, quiet mode, dependency analysis, and exit codes suitable for gates and scheduled checks.
cpmigrate --analyze --audit --outdated --deprecated --output Json --quiet > analysis.json
GitHub Actions example
- name: Install CPMigrate
run: dotnet tool install --global CPMigrate
- name: Analyze dependency health
run: cpmigrate --analyze --audit --outdated --deprecated --output Json --quiet > analysis.json
Gate a migration PR on the resolved graph
A migration pull request is sixty changed project files, and git diff cannot answer the only question a reviewer has: does this change what we ship? It can. --conflict-strategy Highest is the default, and when two projects disagree about a package version one of them is silently upgraded.
--verify restores before and after the migration, diffs the fully-resolved package graph per project and target framework, and attributes every version that moved to the decision that caused it. Anything unaccounted for exits 9 and rolls the migration back, so a failed job leaves the tree as it found it.
- name: Migrate and verify
id: migrate
run: |
set +e
cpmigrate -s ./MySolution.sln --verify --force --output Markdown --quiet > receipt.md
echo "exit_code=$?" >> "$GITHUB_OUTPUT"
- name: Publish the receipt
if: always() && hashFiles('receipt.md') != ''
run: cat receipt.md >> "$GITHUB_STEP_SUMMARY"
- name: Require an accounted-for graph
run: |
code="${{ steps.migrate.outputs.exit_code }}"
[ "$code" = "0" ] || { echo "::error::resolved graph moved unexplained (exit $code)"; exit 1; }
Add --verify-strict when the migration must be a literal no-op — then any graph change fails, even one the receipt explains. Verification costs two full solution restores, which is why it is opt-in.