M14: migrate run/revert/status engine (Phase 5)#14
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend IMigrationLedger with RecordAppliedAsync and RemoveAsync, both taking the ambient DbTransaction so a ledger row commits atomically with the migration's own script. SqlServerMigrationLedger implements them against dbo._sqlbound_migrations. The read methods stay transaction-free since they run outside the per-migration transaction migrate run opens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Factor the run/revert/status decision logic into pure, unit-tested functions over the loaded migrations and the applied ledger rows: - MigrationPlan.Create computes the ordered pending set and enforces the two safety rules — checksum drift on an applied migration and a pending migration ordered before an applied one both throw. - MigrationStatusReport.Build classifies each migration as Applied, Pending, Drifted, or Missing. - MigrationReverter.Plan selects the most recently applied migration to roll back, refusing when it is irreversible or its files are gone. MigrationInconsistencyException marks a directory that disagrees with the applied history, distinct from a malformed directory (MigrationFormatException). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MigrationRunner.RunAsync ensures the ledger, plans against the applied history, and applies each pending migration in its own transaction together with its ledger row — a failing script rolls back that one migration (raising MigrationExecutionException) and leaves every earlier one applied. The provider-neutral engine executes scripts as ordinary DbCommands so every provider will share it. The CLI 'migrate run' subcommand wires it for SQL Server through a shared MigrationCli helper that resolves the target, loads the directory, opens the connection, and maps expected failures to exit code 1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MigrationRunner.RevertAsync rolls back the most recently applied migration: it runs the down-script and removes the ledger row in one transaction, refusing (via MigrationReverter) when that migration is irreversible or its files are gone, and no-opping when nothing is applied. The CLI 'migrate revert' subcommand wires it for SQL Server. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MigrationRunner.StatusAsync ensures the ledger, reads the applied rows, and returns MigrationStatusReport.Build's classification. The CLI 'migrate status' subcommand prints each migration's version, name, state (applied/pending/drifted/missing), and applied-on timestamp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update docs/migrations.md and the README for migrate run/revert/status, including the safety rules (checksum drift, out-of-order) and the documented no-GO-splitting limitation. Place the four SQL Server migration integration test classes in one xunit collection so they no longer run in parallel against the shared _sqlbound_migrations table. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second of three in Phase 5. Turns the M13 migration model into a working engine: applies, reverts, and reports migrations, and adds the ledger write side M13 deferred. SQL Server pilot (other providers in M15).
What's here
IMigrationLedgergainsRecordAppliedAsync/RemoveAsync, both taking the ambientDbTransactionso a ledger row commits atomically with the migration's own script. SQL Server implements them; the read methods stay transaction-free.SqlBound.Migrations, unit-tested) — the run/revert/status decision logic factored out of I/O:MigrationPlan.Create→ ordered pending set, throwingMigrationInconsistencyExceptionon checksum drift (an applied migration was edited) or an out-of-order pending migration.MigrationStatusReport.Build→ classifies each migrationApplied/Pending/Drifted/Missing.MigrationReverter.Plan→ picks the most recently applied migration, refusing when it is irreversible or its files are gone.MigrationRunner— provider-neutral executor: applies each pending migration in its own transaction with its ledger row (a failed script rolls back that one migration and stops, raisingMigrationExecutionException); reverts by running the down-script + ledger removal in one transaction; and a read-only status pass.migrate run,migrate revert,migrate statussubcommands via a sharedMigrationClihelper (resolve target, load directory, open connection, map expected failures to exit 1).docs/migrations.mdand README updated for the three commands, the safety rules, and the documented no-GO-splitting limitation.Decisions (as agreed on the plan)
GObatch splitting — each script runs as one command; multi-batch scripts must be split. Keeps the engine provider-neutral; documented, revisitable.statusreports drift/missing rather than failing.Verification
dotnet formatclean.0.5.0-preview.2.Note: the full-suite run caught a concurrency bug the per-class runs masked — the four SQL Server migration test classes mutated the shared
_sqlbound_migrationstable in parallel. Fixed by serializing them into one xunit collection.Deferred to M15: other-provider ledgers and database lifecycle; the transactional-DDL reconciliation (notably MySQL's implicit DDL commits).
🤖 Generated with Claude Code