Files
MemRelay/backend/migrations/versions/20260804_0007_project_sources.py

97 lines
3.9 KiB
Python

"""Separate project identity from source checkout configuration."""
from collections.abc import Sequence
from urllib.parse import urlsplit
import sqlalchemy as sa
from alembic import op
revision: str = "20260804_0007"
down_revision: str | Sequence[str] | None = "20260804_0006"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def _legacy_clone_url(value: str) -> str:
parsed = urlsplit(value)
if parsed.scheme == "git" and parsed.hostname and parsed.path:
port = f":{parsed.port}" if parsed.port else ""
return f"https://{parsed.hostname}{port}{parsed.path}.git"
return value
def upgrade() -> None:
with op.batch_alter_table("projects") as batch:
batch.add_column(sa.Column("git_remote_normalized", sa.Text()))
batch.add_column(
sa.Column("curation_enabled", sa.Boolean(), nullable=False, server_default=sa.true())
)
batch.add_column(
sa.Column("source_strategy", sa.String(20), nullable=False, server_default="auto")
)
batch.add_column(sa.Column("source_branch", sa.String(200)))
batch.add_column(sa.Column("source_credential_item_id", sa.String(100)))
batch.add_column(sa.Column("source_last_commit", sa.String(64)))
batch.add_column(sa.Column("source_last_branch", sa.String(200)))
batch.add_column(sa.Column("source_last_fetched_at", sa.DateTime(timezone=True)))
batch.add_column(sa.Column("source_last_error", sa.Text()))
batch.add_column(
sa.Column("source_cache_used", sa.Boolean(), nullable=False, server_default=sa.false())
)
batch.add_column(sa.Column("last_agent_sync_at", sa.DateTime(timezone=True)))
batch.add_column(sa.Column("last_agent_branch", sa.String(200)))
batch.add_column(sa.Column("last_agent_commit", sa.String(64)))
batch.add_column(sa.Column("last_agent_dirty", sa.Boolean()))
connection = op.get_bind()
projects = connection.execute(sa.text("SELECT id, git_remote FROM projects")).mappings()
for project in projects:
remote = project["git_remote"]
if not remote:
continue
connection.execute(
sa.text(
"UPDATE projects "
"SET git_remote = :clone_url, git_remote_normalized = :normalized "
"WHERE id = :project_id"
),
{
"clone_url": _legacy_clone_url(remote),
"normalized": remote,
"project_id": project["id"],
},
)
with op.batch_alter_table("projects") as batch:
batch.create_unique_constraint(
"uq_projects_git_remote_normalized", ["git_remote_normalized"]
)
batch.create_index("ix_projects_curation_enabled", ["curation_enabled"])
def downgrade() -> None:
connection = op.get_bind()
connection.execute(
sa.text(
"UPDATE projects SET git_remote = git_remote_normalized "
"WHERE git_remote_normalized IS NOT NULL"
)
)
with op.batch_alter_table("projects") as batch:
batch.drop_index("ix_projects_curation_enabled")
batch.drop_constraint("uq_projects_git_remote_normalized", type_="unique")
batch.drop_column("last_agent_dirty")
batch.drop_column("last_agent_commit")
batch.drop_column("last_agent_branch")
batch.drop_column("last_agent_sync_at")
batch.drop_column("source_cache_used")
batch.drop_column("source_last_error")
batch.drop_column("source_last_fetched_at")
batch.drop_column("source_last_branch")
batch.drop_column("source_last_commit")
batch.drop_column("source_credential_item_id")
batch.drop_column("source_branch")
batch.drop_column("source_strategy")
batch.drop_column("curation_enabled")
batch.drop_column("git_remote_normalized")