Migrate group_run.status to allow 'dry_run'
schema.sql has carried 'dry_run' in the group_run.status CHECK for a while, but CREATE TABLE IF NOT EXISTS never re-applies a constraint to a database that already has the table. Any DB created before that value was added kept the old four-value CHECK, so run_group's `final = "dry_run"` (runner.py:230) hit an IntegrityError in finish_group_run on every group dry run. The per-module work was unaffected -- run_log already permits 'dry_run', so each member recorded its resolved source and merge SQL correctly. Only the group-level bookkeeping failed, leaving the group_run row stuck at 'running'. Via the web UI the failure was invisible: _run_group_in_background swallows the exception and writes status='error', mislabeling a successful dry run. SQLite has no ALTER for CHECK constraints, so this rebuilds the table, the same treatment run_log received earlier. Idempotent on the constraint text, so it runs once. Verified on the live DB: 10,209 rows preserved, no foreign key violations, sqlite_sequence intact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e4c17bfc98
commit
ae959aedad
@ -48,6 +48,31 @@ def _apply_migrations(conn: sqlite3.Connection) -> None:
|
||||
if "last_fired_at" not in sc_cols:
|
||||
conn.execute("ALTER TABLE schedule ADD COLUMN last_fired_at TEXT")
|
||||
|
||||
# group_run.status predates 'dry_run'. schema.sql carries the correct CHECK, but
|
||||
# CREATE TABLE IF NOT EXISTS never re-applies it to an existing DB, so a group
|
||||
# dry run raised IntegrityError in finish_group_run. CHECK constraints need a
|
||||
# table rebuild (SQLite has no ALTER for them); run_log got the same treatment
|
||||
# earlier. Idempotent: keyed on the constraint text itself.
|
||||
gr_ddl = conn.execute(
|
||||
"SELECT sql FROM sqlite_master WHERE type='table' AND name='group_run'"
|
||||
).fetchone()
|
||||
if gr_ddl and "dry_run" not in gr_ddl[0]:
|
||||
conn.executescript("""
|
||||
CREATE TABLE group_run_new (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
group_id INTEGER NOT NULL REFERENCES grp(id),
|
||||
started_at TEXT DEFAULT (datetime('now')),
|
||||
finished_at TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'running'
|
||||
CHECK (status IN ('running','success','error','cancelled','dry_run')),
|
||||
triggered_by TEXT
|
||||
);
|
||||
INSERT INTO group_run_new (id, group_id, started_at, finished_at, status, triggered_by)
|
||||
SELECT id, group_id, started_at, finished_at, status, triggered_by FROM group_run;
|
||||
DROP TABLE group_run;
|
||||
ALTER TABLE group_run_new RENAME TO group_run;
|
||||
""")
|
||||
|
||||
|
||||
@contextmanager
|
||||
def connect(db_path: Path | None = None):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user