Skip to content

fix: Enhance Alembic verification to test module execution #23

fix: Enhance Alembic verification to test module execution

fix: Enhance Alembic verification to test module execution #23

Workflow file for this run

name: CI/CD Pipeline
on:
push:
branches: [ main, develop, 'feature/**' ]
pull_request:
branches: [ main, develop ]
jobs:
backend-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('backend/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
working-directory: ./backend
run: |
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 with explicit paths
python -m pip install --upgrade 'sqlalchemy>=1.4.0,<2.0.0'
python -m pip install --upgrade --force-reinstall 'alembic>=1.12.0,<2.0.0'
python -m pip install --upgrade 'psycopg2-binary>=2.9.0,<3.0.0'
# Install requirements
python -m pip install -r requirements.txt
# Install test dependencies
python -m pip install pytest-cov flake8 httpx pytesseract pycountry PyYAML selenium pytest-mock loguru reportlab inputimeout
# Add local bin to PATH and verify installations
export PATH="$HOME/.local/bin:$PATH"
# Verify installations and paths
python -m pip list
# Verify Alembic installation and module accessibility
python << 'EOF'
import sys

Check failure on line 63 in .github/workflows/main.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/main.yml

Invalid workflow file

You have an error in your yaml syntax on line 63
import os
import subprocess
import importlib.util
print("Python version:", sys.version)
print("Python executable:", sys.executable)
print("PYTHONPATH:", os.getenv("PYTHONPATH"))
try:
import alembic
print("Alembic version:", alembic.__version__)
print("Alembic location:", alembic.__file__)
# Test if we can run alembic as a module
result = subprocess.run([sys.executable, '-m', 'alembic', '--version'],
capture_output=True, text=True)
print("Alembic module test output:", result.stdout)
if result.returncode != 0:
print("Alembic module test error:", result.stderr)
sys.exit(1)
print("Alembic module test successful")
except Exception as e:
print("Error:", str(e))
sys.exit(1)
EOF
- 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
echo "API_HOST=0.0.0.0" >> .env
echo "API_PORT=8000" >> .env
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:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
PYTHONPATH: ${GITHUB_WORKSPACE}/backend
run: |
python -c "import sys; print('Python path:', sys.path)"
python -c "import alembic.config; print('Alembic configuration verified')"
python -c "import psycopg2; conn=psycopg2.connect('$DATABASE_URL'); print('Database connection verified')"
- name: Run migrations
working-directory: ./backend
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
PYTHONPATH: ${GITHUB_WORKSPACE}/backend
run: |
echo "Setting up Python environment..."
# Ensure backend directory is in Python path
export PYTHONPATH="${GITHUB_WORKSPACE}/backend:${PWD}:${PYTHONPATH}"
export PYTHONUNBUFFERED=1
export PYTHONDONTWRITEBYTECODE=1
echo "Current PYTHONPATH: $PYTHONPATH"
# Create Alembic directory structure
mkdir -p migrations/versions
# Initialize Alembic if not already initialized
if [ ! -f alembic.ini ]; then
python -m alembic init migrations
# Update alembic.ini with correct database URL
sed -i "s|sqlalchemy.url = .*|sqlalchemy.url = ${DATABASE_URL}|" alembic.ini
# Debug output
echo "Alembic initialization completed"
echo "Contents of alembic.ini:"
cat 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, pool, MetaData, Table, Column, Integer, String, ForeignKey, TIMESTAMP, text
from alembic import context
import os
config = context.config
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 = get_url()
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
configuration = config.get_section(config.config_ini_section)
if configuration is None:
configuration = {}
configuration["sqlalchemy.url"] = get_url()
connectable = engine_from_config(
configuration,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
EOL
# Debug output before migrations
echo "Verifying migrations setup..."
ls -la migrations/
echo "Verifying migrations/versions directory..."
ls -la migrations/versions/
echo "Current working directory: $(pwd)"
echo "Running initial migration..."
python -m alembic revision --autogenerate -m "Initial migration"
echo "Running migration upgrade..."
python -m alembic upgrade head
- name: Run tests with coverage
working-directory: ./backend
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
run: |
pytest tests/ -v --cov=src --cov-report=xml --junitxml=test-results/results.xml
- name: Run flake8
working-directory: ./backend
run: |
flake8 src tests --max-line-length=100
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: backend-test-results
path: |
backend/coverage.xml
backend/test-results/results.xml
frontend-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'pnpm'
cache-dependency-path: './frontend/pnpm-lock.yaml'
- name: Install dependencies
working-directory: ./frontend
run: pnpm install
- name: Run tests
working-directory: ./frontend
run: CI=true pnpm test
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: frontend-test-results
path: frontend/test-results