17 Commits

Author SHA1 Message Date
dd94dcdb46 Merge pull request 'feat: improve CI/CD workflows and code quality checks' (#6) from dev-6 into main
All checks were successful
Deploy to Production / Deploy to Production (push) Successful in 20s
Deploy to Production / Rollback to Previous Version (push) Has been skipped
Reviewed-on: #6
2026-02-28 22:09:01 +00:00
7d12bebb6e feat: improve CI/CD workflows and code quality checks
All checks were successful
CI pipeline / Test & Code Quality (push) Successful in 14s
CI pipeline / Test & Code Quality (pull_request) Successful in 13s
- ci.yml: fix workflow_dispatch (was missing options), add pull_request trigger
- deploy.yml: add dry_run option for safe testing deployments
- Makefile: improve code quality targets to include bots subdirectories
- docker-compose.yml: clean up telegram-bot env vars (use env_file)

Made-with: Cursor
2026-03-01 01:01:54 +03:00
e35415d3d1 Merge branch 'main' of https://github.com/KerradKerridi/prod 2026-02-01 22:31:08 +03:00
25dd64fc01 feat: add coverage test targets for Telegram bot and AnonBot in Makefile 2026-02-01 22:31:03 +03:00
ANDREY KATYKHIN
51c2a562fa Merge pull request #5 from KerradKerridi/dev-5
refactor: упростил скрипты deploy.yml и ci.yml
2026-01-25 22:26:16 +03:00
4d328444bd refactor: упростил скрипты deploy.yml и ci.yml 2026-01-25 22:24:12 +03:00
804ecd6107 remove: delete health check step from deploy workflow 2026-01-25 20:51:27 +03:00
d736688c62 fix: increase container wait time, fix status variable name, fix delays array for zsh 2026-01-25 20:43:12 +03:00
1bfe772a0d fix: use flock directly with file instead of file descriptor for zsh compatibility 2026-01-25 20:36:07 +03:00
e360e5e215 fix: replace exec 200 with flock -x 9 for zsh compatibility 2026-01-25 20:33:08 +03:00
76cb533851 fix: use exec for flock file descriptors to work with zsh 2026-01-25 20:27:55 +03:00
30465e0bea debug: add more verbose logging for secrets in deploy steps 2026-01-25 20:24:06 +03:00
0a73f9844e fix: pass secrets directly to SSH scripts instead of using env 2026-01-25 20:14:49 +03:00
2ee1977956 feat: add workflow_dispatch to deploy.yml and debug secrets 2026-01-25 20:09:18 +03:00
220b24e867 Merge branch 'dev-4' 2026-01-25 20:08:34 +03:00
fb33da172a debug: add secrets availability check in deploy workflow 2026-01-25 20:08:25 +03:00
ANDREY KATYKHIN
9baee2ceb7 Merge pull request #4 from KerradKerridi/dev-4
Merge dev-4 into main
2026-01-25 19:58:22 +03:00
5 changed files with 318 additions and 1391 deletions

90
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,90 @@
name: CI pipeline
on:
push:
branches: [ 'dev-*', 'feature/**' ]
pull_request:
branches: [ 'main' ]
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
name: Test & Code Quality
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/infra/requirements-test.txt
pip install "black>=24.0,<25" "isort>=5.13,<6" flake8 mypy || true
- name: Code quality (Black + isort) — те же команды, что make code-quality
run: |
make format-check import-check || (echo "" && echo "❌ Code style drift. Locally run: make import-fix && make format && git add -A && git commit -m 'style: isort + black'" && exit 1)
- name: Linting (flake8) - Critical errors
run: |
echo "🔍 Running flake8 linter (critical errors only)..."
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- name: Linting (flake8) - Warnings
run: |
echo "🔍 Running flake8 linter (warnings)..."
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics || true
continue-on-error: true
- name: Run infrastructure tests
run: |
python -m pytest tests/infra/ -v --tb=short
- name: Validate Prometheus config
run: |
python -m pytest tests/infra/test_prometheus_config.py -v
- name: Send test success notification
if: success()
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
✅ CI Tests Passed
📦 Repository: prod
🌿 Branch: ${{ github.ref_name }}
📝 Commit: ${{ github.sha }}
👤 Author: ${{ github.actor }}
✅ All tests passed! Code quality checks completed successfully.
🔗 View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
continue-on-error: true
- name: Send test failure notification
if: failure()
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
❌ CI Tests Failed
📦 Repository: prod
🌿 Branch: ${{ github.ref_name }}
📝 Commit: ${{ github.sha }}
👤 Author: ${{ github.actor }}
❌ Tests failed! Deployment blocked. Please fix the issues and try again.
🔗 View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
continue-on-error: true

File diff suppressed because it is too large Load Diff

View File

@@ -1,451 +0,0 @@
name: CI & CD pipeline
on:
push:
branches: [ main, 'develop', 'dev-*', 'feature/**' ]
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: true
type: choice
options:
- rollback
rollback_to_commit:
description: 'Commit hash to rollback to (optional, uses last deploy if empty)'
required: false
type: string
jobs:
test:
runs-on: ubuntu-latest
name: Test & Code Quality
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/infra/requirements-test.txt
pip install flake8 black isort mypy || true
- name: Code formatting check (Black)
run: |
echo "🔍 Checking code formatting with Black..."
black --check . || (echo "❌ Code formatting issues found. Run 'black .' to fix." && exit 1)
- name: Import sorting check (isort)
run: |
echo "🔍 Checking import sorting with isort..."
isort --check-only . || (echo "❌ Import sorting issues found. Run 'isort .' to fix." && exit 1)
- name: Linting (flake8) - Critical errors
run: |
echo "🔍 Running flake8 linter (critical errors only)..."
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- name: Linting (flake8) - Warnings
run: |
echo "🔍 Running flake8 linter (warnings)..."
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics || true
continue-on-error: true
- name: Run infrastructure tests
run: |
python -m pytest tests/infra/ -v --tb=short
- name: Validate Prometheus config
run: |
python -m pytest tests/infra/test_prometheus_config.py -v
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
.pytest_cache/
htmlcov/
retention-days: 7
- name: Send test failure notification
if: failure()
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
❌ CI Tests Failed
📦 Repository: prod
🌿 Branch: ${{ github.ref_name }}
📝 Commit: ${{ github.sha }}
👤 Author: ${{ github.actor }}
❌ Tests failed! Deployment blocked. Please fix the issues and try again.
🔗 View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
continue-on-error: true
create-pr:
runs-on: ubuntu-latest
name: Create Pull Request
needs: test
if: |
github.event_name == 'push' &&
needs.test.result == 'success' &&
github.ref_name != 'main' &&
github.ref_name != 'develop' &&
(startsWith(github.ref_name, 'dev-') || startsWith(github.ref_name, 'feature/'))
# Примечание: Для создания PR из той же ветки нужен PAT (Personal Access Token)
# Создайте PAT с правами repo и добавьте в Secrets как PAT
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
persist-credentials: true
- name: Check if PR already exists
id: check-pr
uses: actions/github-script@v6
with:
github-token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
script: |
const branchName = context.ref.replace('refs/heads/', '');
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: context.repo.owner + ':' + branchName,
base: 'main',
state: 'open'
});
if (prs.length > 0) {
core.setOutput('exists', 'true');
core.setOutput('number', prs[0].number);
core.setOutput('url', prs[0].html_url);
} else {
core.setOutput('exists', 'false');
}
- name: Update existing PR
if: steps.check-pr.outputs.exists == 'true'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
script: |
const prNumber = parseInt('${{ steps.check-pr.outputs.number }}');
const branchName = context.ref.replace('refs/heads/', '');
const commitSha = '${{ github.sha }}';
const author = '${{ github.actor }}';
const updateBody = '## Updated Changes\n\n' +
'PR updated with new commits after successful CI tests.\n\n' +
'- Latest commit: ' + commitSha + '\n' +
'- Branch: `' + branchName + '`\n' +
'- Author: @' + author + '\n\n' +
'## Test Results\n\n' +
'✅ All tests passed successfully!\n\n' +
'Please review the changes and merge when ready.';
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
title: 'Merge ' + branchName + ' into main',
body: updateBody
});
console.log('✅ PR #' + prNumber + ' updated successfully');
- name: Create Pull Request
if: steps.check-pr.outputs.exists == 'false'
id: create-pr
uses: actions/github-script@v6
with:
github-token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
script: |
const branchName = context.ref.replace('refs/heads/', '');
console.log('📝 Creating PR from ' + branchName + ' to main...');
try {
const commitSha = '${{ github.sha }}';
const author = '${{ github.actor }}';
const prBody = '## Changes\n\n' +
'This PR was automatically created after successful CI tests.\n\n' +
'- Branch: `' + branchName + '`\n' +
'- Commit: `' + commitSha + '`\n' +
'- Author: @' + author + '\n\n' +
'## Test Results\n\n' +
'✅ All tests passed successfully!\n\n' +
'Please review the changes and merge when ready.';
const { data: pr } = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Merge ' + branchName + ' into main',
head: branchName,
base: 'main',
body: prBody,
draft: false
});
// Добавляем labels
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ['automated', 'ready-for-review']
});
} catch (labelError) {
console.log('⚠️ Could not add labels: ' + labelError.message);
}
core.setOutput('number', pr.number.toString());
core.setOutput('url', pr.html_url);
console.log('✅ PR #' + pr.number + ' created successfully: ' + pr.html_url);
} catch (error) {
console.error('❌ Failed to create PR: ' + error.message);
if (error.status === 422) {
console.log('⚠️ PR might already exist or branch is up to date with base');
// Пробуем найти существующий PR
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: context.repo.owner + ':' + branchName,
base: 'main',
state: 'open'
});
if (prs.length > 0) {
const pr = prs[0];
core.setOutput('number', pr.number.toString());
core.setOutput('url', pr.html_url);
console.log('✅ Found existing PR #' + pr.number + ': ' + pr.html_url);
} else {
core.setOutput('number', '');
const serverUrl = '${{ github.server_url }}';
const repo = '${{ github.repository }}';
core.setOutput('url', serverUrl + '/' + repo + '/pulls');
throw error;
}
} else {
throw error;
}
}
- name: Send PR notification - PR exists
if: steps.check-pr.outputs.exists == 'true'
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
Pull Request Updated
📦 Repository: prod
🌿 Branch: ${{ github.ref_name }} → main
📝 Commit: ${{ github.sha }}
👤 Author: ${{ github.actor }}
✅ All tests passed! PR #${{ steps.check-pr.outputs.number }} already exists and has been updated.
🔗 View PR: ${{ steps.check-pr.outputs.url }}
continue-on-error: true
- name: Send PR notification - PR created
if: steps.check-pr.outputs.exists == 'false' && steps.create-pr.outcome == 'success'
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
📝 Pull Request Created
📦 Repository: prod
🌿 Branch: ${{ github.ref_name }} → main
📝 Commit: ${{ github.sha }}
👤 Author: ${{ github.actor }}
${{ steps.create-pr.outputs.number != '' && format('✅ All tests passed! Pull request #{0} has been created and is ready for review.', steps.create-pr.outputs.number) || '✅ All tests passed! Pull request has been created and is ready for review.' }}
${{ steps.create-pr.outputs.url != '' && format('🔗 View PR: {0}', steps.create-pr.outputs.url) || format('🔗 View PRs: {0}/{1}/pulls', github.server_url, github.repository) }}
continue-on-error: true
rollback:
runs-on: ubuntu-latest
name: Manual Rollback
if: |
github.event_name == 'workflow_dispatch' &&
github.event.inputs.action == 'rollback'
environment:
name: production
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: main
- name: Manual Rollback
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ vars.SERVER_HOST || secrets.SERVER_HOST }}
username: ${{ vars.SERVER_USER || secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ vars.SSH_PORT || secrets.SSH_PORT || 22 }}
script: |
set -e
echo "🔄 Starting manual rollback..."
cd /home/prod
DEPLOY_HISTORY="/home/prod/.deploy_history.txt"
DEPLOY_HISTORY_SIZE="${DEPLOY_HISTORY_SIZE:-10}"
# Определяем коммит для отката
if [ -n "${{ github.event.inputs.rollback_to_commit }}" ]; then
ROLLBACK_COMMIT="${{ github.event.inputs.rollback_to_commit }}"
echo "📝 Using specified commit: $ROLLBACK_COMMIT"
else
# Используем последний успешный деплой из истории
ROLLBACK_COMMIT=$(grep "|success" "$DEPLOY_HISTORY" 2>/dev/null | tail -1 | cut -d'|' -f2 || echo "")
# Если нет в истории, используем сохраненный коммит
if [ -z "$ROLLBACK_COMMIT" ]; then
if [ -f "/tmp/last_deploy_commit.txt" ]; then
ROLLBACK_COMMIT=$(cat /tmp/last_deploy_commit.txt)
echo "📝 Using saved commit from /tmp/last_deploy_commit.txt: $ROLLBACK_COMMIT"
else
echo "❌ No commit specified and no previous deploy found!"
exit 1
fi
else
echo "📝 Using last successful deploy from history: $ROLLBACK_COMMIT"
fi
fi
# Проверяем что коммит существует
git fetch origin main
if ! git rev-parse --verify "$ROLLBACK_COMMIT" > /dev/null 2>&1; then
echo "❌ Commit $ROLLBACK_COMMIT not found!"
exit 1
fi
# Откатываем код
echo "🔄 Rolling back to commit: $ROLLBACK_COMMIT"
# Исправляем права на файлы
sudo chown -R deploy:deploy /home/prod || true
git reset --hard "$ROLLBACK_COMMIT"
# Устанавливаем правильные права после отката
sudo chown -R deploy:deploy /home/prod || true
echo "✅ Code rolled back to: $ROLLBACK_COMMIT"
# Пересобираем все контейнеры с обновлением базовых образов и кешированием
echo "🔨 Rebuilding all containers with --pull (updating base images, using cache)..."
docker-compose down || true
docker-compose build --pull
docker-compose up -d
echo "✅ Containers rebuilt and started"
# Ждем запуска сервисов
echo "⏳ Waiting for services to start (45 seconds)..."
sleep 45
# Health checks с экспоненциальным retry
check_health() {
local service=$1
local url=$2
local attempt=1
local delays=(5 15 45)
local max_attempts=${#delays[@]}
echo "🔍 Checking $service health..."
while [ $attempt -le $max_attempts ]; do
if curl -f -s --max-time 10 "$url" > /dev/null 2>&1; then
echo "✅ $service is healthy (attempt $attempt/$max_attempts)"
return 0
else
if [ $attempt -lt $max_attempts ]; then
delay=${delays[$((attempt - 1))]}
echo "⏳ $service not ready yet (attempt $attempt/$max_attempts), waiting ${delay} seconds..."
sleep $delay
else
echo "❌ $service health check failed after $max_attempts attempts"
return 1
fi
fi
attempt=$((attempt + 1))
done
return 1
}
HEALTH_CHECK_FAILED=0
check_health "Prometheus" "http://localhost:9090/-/healthy" || HEALTH_CHECK_FAILED=1
check_health "Grafana" "http://localhost:3000/api/health" || HEALTH_CHECK_FAILED=1
check_health "Telegram Bot" "http://localhost:8080/health" || HEALTH_CHECK_FAILED=1
check_health "AnonBot" "http://localhost:8081/health" || HEALTH_CHECK_FAILED=1
if [ $HEALTH_CHECK_FAILED -eq 1 ]; then
echo "⚠️ Some health checks failed, but rollback completed"
else
echo "✅ All health checks passed after rollback!"
fi
# Обновляем историю
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s" "$ROLLBACK_COMMIT" 2>/dev/null || echo "Manual rollback")
COMMIT_AUTHOR="${{ github.actor }}"
echo "${TIMESTAMP}|${ROLLBACK_COMMIT}|${COMMIT_MESSAGE}|${COMMIT_AUTHOR}|rolled_back" >> "$DEPLOY_HISTORY"
# Оставляем только последние N записей
tail -n "$DEPLOY_HISTORY_SIZE" "$DEPLOY_HISTORY" > "${DEPLOY_HISTORY}.tmp" && mv "${DEPLOY_HISTORY}.tmp" "$DEPLOY_HISTORY"
echo "✅ Rollback completed successfully"
- name: Send rollback notification
if: always()
uses: appleboy/telegram-action@v1.0.0
with:
to: ${{ secrets.TELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
message: |
🔄 Manual Rollback: ${{ job.status }}
📦 Repository: prod
🌿 Branch: main
📝 Commit: ${{ github.event.inputs.rollback_to_commit || 'Previous successful deploy' }}
👤 Author: ${{ github.actor }}
${{ job.status == 'success' && '✅ Rollback completed successfully! Services restored to specified version.' || '❌ Rollback failed! Check logs for details.' }}
🔗 View details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
continue-on-error: true

View File

@@ -175,10 +175,23 @@ test-bot: check-bot-deps ## Запустить тесты Telegram бота
@echo "🤖 Запускаю тесты Telegram бота..."
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ -v
test-bot-coverage: check-bot-deps ## Запустить тесты Telegram бота с отчетом о покрытии
@echo "🤖 Запускаю тесты Telegram бота..."
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ --cov=helper_bot --cov-report=term-missing --cov-report=html:htmlcov/bot
@echo "📊 Отчеты о покрытии сохранены в htmlcov/"
@echo " - Telegram бот: $(shell python3 count_tests.py | head -2 | tail -1) тестов"
test-anonBot: check-anonBot-deps ## Запустить тесты AnonBot
@echo "🔒 Запускаю тесты AnonBot..."
@cd bots/AnonBot && python3 -m pytest tests/ -v
test-anonBot-coverage: check-anonBot-deps ## Запустить тесты AnonBot с отчетом о покрытии
@echo "🔒 Запускаю тесты AnonBot..."
@cd bots/AnonBot && python3 -m pytest tests/ --cov=. --cov-report=term-missing --cov-report=html:htmlcov/anonbot
@echo "📊 Отчеты о покрытии сохранены в htmlcov/"
@echo " - AnonBot: $(shell python3 count_tests.py | head -3 | tail -1) тестов"
test-coverage: check-deps check-bot-deps check-anonBot-deps ## Запустить все тесты с отчетом о покрытии
@echo "📊 Запускаю все тесты с отчетом о покрытии..."
@echo "📈 Покрытие для инфраструктуры..."
@@ -333,58 +346,83 @@ auth-list: ## Показать список пользователей мони
# ========================================
# Code Quality & Formatting
# ========================================
# Явный список .py файлов (find не зависит от .gitignore). Black при обходе директорий
# учитывает .gitignore, поэтому передаём файлы явно, чтобы проверять и bots/.
PY_FIND_PATHS := . bots/telegram-helper-bot bots/AnonBot
PY_FIND_EXCLUDE := -not -path '*/.venv/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' -not -path '*/.git/*'
format-check: ## Проверить форматирование кода (Black)
@echo "🔍 Checking code formatting with Black..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black --check . || (echo "❌ Code formatting issues found. Run 'make format' to fix." && exit 1); \
@PY_FILES=$$(find $(PY_FIND_PATHS) -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null | sort -u); \
if [ -z "$$PY_FILES" ]; then \
PY_FILES=$$(find . -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null); \
fi; \
echo " Files: $$(echo "$$PY_FILES" | wc -l | tr -d ' ') .py files"; \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black --check $$PY_FILES || (echo "❌ Code formatting issues found. Run 'make format' to fix." && exit 1); \
else \
python3 -m black --check . || (echo "❌ Code formatting issues found. Run 'make format' to fix." && exit 1); \
python3 -m black --check $$PY_FILES || (echo "❌ Code formatting issues found. Run 'make format' to fix." && exit 1); \
fi
@echo "✅ Code formatting is correct!"
format: ## Автоматически исправить форматирование кода (Black)
@echo "🎨 Formatting code with Black..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black .; \
@PY_FILES=$$(find $(PY_FIND_PATHS) -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null | sort -u); \
if [ -z "$$PY_FILES" ]; then \
PY_FILES=$$(find . -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null); \
fi; \
echo " Files: $$(echo "$$PY_FILES" | wc -l | tr -d ' ') .py files"; \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black $$PY_FILES; \
else \
python3 -m black .; \
python3 -m black $$PY_FILES; \
fi
@echo "✅ Code formatted!"
format-diff: ## Показать что будет изменено Black (без применения)
@echo "📋 Showing Black diff (no changes applied)..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black --diff .; \
@PY_FILES=$$(find $(PY_FIND_PATHS) -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null | sort -u); \
if [ -z "$$PY_FILES" ]; then PY_FILES=$$(find . -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null); fi; \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m black --diff $$PY_FILES; \
else \
python3 -m black --diff .; \
python3 -m black --diff $$PY_FILES; \
fi
import-check: ## Проверить сортировку импортов (isort)
import-check: ## Проверить сортировку импортов (isort, профиль black)
@echo "🔍 Checking import sorting with isort..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m isort --check-only . || (echo "❌ Import sorting issues found. Run 'make import-fix' to fix." && exit 1); \
@PY_FILES=$$(find $(PY_FIND_PATHS) -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null | sort -u); \
if [ -z "$$PY_FILES" ]; then PY_FILES=$$(find . -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null); fi; \
echo " Files: $$(echo "$$PY_FILES" | wc -l | tr -d ' ') .py files"; \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m isort --profile black --check-only $$PY_FILES || (echo "❌ Import sorting issues found. Run 'make import-fix' to fix." && exit 1); \
else \
python3 -m isort --check-only . || (echo "❌ Import sorting issues found. Run 'make import-fix' to fix." && exit 1); \
python3 -m isort --profile black --check-only $$PY_FILES || (echo "❌ Import sorting issues found. Run 'make import-fix' to fix." && exit 1); \
fi
@echo "✅ Import sorting is correct!"
import-fix: ## Автоматически исправить сортировку импортов (isort)
import-fix: ## Автоматически исправить сортировку импортов (isort, профиль black)
@echo "📦 Fixing import sorting with isort..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m isort .; \
@PY_FILES=$$(find $(PY_FIND_PATHS) -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null | sort -u); \
if [ -z "$$PY_FILES" ]; then PY_FILES=$$(find . -name "*.py" $(PY_FIND_EXCLUDE) 2>/dev/null); fi; \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m isort --profile black $$PY_FILES; \
else \
python3 -m isort .; \
python3 -m isort --profile black $$PY_FILES; \
fi
@echo "✅ Imports sorted!"
lint-check: ## Проверить код линтером (flake8) - только критические ошибки
@echo "🔍 Running flake8 linter (critical errors only)..."
@if [ -f .venv/bin/python ]; then \
.venv/bin/python -m flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=".venv,venv,__pycache__,.git,*.pyc" || true; \
else \
python3 -m flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=".venv,venv,__pycache__,.git,*.pyc" || true; \
fi
@for dir in . bots/telegram-helper-bot bots/AnonBot; do \
if [ -d "$$dir" ]; then \
if [ -f .venv/bin/python ]; then \
.venv/bin/python -m flake8 $$dir --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=".venv,venv,__pycache__,.git,*.pyc" 2>/dev/null || true; \
else \
python3 -m flake8 $$dir --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=".venv,venv,__pycache__,.git,*.pyc" 2>/dev/null || true; \
fi; \
fi; \
done
@echo "✅ Linting check completed (non-critical warnings in dependencies ignored)!"
code-quality: format-check import-check lint-check ## Проверить качество кода (все проверки)

View File

@@ -148,23 +148,8 @@ services:
- LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-30}
- METRICS_HOST=${METRICS_HOST:-0.0.0.0}
- METRICS_PORT=${METRICS_PORT:-8080}
# Telegram settings (токены из GitHub Secrets имеют приоритет над .env)
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-${BOT_TOKEN}}
- TELEGRAM_LISTEN_BOT_TOKEN=${TELEGRAM_LISTEN_BOT_TOKEN:-${LISTEN_BOT_TOKEN}}
- TELEGRAM_TEST_BOT_TOKEN=${TELEGRAM_TEST_BOT_TOKEN:-${TEST_BOT_TOKEN}}
- TELEGRAM_PREVIEW_LINK=${PREVIEW_LINK:-false}
- TELEGRAM_MAIN_PUBLIC=${MAIN_PUBLIC}
- TELEGRAM_GROUP_FOR_POSTS=${GROUP_FOR_POSTS}
- TELEGRAM_GROUP_FOR_MESSAGE=${GROUP_FOR_MESSAGE}
- TELEGRAM_GROUP_FOR_LOGS=${GROUP_FOR_LOGS}
- TELEGRAM_IMPORTANT_LOGS=${IMPORTANT_LOGS}
- TELEGRAM_ARCHIVE=${ARCHIVE}
- TELEGRAM_TEST_GROUP=${TEST_GROUP}
# Bot settings
- SETTINGS_LOGS=${LOGS:-false}
- SETTINGS_TEST=${TEST:-false}
# Database
- DATABASE_PATH=${DATABASE_PATH:-database/tg-bot-database.db}
# Остальные переменные (токены, чаты, админы) — только из env_file: ./bots/telegram-helper-bot/.env
volumes:
- ./bots/telegram-helper-bot/database:/app/database:rw
- ./bots/telegram-helper-bot/logs:/app/logs:rw