trying to rework database migrations
This commit is contained in:
628
scripts/consolidate_migrations.py
Normal file
628
scripts/consolidate_migrations.py
Normal file
@@ -0,0 +1,628 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Migration Consolidation Script
|
||||
|
||||
Consolidates 22 migrations into 13 clean migrations by:
|
||||
1. Removing items created then dropped (runtime_type_enum, workflow_task_execution table, etc.)
|
||||
2. Including items added later in initial table creation (is_adhoc, workflow columns, etc.)
|
||||
3. Moving data insertions to YAML files (runtimes)
|
||||
4. Consolidating incremental additions (webhook columns, notify triggers)
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
# Base directory
|
||||
BASE_DIR = Path(__file__).parent.parent
|
||||
MIGRATIONS_DIR = BASE_DIR / "migrations"
|
||||
MIGRATIONS_OLD_DIR = BASE_DIR / "migrations.old"
|
||||
|
||||
|
||||
def read_migration(filename):
|
||||
"""Read a migration file from the old directory."""
|
||||
path = MIGRATIONS_OLD_DIR / filename
|
||||
if path.exists():
|
||||
return path.read_text()
|
||||
return None
|
||||
|
||||
|
||||
def write_migration(filename, content):
|
||||
"""Write a migration file to the new directory."""
|
||||
path = MIGRATIONS_DIR / filename
|
||||
path.write_text(content)
|
||||
print(f"Created: {filename}")
|
||||
|
||||
|
||||
def extract_section(content, start_marker, end_marker=None):
|
||||
"""Extract a section of SQL between markers."""
|
||||
start = content.find(start_marker)
|
||||
if start == -1:
|
||||
return None
|
||||
|
||||
if end_marker:
|
||||
end = content.find(end_marker, start)
|
||||
if end == -1:
|
||||
end = len(content)
|
||||
else:
|
||||
end = len(content)
|
||||
|
||||
return content[start:end].strip()
|
||||
|
||||
|
||||
def remove_lines_matching(content, patterns):
|
||||
"""Remove lines matching any of the patterns."""
|
||||
lines = content.split("\n")
|
||||
filtered = []
|
||||
skip_until_semicolon = False
|
||||
|
||||
for line in lines:
|
||||
# Check if we should skip this line
|
||||
should_skip = False
|
||||
for pattern in patterns:
|
||||
if pattern in line:
|
||||
should_skip = True
|
||||
# If this line doesn't end with semicolon, skip until we find one
|
||||
if ";" not in line:
|
||||
skip_until_semicolon = True
|
||||
break
|
||||
|
||||
if skip_until_semicolon:
|
||||
if ";" in line:
|
||||
skip_until_semicolon = False
|
||||
continue
|
||||
|
||||
if not should_skip:
|
||||
filtered.append(line)
|
||||
|
||||
return "\n".join(filtered)
|
||||
|
||||
|
||||
def main():
|
||||
print("Starting migration consolidation...")
|
||||
print(f"Reading from: {MIGRATIONS_OLD_DIR}")
|
||||
print(f"Writing to: {MIGRATIONS_DIR}")
|
||||
print()
|
||||
|
||||
# Ensure migrations.old exists
|
||||
if not MIGRATIONS_OLD_DIR.exists():
|
||||
print("ERROR: migrations.old directory not found!")
|
||||
print("Please run: cp -r migrations migrations.old")
|
||||
return
|
||||
|
||||
# Clear the migrations directory except README.md
|
||||
for file in MIGRATIONS_DIR.glob("*.sql"):
|
||||
file.unlink()
|
||||
print("Cleared old migrations from migrations/")
|
||||
print()
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00001: Initial Setup (modified)
|
||||
# ========================================================================
|
||||
|
||||
content_00001 = read_migration("20250101000001_initial_setup.sql")
|
||||
|
||||
# Remove runtime_type_enum
|
||||
content_00001 = remove_lines_matching(
|
||||
content_00001,
|
||||
[
|
||||
"-- RuntimeType enum",
|
||||
"CREATE TYPE runtime_type_enum",
|
||||
"COMMENT ON TYPE runtime_type_enum",
|
||||
],
|
||||
)
|
||||
|
||||
# Add worker_role_enum after worker_type_enum
|
||||
worker_role_enum = """
|
||||
-- WorkerRole enum
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE worker_role_enum AS ENUM (
|
||||
'action',
|
||||
'sensor',
|
||||
'hybrid'
|
||||
);
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
COMMENT ON TYPE worker_role_enum IS 'Role of worker (action executor, sensor, or both)';
|
||||
"""
|
||||
|
||||
# Add pack_environment_status_enum at the end of enums
|
||||
pack_env_enum = """
|
||||
-- PackEnvironmentStatus enum
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE pack_environment_status_enum AS ENUM (
|
||||
'creating',
|
||||
'ready',
|
||||
'failed',
|
||||
'updating',
|
||||
'deleting'
|
||||
);
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
COMMENT ON TYPE pack_environment_status_enum IS 'Status of pack environment setup';
|
||||
"""
|
||||
|
||||
# Insert after worker_type_enum
|
||||
content_00001 = content_00001.replace(
|
||||
"COMMENT ON TYPE worker_type_enum IS 'Type of worker deployment';",
|
||||
"COMMENT ON TYPE worker_type_enum IS 'Type of worker deployment';\n"
|
||||
+ worker_role_enum,
|
||||
)
|
||||
|
||||
# Insert before SHARED FUNCTIONS
|
||||
content_00001 = content_00001.replace(
|
||||
"-- ============================================================================\n-- SHARED FUNCTIONS",
|
||||
pack_env_enum
|
||||
+ "\n-- ============================================================================\n-- SHARED FUNCTIONS",
|
||||
)
|
||||
|
||||
write_migration("20250101000001_initial_setup.sql", content_00001)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00002: Identity and Auth
|
||||
# ========================================================================
|
||||
|
||||
content_00002 = read_migration("20250101000002_core_tables.sql")
|
||||
|
||||
# Extract identity, permission, and policy sections
|
||||
identity_section = extract_section(
|
||||
content_00002, "-- IDENTITY TABLE", "-- PERMISSION_SET TABLE"
|
||||
)
|
||||
permset_section = extract_section(
|
||||
content_00002, "-- PERMISSION_SET TABLE", "-- PERMISSION_ASSIGNMENT TABLE"
|
||||
)
|
||||
permassign_section = extract_section(
|
||||
content_00002, "-- PERMISSION_ASSIGNMENT TABLE", "-- POLICY TABLE"
|
||||
)
|
||||
policy_section = extract_section(content_00002, "-- POLICY TABLE", "-- KEY TABLE")
|
||||
|
||||
migration_00002 = f"""-- Migration: Identity and Authentication
|
||||
-- Description: Creates identity, permission, and policy tables
|
||||
-- Version: 20250101000002
|
||||
|
||||
-- ============================================================================
|
||||
{identity_section}
|
||||
|
||||
-- ============================================================================
|
||||
{permset_section}
|
||||
|
||||
-- ============================================================================
|
||||
{permassign_section}
|
||||
|
||||
-- ============================================================================
|
||||
{policy_section}
|
||||
"""
|
||||
|
||||
write_migration("20250101000002_identity_and_auth.sql", migration_00002)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00003: Pack System
|
||||
# ========================================================================
|
||||
|
||||
pack_section = extract_section(content_00002, "-- PACK TABLE", "-- RUNTIME TABLE")
|
||||
runtime_section = extract_section(
|
||||
content_00002, "-- RUNTIME TABLE", "-- WORKER TABLE"
|
||||
)
|
||||
|
||||
# Modify runtime section
|
||||
runtime_section = remove_lines_matching(
|
||||
runtime_section,
|
||||
[
|
||||
"runtime_type runtime_type_enum NOT NULL,",
|
||||
"runtime_ref_format CHECK (ref ~ '^[^.]+\\.(action|sensor)\\.[^.]+$')",
|
||||
"idx_runtime_type",
|
||||
"idx_runtime_pack_type",
|
||||
"idx_runtime_type_created",
|
||||
],
|
||||
)
|
||||
|
||||
# Add new indexes after idx_runtime_created
|
||||
new_runtime_indexes = """CREATE INDEX idx_runtime_name ON runtime(name);
|
||||
CREATE INDEX idx_runtime_verification ON runtime USING GIN ((distributions->'verification'));
|
||||
"""
|
||||
runtime_section = runtime_section.replace(
|
||||
"CREATE INDEX idx_runtime_created ON runtime(created DESC);",
|
||||
"CREATE INDEX idx_runtime_created ON runtime(created DESC);\n"
|
||||
+ new_runtime_indexes,
|
||||
)
|
||||
|
||||
# Add pack.installers column in pack table
|
||||
pack_section = pack_section.replace(
|
||||
"is_standard BOOLEAN NOT NULL DEFAULT FALSE,",
|
||||
"is_standard BOOLEAN NOT NULL DEFAULT FALSE,\n installers JSONB DEFAULT '[]'::jsonb,",
|
||||
)
|
||||
|
||||
migration_00003 = f"""-- Migration: Pack System
|
||||
-- Description: Creates pack and runtime tables (runtime without runtime_type)
|
||||
-- Version: 20250101000003
|
||||
|
||||
-- ============================================================================
|
||||
{pack_section}
|
||||
|
||||
-- ============================================================================
|
||||
{runtime_section}
|
||||
"""
|
||||
|
||||
write_migration("20250101000003_pack_system.sql", migration_00003)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00004: Action and Sensor
|
||||
# ========================================================================
|
||||
|
||||
content_supporting = read_migration("20250101000005_supporting_tables.sql")
|
||||
|
||||
action_section = extract_section(
|
||||
content_supporting, "-- ACTION TABLE", "-- SENSOR TABLE"
|
||||
)
|
||||
sensor_section = extract_section(
|
||||
content_supporting, "-- SENSOR TABLE", "-- RULE TABLE"
|
||||
)
|
||||
|
||||
# Add is_adhoc to action table
|
||||
action_section = action_section.replace(
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,",
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,\n is_adhoc BOOLEAN DEFAULT false NOT NULL,",
|
||||
)
|
||||
|
||||
# Add is_adhoc to sensor table
|
||||
sensor_section = sensor_section.replace(
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,",
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,\n is_adhoc BOOLEAN DEFAULT false NOT NULL,",
|
||||
)
|
||||
|
||||
migration_00004 = f"""-- Migration: Action and Sensor
|
||||
-- Description: Creates action and sensor tables (with is_adhoc from start)
|
||||
-- Version: 20250101000004
|
||||
|
||||
-- ============================================================================
|
||||
{action_section}
|
||||
|
||||
-- ============================================================================
|
||||
{sensor_section}
|
||||
|
||||
-- Add foreign key constraints for policy and key tables
|
||||
ALTER TABLE policy
|
||||
ADD CONSTRAINT policy_action_fkey
|
||||
FOREIGN KEY (action) REFERENCES action(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE key
|
||||
ADD CONSTRAINT key_owner_action_fkey
|
||||
FOREIGN KEY (owner_action) REFERENCES action(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE key
|
||||
ADD CONSTRAINT key_owner_sensor_fkey
|
||||
FOREIGN KEY (owner_sensor) REFERENCES sensor(id) ON DELETE CASCADE;
|
||||
"""
|
||||
|
||||
write_migration("20250101000004_action_sensor.sql", migration_00004)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00005: Trigger, Event, and Rule
|
||||
# ========================================================================
|
||||
|
||||
content_event = read_migration("20250101000003_event_system.sql")
|
||||
|
||||
trigger_section = extract_section(
|
||||
content_event, "-- TRIGGER TABLE", "-- SENSOR TABLE"
|
||||
)
|
||||
event_section = extract_section(content_event, "-- EVENT TABLE", "-- RULE TABLE")
|
||||
rule_section = extract_section(
|
||||
content_event, "-- RULE TABLE", "-- ENFORCEMENT TABLE"
|
||||
)
|
||||
|
||||
# Add webhook columns to trigger table
|
||||
trigger_section = trigger_section.replace(
|
||||
"out_schema JSONB,",
|
||||
"""out_schema JSONB,
|
||||
webhook_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
webhook_key VARCHAR(64) UNIQUE,
|
||||
webhook_config JSONB DEFAULT '{}'::jsonb,""",
|
||||
)
|
||||
|
||||
# Add webhook index
|
||||
trigger_section = trigger_section.replace(
|
||||
"CREATE INDEX idx_trigger_enabled_created",
|
||||
"""CREATE INDEX idx_trigger_webhook_key ON trigger(webhook_key) WHERE webhook_key IS NOT NULL;
|
||||
CREATE INDEX idx_trigger_webhook_enabled_created""",
|
||||
)
|
||||
|
||||
# Add rule columns to event table
|
||||
event_section = event_section.replace(
|
||||
"created TIMESTAMPTZ NOT NULL DEFAULT NOW(),",
|
||||
"""created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
rule BIGINT,
|
||||
rule_ref TEXT,""",
|
||||
)
|
||||
|
||||
# Add rule index and constraint to event
|
||||
event_section += """
|
||||
|
||||
-- Add foreign key for rule
|
||||
ALTER TABLE event
|
||||
ADD CONSTRAINT event_rule_fkey
|
||||
FOREIGN KEY (rule) REFERENCES rule(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX idx_event_rule ON event(rule);
|
||||
"""
|
||||
|
||||
# Add is_adhoc to rule table
|
||||
rule_section = rule_section.replace(
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,",
|
||||
"enabled BOOLEAN NOT NULL DEFAULT TRUE,\n is_adhoc BOOLEAN DEFAULT false NOT NULL,",
|
||||
)
|
||||
|
||||
migration_00005 = f"""-- Migration: Trigger, Event, and Rule
|
||||
-- Description: Creates trigger (with webhook_config), event (with rule), and rule (with is_adhoc) tables
|
||||
-- Version: 20250101000005
|
||||
|
||||
-- ============================================================================
|
||||
{trigger_section}
|
||||
|
||||
-- ============================================================================
|
||||
{event_section}
|
||||
|
||||
-- ============================================================================
|
||||
{rule_section}
|
||||
"""
|
||||
|
||||
write_migration("20250101000005_trigger_event_rule.sql", migration_00005)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00006: Execution System
|
||||
# ========================================================================
|
||||
|
||||
content_execution = read_migration("20250101000004_execution_system.sql")
|
||||
|
||||
enforcement_section = extract_section(
|
||||
content_execution, "-- ENFORCEMENT TABLE", "-- EXECUTION TABLE"
|
||||
)
|
||||
execution_section = extract_section(
|
||||
content_execution, "-- EXECUTION TABLE", "-- INQUIRY TABLE"
|
||||
)
|
||||
inquiry_section = extract_section(
|
||||
content_execution, "-- INQUIRY TABLE", "-- WORKFLOW_DEFINITION TABLE"
|
||||
)
|
||||
|
||||
# Add workflow columns to execution table
|
||||
execution_section = execution_section.replace(
|
||||
"created TIMESTAMPTZ NOT NULL DEFAULT NOW(),",
|
||||
"""created TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
is_workflow BOOLEAN DEFAULT false NOT NULL,
|
||||
workflow_def BIGINT,
|
||||
workflow_task JSONB,""",
|
||||
)
|
||||
|
||||
# Add workflow_def foreign key constraint (will be added after workflow_definition table exists)
|
||||
# For now, just note it in comments
|
||||
|
||||
migration_00006 = f"""-- Migration: Execution System
|
||||
-- Description: Creates enforcement, execution (with workflow columns), and inquiry tables
|
||||
-- Version: 20250101000006
|
||||
|
||||
-- ============================================================================
|
||||
{enforcement_section}
|
||||
|
||||
-- ============================================================================
|
||||
{execution_section}
|
||||
|
||||
-- ============================================================================
|
||||
{inquiry_section}
|
||||
|
||||
-- Add foreign key constraint for enforcement.rule
|
||||
ALTER TABLE enforcement
|
||||
ADD CONSTRAINT enforcement_rule_fkey
|
||||
FOREIGN KEY (rule) REFERENCES rule(id) ON DELETE CASCADE;
|
||||
"""
|
||||
|
||||
write_migration("20250101000006_execution_system.sql", migration_00006)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00007: Workflow System
|
||||
# ========================================================================
|
||||
|
||||
workflow_def_section = extract_section(
|
||||
content_execution,
|
||||
"-- WORKFLOW_DEFINITION TABLE",
|
||||
"-- WORKFLOW_TASK_EXECUTION TABLE",
|
||||
)
|
||||
|
||||
migration_00007 = f"""-- Migration: Workflow System
|
||||
-- Description: Creates workflow_definition table (workflow_task_execution consolidated into execution.workflow_task JSONB)
|
||||
-- Version: 20250101000007
|
||||
|
||||
-- ============================================================================
|
||||
{workflow_def_section}
|
||||
|
||||
-- Add foreign key constraint for execution.workflow_def
|
||||
ALTER TABLE execution
|
||||
ADD CONSTRAINT execution_workflow_def_fkey
|
||||
FOREIGN KEY (workflow_def) REFERENCES workflow_definition(id) ON DELETE CASCADE;
|
||||
"""
|
||||
|
||||
write_migration("20250101000007_workflow_system.sql", migration_00007)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00008: Worker and Notification
|
||||
# ========================================================================
|
||||
|
||||
worker_section = extract_section(
|
||||
content_00002, "-- WORKER TABLE", "-- IDENTITY TABLE"
|
||||
)
|
||||
notification_section = extract_section(
|
||||
content_supporting, "-- NOTIFICATION TABLE", "-- ARTIFACT TABLE"
|
||||
)
|
||||
|
||||
# Add worker_role to worker table
|
||||
worker_section = worker_section.replace(
|
||||
"worker_type worker_type_enum NOT NULL,",
|
||||
"""worker_type worker_type_enum NOT NULL,
|
||||
worker_role worker_role_enum NOT NULL DEFAULT 'action',""",
|
||||
)
|
||||
|
||||
migration_00008 = f"""-- Migration: Worker and Notification
|
||||
-- Description: Creates worker (with worker_role) and notification tables
|
||||
-- Version: 20250101000008
|
||||
|
||||
-- ============================================================================
|
||||
{worker_section}
|
||||
|
||||
-- ============================================================================
|
||||
{notification_section}
|
||||
"""
|
||||
|
||||
write_migration("20250101000008_worker_notification.sql", migration_00008)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00009: Artifacts and Keys
|
||||
# ========================================================================
|
||||
|
||||
artifact_section = extract_section(content_supporting, "-- ARTIFACT TABLE", None)
|
||||
key_section = extract_section(content_00002, "-- KEY TABLE", "-- WORKER TABLE")
|
||||
|
||||
migration_00009 = f"""-- Migration: Artifacts and Keys
|
||||
-- Description: Creates artifact and key tables for storage and secrets management
|
||||
-- Version: 20250101000009
|
||||
|
||||
-- ============================================================================
|
||||
{artifact_section}
|
||||
|
||||
-- ============================================================================
|
||||
{key_section}
|
||||
"""
|
||||
|
||||
write_migration("20250101000009_artifacts_keys.sql", migration_00009)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00010: Webhook System
|
||||
# ========================================================================
|
||||
|
||||
# Get final webhook functions from restore file
|
||||
content_webhook_restore = read_migration(
|
||||
"20260204000001_restore_webhook_functions.sql"
|
||||
)
|
||||
|
||||
migration_00010 = (
|
||||
"""-- Migration: Webhook System
|
||||
-- Description: Creates webhook-related functions for trigger activation
|
||||
-- Version: 20250101000010
|
||||
|
||||
-- ============================================================================
|
||||
-- WEBHOOK VALIDATION AND PROCESSING FUNCTIONS
|
||||
-- ============================================================================
|
||||
|
||||
"""
|
||||
+ content_webhook_restore
|
||||
)
|
||||
|
||||
write_migration("20250101000010_webhook_system.sql", migration_00010)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00011: Pack Environments
|
||||
# ========================================================================
|
||||
|
||||
content_pack_env = read_migration("20260203000002_add_pack_environments.sql")
|
||||
|
||||
# Extract pack_environment table section (skip the enum and installers column as they're already added)
|
||||
pack_env_table = extract_section(
|
||||
content_pack_env, "CREATE TABLE pack_environment", None
|
||||
)
|
||||
|
||||
migration_00011 = f"""-- Migration: Pack Environments
|
||||
-- Description: Creates pack_environment table for managing pack dependency environments
|
||||
-- Version: 20250101000011
|
||||
|
||||
-- ============================================================================
|
||||
-- PACK_ENVIRONMENT TABLE
|
||||
-- ============================================================================
|
||||
|
||||
{pack_env_table}
|
||||
"""
|
||||
|
||||
write_migration("20250101000011_pack_environments.sql", migration_00011)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00012: Pack Testing
|
||||
# ========================================================================
|
||||
|
||||
content_pack_test = read_migration("20260120200000_add_pack_test_results.sql")
|
||||
|
||||
write_migration("20250101000012_pack_testing.sql", content_pack_test)
|
||||
|
||||
# ========================================================================
|
||||
# Migration 00013: LISTEN/NOTIFY Triggers (Consolidated)
|
||||
# ========================================================================
|
||||
|
||||
# Read all notify trigger migrations
|
||||
exec_notify = read_migration("20260119000001_add_execution_notify_trigger.sql")
|
||||
event_notify = read_migration("20260129150000_add_event_notify_trigger.sql")
|
||||
rule_trigger_update = read_migration(
|
||||
"20260203000003_add_rule_trigger_to_execution_notify.sql"
|
||||
)
|
||||
enforcement_notify = read_migration(
|
||||
"20260204000001_add_enforcement_notify_trigger.sql"
|
||||
)
|
||||
|
||||
# Get the final version of execution notify (with rule field)
|
||||
exec_notify_final = rule_trigger_update if rule_trigger_update else exec_notify
|
||||
|
||||
migration_00013 = f"""-- Migration: LISTEN/NOTIFY Triggers
|
||||
-- Description: Consolidated PostgreSQL LISTEN/NOTIFY triggers for real-time events
|
||||
-- Version: 20250101000013
|
||||
|
||||
-- ============================================================================
|
||||
-- EXECUTION CHANGE NOTIFICATION
|
||||
-- ============================================================================
|
||||
|
||||
{exec_notify_final}
|
||||
|
||||
-- ============================================================================
|
||||
-- EVENT CREATION NOTIFICATION
|
||||
-- ============================================================================
|
||||
|
||||
{event_notify}
|
||||
|
||||
-- ============================================================================
|
||||
-- ENFORCEMENT CHANGE NOTIFICATION
|
||||
-- ============================================================================
|
||||
|
||||
{enforcement_notify}
|
||||
"""
|
||||
|
||||
write_migration("20250101000013_notify_triggers.sql", migration_00013)
|
||||
|
||||
print()
|
||||
print("=" * 70)
|
||||
print("Migration consolidation complete!")
|
||||
print("=" * 70)
|
||||
print()
|
||||
print("Summary:")
|
||||
print(f" Old migrations: 22 files")
|
||||
print(f" New migrations: 13 files")
|
||||
print(f" Removed: 9 files (consolidated or data moved to YAML)")
|
||||
print()
|
||||
print("Key changes:")
|
||||
print(" ✓ Removed runtime_type_enum (never recreated)")
|
||||
print(
|
||||
" ✓ Removed workflow_task_execution table (consolidated into execution.workflow_task)"
|
||||
)
|
||||
print(" ✓ Removed individual webhook columns (consolidated into webhook_config)")
|
||||
print(" ✓ Added is_adhoc flags from start")
|
||||
print(" ✓ Added workflow columns to execution from start")
|
||||
print(" ✓ Added rule tracking to event from start")
|
||||
print(" ✓ Added worker_role from start")
|
||||
print(" ✓ Consolidated all LISTEN/NOTIFY triggers")
|
||||
print()
|
||||
print("Next steps:")
|
||||
print(" 1. Review the generated migrations")
|
||||
print(" 2. Test on fresh database: createdb attune_test && sqlx migrate run")
|
||||
print(" 3. Compare schema: pg_dump --schema-only")
|
||||
print(" 4. If successful, delete migrations.old/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
329
scripts/dev-pack.sh
Executable file
329
scripts/dev-pack.sh
Executable file
@@ -0,0 +1,329 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Helper script for managing development packs
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
PACKS_DEV_DIR="$PROJECT_ROOT/packs.dev"
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
function print_usage() {
|
||||
cat << USAGE
|
||||
Development Pack Management Script
|
||||
|
||||
Usage: $0 <command> [arguments]
|
||||
|
||||
Commands:
|
||||
create <pack-ref> Create a new pack structure
|
||||
list List all dev packs
|
||||
validate <pack-ref> Validate a pack structure
|
||||
register <pack-ref> Register pack in Docker environment
|
||||
clean Remove all non-example packs
|
||||
help Show this help message
|
||||
|
||||
Examples:
|
||||
# Create a new pack
|
||||
$0 create my-awesome-pack
|
||||
|
||||
# List all packs
|
||||
$0 list
|
||||
|
||||
# Register pack in database
|
||||
$0 register my-awesome-pack
|
||||
|
||||
Environment Variables:
|
||||
ATTUNE_API_URL API URL (default: http://localhost:8080)
|
||||
ATTUNE_TOKEN Authentication token (required for register)
|
||||
|
||||
USAGE
|
||||
}
|
||||
|
||||
function create_pack() {
|
||||
local pack_ref="$1"
|
||||
|
||||
if [ -z "$pack_ref" ]; then
|
||||
echo -e "${RED}Error: Pack reference is required${NC}"
|
||||
echo "Usage: $0 create <pack-ref>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local pack_dir="$PACKS_DEV_DIR/$pack_ref"
|
||||
|
||||
if [ -d "$pack_dir" ]; then
|
||||
echo -e "${RED}Error: Pack '$pack_ref' already exists${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Creating pack structure for '$pack_ref'...${NC}"
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$pack_dir/actions"
|
||||
mkdir -p "$pack_dir/triggers"
|
||||
mkdir -p "$pack_dir/sensors"
|
||||
mkdir -p "$pack_dir/workflows"
|
||||
|
||||
# Create pack.yaml
|
||||
cat > "$pack_dir/pack.yaml" << YAML
|
||||
ref: $pack_ref
|
||||
label: "$(echo $pack_ref | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2));}1')"
|
||||
description: "Custom pack: $pack_ref"
|
||||
version: "1.0.0"
|
||||
author: "Developer"
|
||||
email: "dev@example.com"
|
||||
|
||||
system: false
|
||||
enabled: true
|
||||
|
||||
tags:
|
||||
- custom
|
||||
- development
|
||||
YAML
|
||||
|
||||
# Create example action
|
||||
cat > "$pack_dir/actions/example.yaml" << YAML
|
||||
name: example
|
||||
ref: ${pack_ref}.example
|
||||
description: "Example action"
|
||||
runner_type: shell
|
||||
enabled: true
|
||||
entry_point: example.sh
|
||||
|
||||
parameters:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
description: "Message to process"
|
||||
default: "Hello from $pack_ref"
|
||||
required: []
|
||||
|
||||
output:
|
||||
type: object
|
||||
properties:
|
||||
result:
|
||||
type: string
|
||||
description: "Processing result"
|
||||
|
||||
tags:
|
||||
- example
|
||||
YAML
|
||||
|
||||
cat > "$pack_dir/actions/example.sh" << 'BASH'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
MESSAGE="${ATTUNE_ACTION_message:-Hello}"
|
||||
echo "{\"result\": \"Processed: $MESSAGE\"}"
|
||||
BASH
|
||||
|
||||
chmod +x "$pack_dir/actions/example.sh"
|
||||
|
||||
# Create README
|
||||
cat > "$pack_dir/README.md" << README
|
||||
# $pack_ref
|
||||
|
||||
Custom development pack.
|
||||
|
||||
## Actions
|
||||
|
||||
- \`${pack_ref}.example\` - Example action
|
||||
|
||||
## Usage
|
||||
|
||||
\`\`\`bash
|
||||
# Register the pack
|
||||
./scripts/dev-pack.sh register $pack_ref
|
||||
|
||||
# Validate the pack
|
||||
./scripts/dev-pack.sh validate $pack_ref
|
||||
\`\`\`
|
||||
|
||||
## Development
|
||||
|
||||
Edit files in \`packs.dev/$pack_ref/\` and they will be immediately available in Docker containers.
|
||||
|
||||
README
|
||||
|
||||
echo -e "${GREEN}✓ Pack created successfully${NC}"
|
||||
echo -e "${BLUE}Location: $pack_dir${NC}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit $pack_dir/pack.yaml"
|
||||
echo " 2. Add actions in $pack_dir/actions/"
|
||||
echo " 3. Register pack: $0 register $pack_ref"
|
||||
}
|
||||
|
||||
function list_packs() {
|
||||
echo -e "${BLUE}Development Packs:${NC}"
|
||||
echo ""
|
||||
|
||||
local count=0
|
||||
for pack_dir in "$PACKS_DEV_DIR"/*; do
|
||||
if [ -d "$pack_dir" ] && [ -f "$pack_dir/pack.yaml" ]; then
|
||||
local pack_ref=$(basename "$pack_dir")
|
||||
local label=$(grep "^label:" "$pack_dir/pack.yaml" | cut -d'"' -f2)
|
||||
local version=$(grep "^version:" "$pack_dir/pack.yaml" | cut -d'"' -f2)
|
||||
|
||||
echo -e " ${GREEN}$pack_ref${NC}"
|
||||
echo -e " Label: $label"
|
||||
echo -e " Version: $version"
|
||||
echo ""
|
||||
|
||||
((count++))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $count -eq 0 ]; then
|
||||
echo -e " ${YELLOW}No packs found${NC}"
|
||||
echo ""
|
||||
echo "Create a pack with: $0 create <pack-ref>"
|
||||
else
|
||||
echo -e "Total: $count pack(s)"
|
||||
fi
|
||||
}
|
||||
|
||||
function validate_pack() {
|
||||
local pack_ref="$1"
|
||||
|
||||
if [ -z "$pack_ref" ]; then
|
||||
echo -e "${RED}Error: Pack reference is required${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local pack_dir="$PACKS_DEV_DIR/$pack_ref"
|
||||
|
||||
if [ ! -d "$pack_dir" ]; then
|
||||
echo -e "${RED}Error: Pack '$pack_ref' not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Validating pack '$pack_ref'...${NC}"
|
||||
|
||||
# Check pack.yaml
|
||||
if [ ! -f "$pack_dir/pack.yaml" ]; then
|
||||
echo -e "${RED}✗ pack.yaml not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ pack.yaml exists${NC}"
|
||||
|
||||
# Check for actions
|
||||
local action_count=$(find "$pack_dir/actions" -name "*.yaml" 2>/dev/null | wc -l)
|
||||
echo -e "${GREEN}✓ Found $action_count action(s)${NC}"
|
||||
|
||||
# Check action scripts
|
||||
for action_yaml in "$pack_dir/actions"/*.yaml; do
|
||||
if [ -f "$action_yaml" ]; then
|
||||
local entry_point=$(grep "entry_point:" "$action_yaml" | awk '{print $2}')
|
||||
local script_path="$pack_dir/actions/$entry_point"
|
||||
|
||||
if [ ! -f "$script_path" ]; then
|
||||
echo -e "${RED}✗ Script not found: $entry_point${NC}"
|
||||
elif [ ! -x "$script_path" ]; then
|
||||
echo -e "${YELLOW}⚠ Script not executable: $entry_point${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ Script OK: $entry_point${NC}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}Validation complete${NC}"
|
||||
}
|
||||
|
||||
function register_pack() {
|
||||
local pack_ref="$1"
|
||||
|
||||
if [ -z "$pack_ref" ]; then
|
||||
echo -e "${RED}Error: Pack reference is required${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local pack_dir="$PACKS_DEV_DIR/$pack_ref"
|
||||
|
||||
if [ ! -d "$pack_dir" ]; then
|
||||
echo -e "${RED}Error: Pack '$pack_ref' not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Registering pack '$pack_ref' in Docker environment...${NC}"
|
||||
|
||||
# Extract pack metadata
|
||||
local label=$(grep "^label:" "$pack_dir/pack.yaml" | cut -d'"' -f2)
|
||||
local version=$(grep "^version:" "$pack_dir/pack.yaml" | cut -d'"' -f2)
|
||||
local description=$(grep "^description:" "$pack_dir/pack.yaml" | cut -d'"' -f2)
|
||||
|
||||
echo -e "${YELLOW}Note: Manual registration required via API${NC}"
|
||||
echo ""
|
||||
echo "Run the following command to register the pack:"
|
||||
echo ""
|
||||
echo "curl -X POST http://localhost:8080/api/v1/packs \\"
|
||||
echo " -H \"Authorization: Bearer \$ATTUNE_TOKEN\" \\"
|
||||
echo " -H \"Content-Type: application/json\" \\"
|
||||
echo " -d '{"
|
||||
echo " \"ref\": \"$pack_ref\","
|
||||
echo " \"label\": \"${label:-Custom Pack}\","
|
||||
echo " \"description\": \"${description:-Development pack}\","
|
||||
echo " \"version\": \"${version:-1.0.0}\","
|
||||
echo " \"system\": false,"
|
||||
echo " \"enabled\": true"
|
||||
echo " }'"
|
||||
echo ""
|
||||
echo "The pack files are available at: /opt/attune/packs.dev/$pack_ref"
|
||||
}
|
||||
|
||||
function clean_packs() {
|
||||
echo -e "${YELLOW}This will remove all non-example packs from packs.dev/${NC}"
|
||||
echo -e "${RED}This action cannot be undone!${NC}"
|
||||
read -p "Are you sure? (yes/no): " confirm
|
||||
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
echo "Cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local count=0
|
||||
for pack_dir in "$PACKS_DEV_DIR"/*; do
|
||||
if [ -d "$pack_dir" ]; then
|
||||
local pack_name=$(basename "$pack_dir")
|
||||
if [ "$pack_name" != "examples" ] && [ "$pack_name" != "README.md" ]; then
|
||||
echo "Removing: $pack_name"
|
||||
rm -rf "$pack_dir"
|
||||
((count++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}Removed $count pack(s)${NC}"
|
||||
}
|
||||
|
||||
# Main command dispatch
|
||||
case "${1:-}" in
|
||||
create)
|
||||
create_pack "$2"
|
||||
;;
|
||||
list)
|
||||
list_packs
|
||||
;;
|
||||
validate)
|
||||
validate_pack "$2"
|
||||
;;
|
||||
register)
|
||||
register_pack "$2"
|
||||
;;
|
||||
clean)
|
||||
clean_packs
|
||||
;;
|
||||
help|--help|-h)
|
||||
print_usage
|
||||
;;
|
||||
*)
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user