feat: добавлена система миграций БД и CI/CD пайплайны
- Создана система отслеживания миграций (MigrationRepository, таблица migrations) - Добавлен скрипт apply_migrations.py для автоматического применения миграций - Созданы CI/CD пайплайны (.github/workflows/ci.yml, deploy.yml) - Обновлена документация по миграциям в database-patterns.md - Миграции применяются автоматически при деплое в продакшн
This commit is contained in:
@@ -112,6 +112,106 @@ class UserRepository(DatabaseConnection):
|
||||
|
||||
## Миграции
|
||||
|
||||
- SQL миграции в `database/schema.sql`
|
||||
- Python скрипты для миграций в `scripts/`
|
||||
- Всегда проверяйте существование таблиц перед созданием: `CREATE TABLE IF NOT EXISTS`
|
||||
### Обзор
|
||||
|
||||
Система миграций автоматически отслеживает и применяет изменения схемы БД. Миграции хранятся в `scripts/` и применяются автоматически при деплое.
|
||||
|
||||
### Создание миграции
|
||||
|
||||
1. **Создайте файл** в `scripts/` с понятным именем (например, `add_user_email_column.py`)
|
||||
2. **Обязательные требования:**
|
||||
- Функция `async def main(db_path: str)`
|
||||
- Использует `aiosqlite` для работы с БД
|
||||
- **Идемпотентна** - можно запускать несколько раз без ошибок
|
||||
- Проверяет текущее состояние перед применением изменений
|
||||
|
||||
3. **Пример структуры:**
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
project_root = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
import aiosqlite
|
||||
from logs.custom_logger import logger
|
||||
|
||||
DEFAULT_DB_PATH = "database/tg-bot-database.db"
|
||||
|
||||
|
||||
async def main(db_path: str) -> None:
|
||||
"""Основная функция миграции."""
|
||||
db_path = os.path.abspath(db_path)
|
||||
if not os.path.exists(db_path):
|
||||
logger.error(f"База данных не найдена: {db_path}")
|
||||
return
|
||||
|
||||
async with aiosqlite.connect(db_path) as conn:
|
||||
await conn.execute("PRAGMA foreign_keys = ON")
|
||||
|
||||
# Проверяем текущее состояние
|
||||
cursor = await conn.execute("PRAGMA table_info(users)")
|
||||
columns = await cursor.fetchall()
|
||||
|
||||
# Проверяем, нужно ли применять изменения
|
||||
column_exists = any(col[1] == "email" for col in columns)
|
||||
|
||||
if not column_exists:
|
||||
await conn.execute("ALTER TABLE users ADD COLUMN email TEXT")
|
||||
await conn.commit()
|
||||
logger.info("Колонка email добавлена")
|
||||
else:
|
||||
logger.info("Колонка email уже существует")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Добавление колонки email")
|
||||
parser.add_argument(
|
||||
"--db",
|
||||
default=os.environ.get("DATABASE_PATH", DEFAULT_DB_PATH),
|
||||
help="Путь к БД",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
asyncio.run(main(args.db))
|
||||
```
|
||||
|
||||
### Применение миграций
|
||||
|
||||
**Локально:**
|
||||
```bash
|
||||
python3 scripts/apply_migrations.py --dry-run # проверить
|
||||
python3 scripts/apply_migrations.py # применить
|
||||
```
|
||||
|
||||
**В продакшене:** Применяются автоматически при деплое через CI/CD (перед перезапуском контейнера).
|
||||
|
||||
### Важные правила
|
||||
|
||||
1. **Идемпотентность** - всегда проверяйте состояние перед изменением:
|
||||
```python
|
||||
# ✅ Правильно
|
||||
cursor = await conn.execute("PRAGMA table_info(users)")
|
||||
columns = await cursor.fetchall()
|
||||
if not any(col[1] == "email" for col in columns):
|
||||
await conn.execute("ALTER TABLE users ADD COLUMN email TEXT")
|
||||
|
||||
# ❌ Неправильно - упадет при повторном запуске
|
||||
await conn.execute("ALTER TABLE users ADD COLUMN email TEXT")
|
||||
```
|
||||
|
||||
2. **Порядок применения** - миграции применяются в алфавитном порядке по имени файла
|
||||
|
||||
3. **Исключения** - следующие скрипты не считаются миграциями:
|
||||
- `apply_migrations.py`, `backfill_migrations.py`, `test_s3_connection.py`, `voice_cleanup.py`
|
||||
|
||||
### Регистрация существующих миграций
|
||||
|
||||
Если миграции уже применены, но не зарегистрированы:
|
||||
```bash
|
||||
python3 scripts/backfill_migrations.py # зарегистрировать все существующие
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user