diff --git a/pipekit/db.py b/pipekit/db.py index dfa48ff..e85f24f 100644 --- a/pipekit/db.py +++ b/pipekit/db.py @@ -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):