diff --git a/backend/alembic/versions/a5b6c7d8e9f0_set_null_ondelete_for_task_records_env_fk.py b/backend/alembic/versions/a5b6c7d8e9f0_set_null_ondelete_for_task_records_env_fk.py index ef84b66e..6e93f296 100644 --- a/backend/alembic/versions/a5b6c7d8e9f0_set_null_ondelete_for_task_records_env_fk.py +++ b/backend/alembic/versions/a5b6c7d8e9f0_set_null_ondelete_for_task_records_env_fk.py @@ -1,7 +1,12 @@ """set null ondelete for task_records environment FK +task_records table is now created by prior migration d1e2f3a4b5c6. + +This migration alters the FK to add ondelete='SET NULL' for databases +that were migrated before the FK was defined with ondelete. + Revision ID: a5b6c7d8e9f0 -Revises: c4a3a2f74bfe +Revises: d1e2f3a4b5c6 Create Date: 2026-05-21 18:55:00.000000 """ @@ -9,9 +14,10 @@ from collections.abc import Sequence from alembic import op + # revision identifiers, used by Alembic. revision: str = 'a5b6c7d8e9f0' -down_revision: str | Sequence[str] | None = 'c4a3a2f74bfe' +down_revision: str | Sequence[str] | None = 'd1e2f3a4b5c6' branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None diff --git a/backend/alembic/versions/d1e2f3a4b5c6_create_task_records_table.py b/backend/alembic/versions/d1e2f3a4b5c6_create_task_records_table.py new file mode 100644 index 00000000..55e22f03 --- /dev/null +++ b/backend/alembic/versions/d1e2f3a4b5c6_create_task_records_table.py @@ -0,0 +1,55 @@ +"""create task_records table + +Previously task_records was created at runtime by init_db() → +Base.metadata.create_all(bind=tasks_engine). This broke Alembic +migrations that reference task_records (e.g. a5b6c7d8e9f0) — on a +fresh database, the table didn't exist when migrations ran. + +This migration brings task_records into the Alembic-managed schema. +create_all() becomes a no-op for this table. + +Revision ID: d1e2f3a4b5c6 +Revises: c4a3a2f74bfe +Create Date: 2026-06-11 17:00:00.000000 + +""" +from collections.abc import Sequence + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = 'd1e2f3a4b5c6' +down_revision: str | Sequence[str] | None = 'c4a3a2f74bfe' +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Create task_records table matching TaskRecord model.""" + op.create_table( + 'task_records', + sa.Column('id', sa.String(), nullable=False), + sa.Column('type', sa.String(), nullable=False), + sa.Column('status', sa.String(), nullable=False), + sa.Column('environment_id', sa.String(), nullable=True), + sa.Column('started_at', sa.DateTime(timezone=True), nullable=True), + sa.Column('finished_at', sa.DateTime(timezone=True), nullable=True), + sa.Column('logs', sa.JSON(), nullable=True), + sa.Column('error', sa.String(), nullable=True), + sa.Column('result', sa.JSON(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=True), + sa.Column('params', sa.JSON(), nullable=True), + sa.ForeignKeyConstraint( + ['environment_id'], + ['environments.id'], + ondelete='SET NULL', + name='task_records_environment_id_fkey', + ), + sa.PrimaryKeyConstraint('id'), + ) + + +def downgrade() -> None: + """Drop task_records table.""" + op.drop_table('task_records')