← Назад к вопросам

За что отвечает CI в процессе разработки

2.0 Middle🔥 211 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

CI (Continuous Integration) в разработке

CI — это практика и инструментарий, который автоматизирует проверку кода и обеспечивает качество при каждом коммите. Рассмотрю полный спектр ответственности CI.

1. Основная ответственность CI

Главная роль: Проверить, что код готов к merge, ДО того как он попадёт в main ветку.

Разработчик коммитит код → CI запускается → Проверяет всё → Результат: OK или FAILED

Eсли CI падает, код в main не попадает (merge блокируется).

2. Линтинг и статический анализ

Задача: Поймать стилистические и логические ошибки до code review.

# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      
      - name: Install dependencies
        run: pip install ruff black mypy
      
      - name: Check formatting
        run: black --check .
      
      - name: Lint
        run: ruff check .
      
      - name: Type checking
        run: mypy .

Что проверяет:

  • Форматирование кода (Black, Prettier)
  • Стиль (PEP 8, Ruff)
  • Типизация (MyPy, Pyright)
  • Неиспользуемые импорты
  • Потенциальные ошибки
# Рассмотрите пример: Ruff поймает это

# Неиспользуемый импорт
import os  # ❌ Ruff скажет: "Unused import"

# Неопределённая переменная
print(undefined_var)  # ❌ MyPy скажет: "Name is not defined"

# Плохой формат
def func(x,y,z):  # ❌ Black переформатирует
    pass

# После CI fix
def func(x, y, z):  # ✅ Правильно
    pass

3. Unit тестирование

Задача: Убедиться, что логика работает правильно.

name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_PASSWORD: password
      redis:
        image: redis:7
    
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
      
      - name: Install dependencies
        run: pip install -e .
      
      - name: Run tests
        run: pytest --cov=. --cov-report=xml
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3

Пример теста:

import pytest
from app.users import create_user, get_user

@pytest.mark.asyncio
async def test_create_user():
    """Тест создания пользователя"""
    user = await create_user(email="test@example.com", password="secure123")
    assert user.email == "test@example.com"
    assert user.password_hash is not None  # Зашифрована

@pytest.mark.asyncio
async def test_get_user():
    """Тест получения пользователя"""
    user = await get_user(user_id=1)
    assert user is not None
    assert user.id == 1

@pytest.mark.asyncio
async def test_user_not_found():
    """Тест: пользователь не найден"""
    user = await get_user(user_id=99999)
    assert user is None

CI проверяет:

  • Все тесты проходят
  • Coverage >= 80% (или что-то требуемое)
  • Нет flaky tests
  • Performance tests (если есть)

4. Интеграционные тесты

Задача: Убедиться, что компоненты работают вместе.

# Пример: интеграция API + БД
import pytest
from httpx import AsyncClient
from app.main import app

@pytest.mark.asyncio
async def test_create_user_api():
    """Полный flow: HTTP request → Business logic → Database"""
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.post(
            "/api/v1/users",
            json={"email": "test@example.com", "password": "secure123"}
        )
        assert response.status_code == 201
        data = response.json()
        assert data["email"] == "test@example.com"
        
        # Проверяем, что в БД сохранилось
        get_response = await client.get(f"/api/v1/users/{data['id']}")
        assert get_response.status_code == 200

5. Security сканирование

Задача: Поймать уязвимости в зависимостях и коде.

name: Security
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      # Проверка зависимостей
      - name: Check dependencies
        run: pip install safety && safety check
      
      # SAST (Static Application Security Testing)
      - name: Security scanning
        run: pip install bandit && bandit -r . -f json
      
      # Secret scanning
      - name: Secret scanning
        uses: trufflesecurity/trufflehog@main

Что проверяет:

# Bandit поймёт уязвимости

# ❌ Уязвимо: SQL injection
query = f"SELECT * FROM users WHERE id = {user_id}"
db.execute(query)

# ✅ Безопасно: parameterized query
query = "SELECT * FROM users WHERE id = ?"
db.execute(query, (user_id,))

# ❌ Уязвимо: hardcoded secret
API_KEY = "sk_live_123456789"

# ✅ Безопасно: из environment
import os
API_KEY = os.getenv("API_KEY")

# ❌ Уязвимо: слабый hash
import hashlib
password_hash = hashlib.md5(password).hexdigest()

# ✅ Безопасно: bcrypt
from bcrypt import hashpw, gensalt
password_hash = hashpw(password.encode(), gensalt())

6. Build и артефакты

Задача: Убедиться, что проект успешно собирается.

name: Build
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Docker image
        run: docker build -t myapp:latest .
      
      - name: Push to registry
        if: github.ref == 'refs/heads/main'
        run: |
          docker tag myapp:latest myregistry.azurecr.io/myapp:latest
          docker push myregistry.azurecr.io/myapp:latest

Dockerfile:

FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]

7. Code coverage отчёты

Задача: Отследить процент протестированного кода.

- name: Run tests with coverage
  run: pytest --cov=app --cov-report=xml --cov-report=html

- name: Upload to codecov.io
  uses: codecov/codecov-action@v3
  with:
    files: ./coverage.xml

Требования в проекте:

# pyproject.toml или setup.cfg
[tool.pytest.ini_options]
addopts = "--cov=app --cov-report=term-missing --cov-fail-under=80"
# CI падает, если coverage < 80%

8. Code review автоматизация

Задача: Автоматически комментировать PR'ы.

name: Code Review Bot
on: [pull_request]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: AI Code Review (optional)
        uses: anc95/ChatGPT-CodeReview@main
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

9. Performance тестирование

Задача: Убедиться, что изменения не сломали производительность.

# benchmarks/test_performance.py
import pytest
from app.algorithm import process_data

def test_process_data_performance(benchmark):
    """Тест производительности"""
    data = list(range(1000))
    result = benchmark(process_data, data)
    assert len(result) > 0

# CI запустит с pytest-benchmark
# pytest benchmarks/ --benchmark-compare

10. Полный CI pipeline пример

name: CI Pipeline
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
      - run: pip install ruff black mypy
      - run: black --check .
      - run: ruff check .
      - run: mypy .
  
  test:
    runs-on: ubuntu-latest
    needs: lint  # Тесты только если lint passed
    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_PASSWORD: password
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
      - run: pip install -e .
      - run: pytest --cov=app --cov-fail-under=80
  
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: pip install safety bandit
      - run: safety check
      - run: bandit -r . -f json
  
  build:
    runs-on: ubuntu-latest
    needs: [lint, test, security]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      - name: Build and push
        run: |
          docker build -t myapp:latest .
          docker push myregistry.azurecr.io/myapp:latest

11. CI vs CD

CI (Continuous Integration): ← Мы говорим про это

  • Проверка кода при коммите
  • Автоматические тесты
  • Статический анализ
  • Падает, если что-то не так

CD (Continuous Deployment): ← Это следующий шаг

  • Автоматический деплой на production
  • Запускается, если CI прошёл успешно
  • Может быть с approval'ом

Заключение

CI отвечает за:

Качество кода — линтинг, форматирование, типизация ✅ Функциональность — unit, интеграционные тесты ✅ Безопасность — сканирование уязвимостей, secret detection ✅ Надёжность — coverage отчёты, performance tests ✅ Сборка — docker image'ы, артефакты

Правило: Если CI не зелёный — код в main не попадает. Это защита качества для всей команды.

За что отвечает CI в процессе разработки | PrepBro