From d94ddb063fbfafd351fad7fcf955b203886dbca5 Mon Sep 17 00:00:00 2001 From: busya Date: Thu, 11 Jun 2026 16:49:55 +0300 Subject: [PATCH] fix(migrations): bring task_records into Alembic, remove guard workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add d1e2f3a4b5c6 migration: create task_records table matching the TaskRecord model (previously created at runtime by init_db() via Base.metadata.create_all). - Update a5b6c7d8e9f0: down_revision now points to d1e2f3a4b5c6, so task_records exists when this migration runs. Remove the inspector.has_table() guard (no longer needed). - create_all() in init_db() becomes a no-op for task_records — the table is now fully managed by Alembic. --- ...t_null_ondelete_for_task_records_env_fk.py | 10 +++- .../d1e2f3a4b5c6_create_task_records_table.py | 55 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 backend/alembic/versions/d1e2f3a4b5c6_create_task_records_table.py 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')