feat: implement CI/CD pipeline with Gitea Actions

- Add Gitea Actions workflow with 4 stages: lint, test, build, push
- Configure ruff linting and formatting checks
- Set up Django tests with PostgreSQL and Redis services
- Implement Docker image building for web and celery services
- Add requirements.txt and requirements-dev.txt generation
- Fix ipdb compatibility issues in test runner
- Update ruff configuration for Django compatibility
- Add comprehensive CI/CD documentation
This commit is contained in:
2026-01-19 14:24:48 +01:00
parent cbfbd8652d
commit 06b30fca02
26 changed files with 1769 additions and 726 deletions

View File

@@ -1,4 +1,5 @@
from typing import Dict, Any, Optional
from typing import Any, Dict, Optional
from django.contrib.auth import get_user_model
from django.db import transaction
from rest_framework_simplejwt.tokens import RefreshToken
@@ -12,28 +13,27 @@ class UserService:
"""Сервисный слой для работы с пользователями"""
@classmethod
def create_user(cls, *, email: str, username: str, password: str, **extra_fields) -> User:
def create_user(
cls, *, email: str, username: str, password: str, **extra_fields
) -> User:
"""
Создает нового пользователя
Args:
email: Email пользователя
username: Username пользователя
password: Пароль
**extra_fields: Дополнительные поля
Returns:
User: Созданный пользователь
Raises:
ValidationError: При некорректных данных
"""
with transaction.atomic():
user = User.objects.create_user(
email=email,
username=username,
password=password,
**extra_fields
email=email, username=username, password=password, **extra_fields
)
return user
@@ -57,11 +57,11 @@ class UserService:
def update_user(cls, user_id: int, **fields) -> Optional[User]:
"""
Обновляет данные пользователя
Args:
user_id: ID пользователя
**fields: Поля для обновления
Returns:
User: Обновленный пользователь или None
"""
@@ -71,7 +71,7 @@ class UserService:
for field, value in fields.items():
setattr(user, field, value)
user.save()
return user
@@ -79,10 +79,10 @@ class UserService:
def delete_user(cls, user_id: int) -> bool:
"""
Удаляет пользователя
Args:
user_id: ID пользователя
Returns:
bool: True если успешно удален
"""
@@ -96,27 +96,27 @@ class UserService:
def get_tokens_for_user(cls, user: User) -> Dict[str, str]:
"""
Генерирует JWT токены для пользователя
Args:
user: Пользователь
Returns:
Dict[str, str]: refresh и access токены
"""
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
"refresh": str(refresh),
"access": str(refresh.access_token),
}
@classmethod
def verify_email(cls, user_id: int) -> bool:
"""
Подтверждает email пользователя
Args:
user_id: ID пользователя
Returns:
bool: True если успешно подтвержден
"""
@@ -135,7 +135,7 @@ class ProfileService:
def get_profile_by_user_id(cls, user_id: int) -> Optional[Profile]:
"""Получает профиль по ID пользователя"""
try:
return Profile.objects.select_related('user').get(user_id=user_id)
return Profile.objects.select_related("user").get(user_id=user_id)
except Profile.DoesNotExist:
return None
@@ -143,11 +143,11 @@ class ProfileService:
def update_profile(cls, user_id: int, **fields) -> Optional[Profile]:
"""
Обновляет профиль пользователя
Args:
user_id: ID пользователя
**fields: Поля для обновления
Returns:
Profile: Обновленный профиль или None
"""
@@ -157,7 +157,7 @@ class ProfileService:
for field, value in fields.items():
setattr(profile, field, value)
profile.save()
return profile
@@ -165,10 +165,10 @@ class ProfileService:
def get_full_profile_data(cls, user_id: int) -> Optional[Dict[str, Any]]:
"""
Получает полные данные пользователя и профиля
Args:
user_id: ID пользователя
Returns:
Dict: Полные данные или None
"""
@@ -178,17 +178,17 @@ class ProfileService:
user = profile.user
return {
'id': user.id,
'email': user.email,
'username': user.username,
'is_verified': user.is_verified,
'phone': user.phone,
'first_name': profile.first_name,
'last_name': profile.last_name,
'full_name': profile.full_name,
'bio': profile.bio,
'avatar': profile.avatar.url if profile.avatar else None,
'date_of_birth': profile.date_of_birth,
'created_at': user.created_at,
'updated_at': user.updated_at,
}
"id": user.id,
"email": user.email,
"username": user.username,
"is_verified": user.is_verified,
"phone": user.phone,
"first_name": profile.first_name,
"last_name": profile.last_name,
"full_name": profile.full_name,
"bio": profile.bio,
"avatar": profile.avatar.url if profile.avatar else None,
"date_of_birth": profile.date_of_birth,
"created_at": user.created_at,
"updated_at": user.updated_at,
}