"""delivery infra: pipeline runs, steps, releases, app runtimes Revision ID: a3b4c5d6e7f3 Revises: a0f0e1d2c3b4 Create Date: 2026-10-13 23:59:00.000000 Owned by the delivery workstream (PLAN-v2 ยง6). ``down_revision`` is the v2 foundation; Claude adds the merge revision when the three branches land. """ from __future__ import annotations from collections.abc import Sequence import sqlalchemy as sa from alembic import op revision: str = "a3b4c5d6e7f3" down_revision: str | None = "a0f0e1d2c3b4" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: op.create_table( "pipeline_runs", sa.Column("id", sa.String(length=32), primary_key=True), sa.Column( "organization_id", sa.String(length=32), sa.ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "project_id", sa.String(length=32), sa.ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, ), sa.Column("trigger", sa.String(length=16), nullable=False, server_default="engine"), sa.Column("branch", sa.String(length=120), nullable=False, server_default="dev"), sa.Column("sha", sa.String(length=64), nullable=False, server_default=""), sa.Column("status", sa.String(length=16), nullable=False, server_default="queued"), sa.Column("error_summary", sa.Text(), nullable=False, server_default=""), sa.Column("started_at", sa.DateTime(timezone=True), nullable=True), sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), ) op.create_index("ix_pipeline_runs_organization_id", "pipeline_runs", ["organization_id"]) op.create_index("ix_pipeline_runs_project_id", "pipeline_runs", ["project_id"]) op.create_index( "ix_pipeline_run_project_status", "pipeline_runs", ["project_id", "status"] ) op.create_index( "ix_pipeline_run_org_created", "pipeline_runs", ["organization_id", "created_at"] ) op.create_table( "pipeline_steps", sa.Column("id", sa.String(length=32), primary_key=True), sa.Column( "run_id", sa.String(length=32), sa.ForeignKey("pipeline_runs.id", ondelete="CASCADE"), nullable=False, ), sa.Column("index", sa.Integer(), nullable=False), sa.Column("name", sa.String(length=48), nullable=False), sa.Column("status", sa.String(length=16), nullable=False, server_default="pending"), sa.Column("exit_code", sa.Integer(), nullable=True), sa.Column("log_tail", sa.Text(), nullable=False, server_default=""), sa.Column("started_at", sa.DateTime(timezone=True), nullable=True), sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True), ) op.create_index("ix_pipeline_steps_run_id", "pipeline_steps", ["run_id"]) op.create_index("ix_pipeline_step_run_index", "pipeline_steps", ["run_id", "index"]) op.create_table( "releases", sa.Column("id", sa.String(length=32), primary_key=True), sa.Column( "organization_id", sa.String(length=32), sa.ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "project_id", sa.String(length=32), sa.ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "run_id", sa.String(length=32), sa.ForeignKey("pipeline_runs.id", ondelete="CASCADE"), nullable=False, ), sa.Column("sha", sa.String(length=64), nullable=False), sa.Column("artifact_path", sa.String(length=512), nullable=False, server_default=""), sa.Column( "is_demo_live", sa.Boolean(), nullable=False, server_default=sa.false() ), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), ) op.create_index("ix_releases_organization_id", "releases", ["organization_id"]) op.create_index("ix_releases_project_id", "releases", ["project_id"]) op.create_index("ix_releases_run_id", "releases", ["run_id"]) op.create_index("ix_release_project_created", "releases", ["project_id", "created_at"]) op.create_table( "app_runtimes", sa.Column( "project_id", sa.String(length=32), sa.ForeignKey("projects.id", ondelete="CASCADE"), primary_key=True, ), sa.Column( "organization_id", sa.String(length=32), sa.ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, ), sa.Column("demo_container_id", sa.String(length=160), nullable=True), sa.Column("host_port", sa.Integer(), nullable=True), sa.Column("demo_host", sa.String(length=255), nullable=False, server_default=""), sa.Column( "status", sa.String(length=16), nullable=False, server_default="provisioning" ), sa.Column( "current_release_id", sa.String(length=32), sa.ForeignKey("releases.id", ondelete="SET NULL"), nullable=True, ), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), ) op.create_index("ix_app_runtimes_organization_id", "app_runtimes", ["organization_id"]) op.create_index("ix_app_runtime_org", "app_runtimes", ["organization_id"]) def downgrade() -> None: op.drop_table("app_runtimes") op.drop_table("releases") op.drop_table("pipeline_steps") op.drop_table("pipeline_runs")