Compare commits

..

10 Commits

10 changed files with 657 additions and 0 deletions

114
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,114 @@
# ============================================================
# Continuous Integration (CI)
# Основной pipeline проверки проекта
# ============================================================
name: CI
# ------------------------------------------------------------
# Когда запускать workflow.yml
# ------------------------------------------------------------
on:
push:
branches:
- main
- develop
pull_request:
# ------------------------------------------------------------
# Глобальные переменные
# ------------------------------------------------------------
env:
PYTHON_VERSION: "3.13"
# ============================================================
# JOB 1 — Проверка качества кода
# ============================================================
jobs:
lint:
name: Lint (ruff + mypy)
runs-on: ubuntu-latest
steps:
# Клонирование репозитория
- name: Checkout repository
uses: actions/checkout@v4
# Установка Python
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
# Установка uv (быстрый менеджер зависимостей)
- name: Install uv
run: pip install uv
# Кэширование зависимостей
- name: Cache uv dependencies
uses: actions/cache@v4
with:
path: ~/.cache/uv
key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}
# Установка зависимостей
- name: Install dependencies
run: uv sync
# Проверка кода линтером Ruff
- name: Run Ruff
run: ruff check .
# Проверка типизации
- name: Run MyPy
run: mypy .
# ============================================================
# JOB 2 — Тестирование
# ============================================================
tests:
name: Run tests
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install uv
run: pip install uv
- name: Install dependencies
run: uv sync
# Запуск pytest
- name: Run tests
run: pytest
# ============================================================
# JOB 3 — Проверка Docker
# ============================================================
docker:
name: Docker build test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Проверка что Dockerfile собирается
- name: Build Docker image
run: docker build .

View File

@@ -0,0 +1,33 @@
# ============================================================
# Auto format code
# ============================================================
name: Auto Format
on:
pull_request:
jobs:
format:
name: Format code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install formatter
run: pip install ruff
# Автоматическое форматирование
- name: Run formatter
run: ruff format .
# Проверка что после форматирования нет изменений
- name: Check formatting
run: ruff check .

View File

@@ -0,0 +1,36 @@
# ============================================================
# Security checks
# Проверка уязвимостей зависимостей
# ============================================================
name: Security
on:
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:
jobs:
security-scan:
name: Dependency security scan
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Установка Python
- uses: actions/setup-python@v5
with:
python-version: "3.12"
# Установка инструмента проверки
- name: Install pip-audit
run: pip install pip-audit
# Проверка зависимостей
- name: Run security audit
run: pip-audit

View File

@@ -0,0 +1,31 @@
# ============================================================
# Release workflow
# Автоматическая публикация релизов
# ============================================================
name: Release
on:
push:
tags:
- "v*"
jobs:
release:
name: Create release
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Установка Python
- uses: actions/setup-python@v5
with:
python-version: "3.12"
# Создание релиза
- name: Create GitHub Release
uses: softprops/action-gh-release@v2

55
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,55 @@
repos:
# =============================================================================
# Ruff (lint + import sorting + formatting)
# =============================================================================
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
# =============================================================================
# Base repository hygiene
# =============================================================================
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
args: [--allow-multiple-documents]
- id: check-json
- id: check-toml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-merge-conflict
- id: detect-private-key
- id: check-added-large-files
- id: debug-statements
- id: check-executables-have-shebangs
- id: requirements-txt-fixer
# =============================================================================
# Static typing
# =============================================================================
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
args: [--ignore-missing-imports]
# =============================================================================
# Security checks
# =============================================================================
- repo: https://github.com/PyCQA/bandit
rev: 1.7.8
hooks:
- id: bandit
args: ["-r", "src"]
# =============================================================================
# Secret detection
# =============================================================================
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets

74
Dockerfile Normal file
View File

@@ -0,0 +1,74 @@
# syntax=docker/dockerfile:1.7
# ============================================================
# Stage 1 — builder
# ============================================================
FROM python:3.13-slim AS builder
# Metadata arguments (для CI/CD)
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION=dev
# Python runtime оптимизация
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
# Установка uv (копируем бинарник напрямую — быстрее pip)
COPY --from=ghcr.io/astral-sh/uv:0.10.8 /uv /uvx /bin/
# Копируем только файлы зависимостей (Docker cache layer)
COPY pyproject.toml uv.lock* ./
# Установка зависимостей
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --no-dev --frozen
# ============================================================
# Stage 2 — runtime
# ============================================================
FROM python:3.13-slim
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION=dev
WORKDIR /app
# Python runtime оптимизация
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/app/.venv/bin:$PATH" \
PYTHONPATH="/app"
# Создание non-root пользователя
RUN groupadd -g 1000 app \
&& useradd -u 1000 -g app -m -s /usr/sbin/nologin app
# Копируем виртуальное окружение
COPY --from=builder /app/.venv /app/.venv
# Копируем код приложения
COPY --chown=app:app . .
# Создаём runtime директории
RUN mkdir -p logs data \
&& chown -R app:app /app
USER app
# OCI image metadata
LABEL org.opencontainers.image.title="Python Application" \
org.opencontainers.image.description="Production Python container" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}"
# Healthcheck (опционально)
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD python -c "import socket; s=socket.socket(); s.connect(('127.0.0.1',8000)); s.close()" || exit 1
# Default command
CMD ["python", "main.py"]

71
alembic.ini Normal file
View File

@@ -0,0 +1,71 @@
[alembic]
# Location of migration scripts
script_location = migrations
# Add project root to sys.path
prepend_sys_path = .
# Cross-platform path separator
version_path_separator = os
# Version file naming
file_template = %(year)d_%(month).2d_%(day).2d_%(hour).2d%(minute).2d_%(slug)s
# Timezone for migration timestamps
timezone = UTC
# Encoding for generated files
output_encoding = utf-8
# Migration locations
version_locations = migrations/versions
# Allow nested migration directories
recursive_version_locations = true
# Database URL should be provided via env.py / environment variables
sqlalchemy.url =
# =============================================================================
# Logging
# =============================================================================
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = default
[logger_root]
level = WARN
handlers = console
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = default
[formatter_default]
format = %(asctime)s | %(levelname)s | %(name)s | %(message)s
datefmt = %Y-%m-%d %H:%M:%S

36
babel.cfg Normal file
View File

@@ -0,0 +1,36 @@
# ==========================================================
# Babel configuration
# ==========================================================
# ----------------------------------------------------------
# Python source files
# ----------------------------------------------------------
[python: **.py]
encoding = utf-8
keywords =
_
gettext
ngettext:1,2
pgettext:1c,2
npgettext:1c,2,3
lazy_gettext
lazy_pgettext:1c,2
__
# ----------------------------------------------------------
# Jinja2 templates (optional)
# ----------------------------------------------------------
[jinja2: **/templates/**.html]
encoding = utf-8
# ----------------------------------------------------------
# Ignore directories
# ----------------------------------------------------------
[ignore: venv/**]
[ignore: .venv/**]
[ignore: env/**]
[ignore: migrations/**]
[ignore: alembic/**]
[ignore: tests/**]

71
cliff.toml Normal file
View File

@@ -0,0 +1,71 @@
# ============================================================
# GIT CLIFF CONFIGURATION
# ============================================================
[changelog]
header = """
# Changelog
All notable changes to this project will be documented in this file.
The format is based on:
https://keepachangelog.com
https://semver.org
"""
body = """
{% if version %}
## {{ version }} — {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## Unreleased
{% endif %}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group }}
{% for commit in commits %}
- {{ commit.message | upper_first }} ({{ commit.id | truncate(length=7, end="") }})
{% endfor %}
{% endfor %}
"""
footer = """
---
Generated automatically by git-cliff
"""
trim = true
[git]
conventional_commits = true
filter_unconventional = true
split_commits = false
sort_commits = "oldest"
commit_parsers = [
{ message = ".*!", group = "💥 Breaking Changes" },
{ message = "^feat(\\(.+\\))?:", group = "🚀 Features" },
{ message = "^fix(\\(.+\\))?:", group = "🐛 Bug Fixes" },
{ message = "^perf(\\(.+\\))?:", group = "⚡ Performance" },
{ message = "^refactor(\\(.+\\))?:", group = "♻️ Refactoring" },
{ message = "^docs(\\(.+\\))?:", group = "📚 Documentation" },
{ message = "^style(\\(.+\\))?:", group = "🎨 Styling" },
{ message = "^test(\\(.+\\))?:", group = "🧪 Tests" },
{ message = "^build(\\(.+\\))?:", group = "📦 Build System" },
{ message = "^ci(\\(.+\\))?:", group = "⚙️ CI" },
{ message = "^chore(\\(.+\\))?:", group = "🔧 Maintenance" }
]
tag_pattern = "v[0-9]*"
[remote.github]
owner = "your-user"
repo = "your-repo"

136
docker-compose.yml Normal file
View File

@@ -0,0 +1,136 @@
services:
app:
# Сборка Docker образа
build:
context: .
dockerfile: Dockerfile
# build arguments (используются в Dockerfile)
args:
VERSION: ${VERSION:-dev}
BUILD_DATE: ${BUILD_DATE:-unknown}
VCS_REF: ${VCS_REF:-unknown}
# Имя создаваемого образа
image: python-project
# Имя контейнера
container_name: python-project-app
# Файл переменных окружения
#
# Обычно содержит:
# DATABASE_URL
# REDIS_URL
# API_KEYS
env_file:
- .env
# Перезапуск контейнера при падении
restart: unless-stopped
# Проброс портов
#
# host:container
ports:
- "8000:8000"
# Подключаемые тома
#
# Используются для:
# • логов
# • данных приложения
volumes:
- logs:/app/logs
- data:/app/data
# Зависимости сервиса
#
# Если используются другие сервисы
# их можно добавить сюда
#
# depends_on:
# - postgres
# - redis
# Ограничения ресурсов (опционально)
#
# Полезно для production
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
cpus: "0.25"
memory: 128M
# Healthcheck контейнера
#
# Проверяет доступность сервиса
healthcheck:
test: ["CMD", "python", "-c", "import socket; s=socket.socket(); s.connect(('127.0.0.1',8000)); s.close()"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# ==========================================================
# PostgreSQL (пример базы данных)
# ==========================================================
#
# Закомментировано по умолчанию.
# Раскомментируйте при необходимости.
#
# postgres:
# image: postgres:16
#
# container_name: python-project-postgres
#
# environment:
# POSTGRES_DB: app
# POSTGRES_USER: app
# POSTGRES_PASSWORD: app
#
# volumes:
# - postgres_data:/var/lib/postgresql/data
#
# ports:
# - "5432:5432"
# ==========================================================
# Redis (пример кеша / очереди)
# ==========================================================
#
# redis:
# image: redis:7
#
# container_name: python-project-redis
#
# volumes:
# - redis_data:/data
#
# ports:
# - "6379:6379"
# ============================================================
# Docker volumes
# ============================================================
volumes:
# Логи приложения
logs:
# Данные приложения
data:
# PostgreSQL data (если используется)
# postgres_data:
# Redis data (если используется)
# redis_data: