Compare commits
15 Commits
dev-4
...
e35415d3d1
| Author | SHA1 | Date | |
|---|---|---|---|
| e35415d3d1 | |||
| 25dd64fc01 | |||
|
|
51c2a562fa | ||
| 4d328444bd | |||
| 804ecd6107 | |||
| d736688c62 | |||
| 1bfe772a0d | |||
| e360e5e215 | |||
| 76cb533851 | |||
| 30465e0bea | |||
| 0a73f9844e | |||
| 2ee1977956 | |||
| 220b24e867 | |||
| fb33da172a | |||
|
|
9baee2ceb7 |
99
.github/workflows/ci.yml
vendored
Normal file
99
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
name: CI pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ 'dev-*', 'feature/**' ]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
action:
|
||||||
|
description: 'Action to perform'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
|
||||||
|
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: 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
|
||||||
1011
.github/workflows/deploy.yml
vendored
1011
.github/workflows/deploy.yml
vendored
File diff suppressed because it is too large
Load Diff
451
.github/workflows/pipeline.yml
vendored
451
.github/workflows/pipeline.yml
vendored
@@ -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
|
|
||||||
13
Makefile
13
Makefile
@@ -175,10 +175,23 @@ test-bot: check-bot-deps ## Запустить тесты Telegram бота
|
|||||||
@echo "🤖 Запускаю тесты Telegram бота..."
|
@echo "🤖 Запускаю тесты Telegram бота..."
|
||||||
@cd bots/telegram-helper-bot && source .venv/bin/activate && python3 -m pytest tests/ -v
|
@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
|
test-anonBot: check-anonBot-deps ## Запустить тесты AnonBot
|
||||||
@echo "🔒 Запускаю тесты AnonBot..."
|
@echo "🔒 Запускаю тесты AnonBot..."
|
||||||
@cd bots/AnonBot && python3 -m pytest tests/ -v
|
@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 ## Запустить все тесты с отчетом о покрытии
|
test-coverage: check-deps check-bot-deps check-anonBot-deps ## Запустить все тесты с отчетом о покрытии
|
||||||
@echo "📊 Запускаю все тесты с отчетом о покрытии..."
|
@echo "📊 Запускаю все тесты с отчетом о покрытии..."
|
||||||
@echo "📈 Покрытие для инфраструктуры..."
|
@echo "📈 Покрытие для инфраструктуры..."
|
||||||
|
|||||||
Reference in New Issue
Block a user