-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Update Alembic migration configuration in workflow
- Switch to using Alembic CLI directly - Add proper table definitions in env.py - Fix Python path configuration - Improve error handling and logging
- Loading branch information
1 parent
8660f1f
commit 9a2ab3f
Showing
1 changed file
with
87 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,19 +42,30 @@ jobs: | |
- name: Install dependencies | ||
working-directory: ./backend | ||
run: | | ||
python -m pip install --upgrade pip | ||
python -m pip install --upgrade pip setuptools wheel | ||
# Install system dependencies | ||
sudo apt-get update | ||
sudo apt-get install -y tesseract-ocr | ||
# Install core dependencies first | ||
pip install 'sqlalchemy>=1.4.0,<2.0.0' | ||
pip install 'alembic>=1.12.0,<2.0.0' | ||
pip install 'psycopg2-binary>=2.9.0,<3.0.0' | ||
# Install requirements | ||
pip install -r requirements.txt | ||
# Install test dependencies | ||
pip install --upgrade --force-reinstall alembic pytest-cov flake8 psycopg2-binary httpx pytesseract pycountry PyYAML selenium pytest-mock loguru reportlab inputimeout | ||
pip install pytest-cov flake8 httpx pytesseract pycountry PyYAML selenium pytest-mock loguru reportlab inputimeout | ||
# Add local bin to PATH | ||
export PATH="$HOME/.local/bin:$PATH" | ||
pip list | grep alembic | ||
# Verify installations | ||
python -m pip list | ||
python -c "import alembic; print(f'Alembic version: {alembic.__version__}')" | ||
- name: Setup backend test environment | ||
working-directory: ./backend | ||
env: | ||
POSTGRES_USER: postgres | ||
POSTGRES_PASSWORD: postgres | ||
POSTGRES_DB: test_db | ||
run: | | ||
echo "DEV_MODE=true" > .env | ||
echo "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/test_db" >> .env | ||
|
@@ -63,6 +74,31 @@ jobs: | |
echo "[email protected]" >> .env | ||
echo "INDEED_PASSWORD=testpass123" >> .env | ||
# Initialize database schema | ||
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres -c 'DROP DATABASE IF EXISTS test_db;' | ||
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres -c 'CREATE DATABASE test_db;' | ||
# Create initial schema | ||
PGPASSWORD=postgres psql -h localhost -U postgres -d test_db << 'EOSQL' | ||
CREATE TABLE IF NOT EXISTS users ( | ||
id SERIAL PRIMARY KEY, | ||
username VARCHAR(255) NOT NULL, | ||
email VARCHAR(255) UNIQUE NOT NULL, | ||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||
); | ||
CREATE TABLE IF NOT EXISTS verified_documents ( | ||
id SERIAL PRIMARY KEY, | ||
user_id INTEGER REFERENCES users(id), | ||
document_type VARCHAR(50) NOT NULL, | ||
document_number VARCHAR(255), | ||
status VARCHAR(50) DEFAULT 'PENDING', | ||
verification_date TIMESTAMP, | ||
expiry_date TIMESTAMP, | ||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||
); | ||
EOSQL | ||
- name: Verify environment | ||
working-directory: ./backend | ||
env: | ||
|
@@ -83,15 +119,24 @@ jobs: | |
export PYTHONPATH="${PYTHONPATH}:${PWD}" | ||
echo "Current PYTHONPATH: $PYTHONPATH" | ||
# Ensure alembic CLI is in PATH | ||
python -m pip install --upgrade alembic | ||
export PATH="$HOME/.local/bin:$PATH" | ||
# Create Alembic directory structure | ||
mkdir -p migrations/versions | ||
# Create env.py | ||
mkdir -p migrations | ||
# Initialize Alembic if not already initialized | ||
if [ ! -f alembic.ini ]; then | ||
alembic init migrations | ||
# Update alembic.ini with correct database URL | ||
sed -i "s|sqlalchemy.url = .*|sqlalchemy.url = ${DATABASE_URL}|" alembic.ini | ||
fi | ||
# Update env.py to use environment variable for database URL | ||
cat > migrations/env.py << 'EOL' | ||
from logging.config import fileConfig | ||
from sqlalchemy import engine_from_config | ||
from sqlalchemy import pool | ||
from sqlalchemy import engine_from_config, pool, MetaData, Table, Column, Integer, String, ForeignKey, TIMESTAMP, text | ||
from alembic import context | ||
import os | ||
|
@@ -100,11 +145,38 @@ jobs: | |
if config.config_file_name is not None: | ||
fileConfig(config.config_file_name) | ||
def get_url(): | ||
return os.getenv("DATABASE_URL") | ||
# Create MetaData object | ||
metadata = MetaData() | ||
# Define tables | ||
users = Table('users', metadata, | ||
Column('id', Integer, primary_key=True), | ||
Column('username', String(255), nullable=False), | ||
Column('email', String(255), unique=True, nullable=False), | ||
Column('created_at', TIMESTAMP, server_default=text('CURRENT_TIMESTAMP')) | ||
) | ||
verified_documents = Table('verified_documents', metadata, | ||
Column('id', Integer, primary_key=True), | ||
Column('user_id', Integer, ForeignKey('users.id')), | ||
Column('document_type', String(50), nullable=False), | ||
Column('document_number', String(255)), | ||
Column('status', String(50), server_default='PENDING'), | ||
Column('verification_date', TIMESTAMP), | ||
Column('expiry_date', TIMESTAMP), | ||
Column('created_at', TIMESTAMP, server_default=text('CURRENT_TIMESTAMP')) | ||
) | ||
target_metadata = metadata | ||
def run_migrations_offline() -> None: | ||
url = os.getenv("DATABASE_URL") | ||
url = get_url() | ||
context.configure( | ||
url=url, | ||
target_metadata=None, | ||
target_metadata=target_metadata, | ||
literal_binds=True, | ||
dialect_opts={"paramstyle": "named"}, | ||
) | ||
|
@@ -115,7 +187,7 @@ jobs: | |
configuration = config.get_section(config.config_ini_section) | ||
if configuration is None: | ||
configuration = {} | ||
configuration["sqlalchemy.url"] = os.getenv("DATABASE_URL") | ||
configuration["sqlalchemy.url"] = get_url() | ||
connectable = engine_from_config( | ||
configuration, | ||
prefix="sqlalchemy.", | ||
|
@@ -124,7 +196,7 @@ jobs: | |
with connectable.connect() as connection: | ||
context.configure( | ||
connection=connection, | ||
target_metadata=None | ||
target_metadata=target_metadata | ||
) | ||
with context.begin_transaction(): | ||
context.run_migrations() | ||
|
@@ -135,78 +207,11 @@ jobs: | |
run_migrations_online() | ||
EOL | ||
# Create script.py.mako | ||
cat > migrations/script.py.mako << 'EOL' | ||
"""${message} | ||
Revision ID: ${up_revision} | ||
Revises: ${down_revision | comma,n} | ||
Create Date: ${create_date} | ||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
${imports if imports else ""} | ||
# revision identifiers, used by Alembic. | ||
revision = ${repr(up_revision)} | ||
down_revision = ${repr(down_revision)} | ||
branch_labels = ${repr(branch_labels)} | ||
depends_on = ${repr(depends_on)} | ||
def upgrade() -> None: | ||
${upgrades if upgrades else "pass"} | ||
def downgrade() -> None: | ||
${downgrades if downgrades else "pass"} | ||
EOL | ||
# Create and run migration script | ||
cat > run_migrations.py << 'EOL' | ||
import os | ||
import sys | ||
import logging | ||
from alembic.config import Config | ||
from alembic import command | ||
from pathlib import Path | ||
logging.basicConfig(level=logging.INFO) | ||
logger = logging.getLogger(__name__) | ||
try: | ||
# Create alembic.ini | ||
config_path = Path('alembic.ini') | ||
if not config_path.exists(): | ||
logger.info("Creating alembic.ini...") | ||
config = Config() | ||
config.set_main_option('script_location', 'migrations') | ||
config.set_main_option('sqlalchemy.url', os.environ['DATABASE_URL']) | ||
config.set_main_option('file_template', '%%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d_%%(minute).2d_%%(second).2d_%%(rev)s_%%(slug)s') | ||
with open(config_path, 'w') as f: | ||
config.write(f) | ||
else: | ||
config = Config(config_path) | ||
# Initialize migrations if needed | ||
migrations_dir = Path('migrations/versions') | ||
if not migrations_dir.exists(): | ||
migrations_dir.mkdir(parents=True, exist_ok=True) | ||
logger.info("Creating initial migration...") | ||
command.revision(config, message="Initial migration", autogenerate=True) | ||
# Run the migration | ||
logger.info("Running database migrations...") | ||
command.upgrade(config, "head") | ||
logger.info("Migrations completed successfully") | ||
except Exception as e: | ||
logger.error(f"Migration failed: {str(e)}", exc_info=True) | ||
sys.exit(1) | ||
EOL | ||
# Create initial migration | ||
alembic revision --autogenerate -m "Initial migration" | ||
# Run the migration script | ||
python run_migrations.py | ||
# Run migrations | ||
alembic upgrade head | ||
- name: Run tests with coverage | ||
working-directory: ./backend | ||
|