Compare commits
10 Commits
c10fd31e56
...
77eeb009aa
| Author | SHA1 | Date | |
|---|---|---|---|
| 77eeb009aa | |||
| ef0c5e271f | |||
| 9696a5ec7f | |||
| f073637a8d | |||
| 78b6c41025 | |||
| 50d5dd39a2 | |||
| 74d04bc98a | |||
| 6558f67faf | |||
| af12fb38de | |||
| b6ab76a637 |
114
.gitea/workflows/ci.yml
Normal file
114
.gitea/workflows/ci.yml
Normal 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 .
|
||||
33
.gitea/workflows/format_code.yml
Normal file
33
.gitea/workflows/format_code.yml
Normal 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 .
|
||||
36
.gitea/workflows/security.yml
Normal file
36
.gitea/workflows/security.yml
Normal 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
|
||||
31
.gitea/workflows/workflow.yml
Normal file
31
.gitea/workflows/workflow.yml
Normal 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
55
.pre-commit-config.yaml
Normal 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
74
Dockerfile
Normal 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
71
alembic.ini
Normal 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
36
babel.cfg
Normal 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
71
cliff.toml
Normal 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
136
docker-compose.yml
Normal 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:
|
||||
Reference in New Issue
Block a user