Repository navigation
refactor: extract _require_ai helper to deduplicate API key validation - #13
Merged
Merged
Conversation
Characterization
…-record-rollback) Adds a migradiff_history table recorded in target databases via migra/history.py, plus CLI flags to view history, record generated migrations, chain migrations across environments with conflict detection, and close the audit loop on executed rollbacks. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Both files still described v1.5.1 as current and --explain-drift/ multi-language README as future work, even though v1.7.2 is on PyPI and both features shipped long ago. Updates completed-features, current version, roadmap, version history, and known limitations (including that docker-compose.yml is referenced but missing from the repo) to match the real code and CHANGELOG. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CLAUDE.md documents build/test/lint commands and the core diff-engine, CLI, history-tracking, and AI-feature architecture for future agent sessions. decisions.md and status.md are empty/lightweight tracking docs to log decisions and branch status going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add migration state tracking (--status, --history, --promote, --record-rollback)
The GitHub Actions CI workflow only triggered on push/PR to `master`, but `main` is the repo's actual default branch (confirmed via `gh repo view --json defaultBranchRef`). PRs targeting `main` — like the one that just merged the migration state tracking feature — got no CI run at all. Adds `main` to the trigger branches alongside `master` and documents the finding in CI_NOTES.md, including that `main` still lacks the branch protection rule that `master` has (a separate repo-settings change, not covered here). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fix: run CI on main in addition to master
Three s.execute() calls passed raw strings directly instead of wrapping them in sqlalchemy.text(). SQLAlchemy 1.4 (installed locally) only warns about this; SQLAlchemy 2.x — which CI resolves to since pyproject.toml pins sqlalchemy to "*" — raises ArgumentError and fails the test. Verified against SQLAlchemy 2.0.51 in an isolated venv: these 3 tests plus the other 2 new test files (32 tests total) and the full 342-test suite all pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…hemy2-text fix: wrap raw SQL in text() in test_history.py for SQLAlchemy 2.x
Closes the gap where MigraDiff only ever generated SQL and left users to pipe it to psql themselves, with no reliable way to know whether migradiff_history reflected a migration that actually ran. --apply executes the generated migration against dburl_from (the database being migrated, matching the CLI's own help text and the README's psql dburl_from < migration.sql convention) inside a single transaction -- any failing statement rolls back everything, and nothing is recorded, so migradiff_history only ever reflects migrations that were confirmed applied. On success it auto-records history against dburl_from without needing a separate --record-history call. Rejected up front with --from-file (dburl_from would be an ephemeral throwaway database) and --promote (the chain's from/to direction isn't yet reconciled with which database --apply should execute against -- tracked as a follow-up in PROJECT_PLAN.md rather than guessed at here). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat: add --apply flag to execute migrations directly
--schema public,reporting was documented as supported but the raw comma-joined string was passed straight through to schemainspect's filter_schema(), which compares it for exact equality against each object's schema name -- "public,reporting" never equals "public" or "reporting", so the diff was always empty with no error. Single-schema and no-schema calls were never affected. Adds parse_schema_arg()/filter_inspector_schemas() in migra/util.py (the latter reuses schemainspect's own PROPS list rather than a hardcoded copy, so it can't drift out of sync) and _get_inspector() in migra/migra.py, wired into all 5 of Migration's inspector-construction call sites. Single/no-schema calls pass straight through to the original get_inspector() unchanged; only 2+ comma-separated names take the new post-filter path. New tests each include a third, unlisted schema in the fixture data to prove real filtering rather than "happens to work with one schema", and exercise both the CLI path and Migration.apply() directly. Co-Authored-By: Claude Sonnet 5 <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.
Summary
Extracts 6 duplicated AI key validation blocks into a single
_require_ai()helper function inmigra/command.py.Before
Each of the 6 AI modes (
--explain-drift,--generate,--advisex2,--explain,--rollback) had its own inline block that:anthropicpackage was installedresolve_api_key(cli_key=args.api_key)--setup-aior settingANTHROPIC_API_KEYAfter
A single shared helper at
command.py:279:Impact
Diff
-149 / +48lines inmigra/command.py