Files
awoooi/scripts/sync_dev_db.py
Your Name 8c4dc7a5a8
Some checks failed
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / tests (push) Successful in 1m5s
CD Pipeline / build-and-deploy (push) Failing after 10m6s
CD Pipeline / post-deploy-checks (push) Has been skipped
chore(rls): 新增 manual script gate 與 canary wave1
2026-05-12 20:23:27 +08:00

115 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""同步 dev DB — 補齊 prod 有但 dev 沒有的表"""
import asyncio
import os
import sys
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import text
DEV_URL = os.environ.get("DEV_DATABASE_URL")
if not DEV_URL:
print("ERROR: DEV_DATABASE_URL not set", file=sys.stderr)
sys.exit(1)
MIGRATIONS = [
("auto_repair_executions", """
CREATE TABLE IF NOT EXISTS auto_repair_executions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
incident_id UUID,
playbook_name TEXT,
status TEXT NOT NULL DEFAULT 'pending',
started_at TIMESTAMPTZ,
finished_at TIMESTAMPTZ,
result JSONB,
error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
("alert_operation_log", """
CREATE TABLE IF NOT EXISTS alert_operation_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_type TEXT NOT NULL,
incident_id UUID,
approval_id UUID,
actor TEXT,
action_detail TEXT,
success BOOLEAN DEFAULT true,
context JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
("playbooks", """
CREATE TABLE IF NOT EXISTS playbooks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
steps JSONB NOT NULL DEFAULT '[]',
tags TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
("drift_reports", """
CREATE TABLE IF NOT EXISTS drift_reports (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
host TEXT NOT NULL,
report_type TEXT NOT NULL DEFAULT 'config',
items JSONB NOT NULL DEFAULT '[]',
summary TEXT,
severity TEXT DEFAULT 'low',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
("pr_reviews", """
CREATE TABLE IF NOT EXISTS pr_reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
repo TEXT NOT NULL,
pr_id TEXT NOT NULL,
review_text TEXT,
model TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
("vector_extension", "CREATE EXTENSION IF NOT EXISTS vector"),
("rag_chunks", """
CREATE TABLE IF NOT EXISTS rag_chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source TEXT NOT NULL,
source_id TEXT NOT NULL,
title TEXT,
chunk_text TEXT NOT NULL,
embedding vector(768),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""),
]
async def main():
engine = create_async_engine(DEV_URL, echo=False)
async with engine.begin() as conn:
r = await conn.execute(text(
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name"
))
existing = {row[0] for row in r}
print(f"dev 現有: {sorted(existing)}")
for name, sql in MIGRATIONS:
try:
await conn.execute(text(sql))
print(f"{name}")
except Exception as e:
print(f"{name}: {e}")
r2 = await conn.execute(text(
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name"
))
final = [row[0] for row in r2]
print(f"\ndev 最終: {final}")
await engine.dispose()
asyncio.run(main())