Введение

Цель : Сопроводить читателя в создании минималистичного, но функционального CI/CD-пайплайна для Python-приложения с автоматическим развертыванием на PyPI.

Автоматизация процессов разработки стала неизбежной в современных проектах. Хорошо спроектированный CI/CD‑pipeline позволяет не только выявлять регрессии на ранних этапах цикла разработки, но и полностью автоматизировать процесс развёртывания.

В этой статье мы рассмотрим, как настроить полный пайплайн с GitHub Actions для приложения Python: от непрерывной интеграции (CI) до непрерывного развертывания (CD) на PyPI.

Архитектура конвейера

Наш конвейер состоит из двух отдельных рабочих процессов:

  1. конвейер CI: Выполняется при каждом push и pull request

  2. Конвейер CD: Срабатывает только во время релизов GitHub

@startuml
!theme plain

package "Репозиторий GitHub" {
  [Source Code] as source
  [GitHub Actions] as actions
}

package "CI-пайплайн" {
  [Checkout] as checkout_ci
  [Setup Python] as python_ci
  [Install Dependencies] as deps_ci
  [Linting (Ruff)] as lint
  [Unit Tests] as tests
}

package "Конвейер CD" {
  [Checkout] as checkout_cd
  [Setup Python] as python_cd
  [Build Package] as build
  [Publish to PyPI] as pypi
}

source --> actions : Push/PR
actions --> checkout_ci
checkout_ci --> python_ci
python_ci --> deps_ci
deps_ci --> lint
lint --> tests

source --> actions : Release
actions --> checkout_cd : On Release
checkout_cd --> python_cd
python_cd --> build
build --> pypi

@enduml

Настройка конвейера непрерывной интеграции (CI)

Структура CI Workflow

CI-рабочий процесс разработан для проверки каждого вклада в код. Вот его полная конфигурация:

name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install ruff pytest pytest-mock

    - name: Run Linting (Ruff)
      run: ruff check .

    - name: Run Tests (Pytest)
      run: pytest

Анализ этапов CI

Триггеры (on)

----
----
----
----
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
----

Конвейер запускается при: - Каждый push в ветку`main` - Каждый pull request к`main`

Этот подход гарантирует, что основной код остаётся стабильным и что любой вклад одобрен перед интеграцией.

==== 2. Среда выполнения

----

runs-on: ubuntu-latest

Ubuntu Latest предлагает хороший компромисс между производительностью, стоимостью и совместимостью для большинства проектов на Python.

==== 3. Выдача кода

----

- name: Checkout code uses: actions/checkout@v4

действие`checkout@v4`Получает исходный код репозитория. Версия v4 приносит улучшения производительности и безопасности.

==== 4. Конфигурация Python

- name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x'

Использование`'3.x'`позволяет автоматически использовать последнюю стабильную версию Python 3, упрощая обслуживание.

==== 5. Установка зависимостей

----

- name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install ruff pytest pytest-mock

Этап: - Обновить pip до последней версии - Установите зависимости проекта - Добавьте инструменты разработки (линтинг и тесты)

==== 6. Линтинг с Ruff

- name: Run Linting (Ruff) run: ruff check .

**Ruff**является сверхбыстрым линтером Python, написанным на Rust. Он объединяет функции нескольких инструментов (Flake8, Black, isort) в один мощный инструмент.

==== 7. Выполнение тестов

- name: Run Tests (Pytest) run: pytest

Pytest запускает весь набор тестов, гарантируя, что изменения не вызывают регрессий.

== Конфигурация пайплайна развертывания (CD)

=== Структура рабочего процесса CD

CD workflow запускается только при релизах GitHub и автоматизирует публикацию на PyPI :

[source,yaml]
----
name: Publish to PyPI

on:
  release:
    types:
      - published

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine

    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*
----

=== Анализ этапов CD

==== 1. Срабатывание Release

on: release: types: - published

Pipeline CD срабатывает только при публикации релиза GitHub. Такой подход обеспечивает точный контроль над развертываниями.

==== 2. Установка средств сборки

```yaml
----
----
----
----
pip install setuptools wheel twine
----

- **setuptools**: Инструменты упаковки Python - **колесо**: Формат дистрибутива современного Питона - **шпагат**: Безопасный инструмент для загрузки в PyPI

==== 3. Настройка аутентификации

----

env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}

Аутентификация использует токен API PyPI, хранящийся как секрет GitHub, который более безопасен, чем классические учётные данные.

==== 4. Сборка и публикация

----

run: | python setup.py sdist bdist_wheel twine upload dist/*

- `sdist`Создаёт исходный дистрибутив - `bdist_wheel`: Создаёт wheel (бинарное распределение) - `twine upload`Опубликуй дистрибутивы на PyPI

== Настройка пакета Python

=== Структура setup.py

Чтобы пайплайн работал, ваш проект должен включать файл`setup.py`:

[source,python]
----
from setuptools import setup, find_packages

with open("README.adoc", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setup(
    name="playlist-downloader",
    version="1.0.0",
    author="Votre Nom",
    author_email="[email protected]",
    description="CLI tool for managing YouTube playlists",
    long_description=long_description,
    long_description_content_type="text/plain",
    url="https://github.com/cheroliv/playlist-downloader",
    packages=find_packages(),
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
    ],
    python_requires=">=3.8",
    install_requires=[
        "typer>=0.9.0",
        "yt-dlp>=2023.1.6",
        "google-api-python-client>=2.70.0",
        "google-auth-oauthlib>=0.7.1",
        "pymonad>=2.4.0",
        "pyyaml>=6.0",
    ],
    entry_points={
        "console_scripts": [
            "playlist-downloader=cli:app",
        ],
    },
)
----

=== Ключевые моменты setup.py

1. **Метаданные**: Название, версия, автор, описание
2. **Зависимости**Список требуемых пакетов
3. **Точки входа**: Открытые команды CLI
4. **Классификаторы**: Метаданные для PyPI

== Безопасность с использованием секретов GitHub

=== Настройка токена PyPI

1. **Создать токен API на PyPI**:

- Войдите в PyPI - Перейдите в Account Settings > API tokens - Создайте новый токен с соответствующими разрешениями

1. **Добавить секрет в GitHub** :

- Настройки репозитория > Секреты и переменные > Действия - Создайте новый секрет с именем`PYPI_API_TOKEN` Вставьте ваш токен PyPI

[plantuml, secrets-flow, svg]
----
@startuml
!theme plain

actor Developer as dev
participant "Репозиторий GitHub" as repo
participant "GitHub Actions" as actions
participant PyPI

dev -> repo : Configure PYPI_API_TOKEN secret
repo -> actions : Trigger CD pipeline on release
actions -> actions : Access secret securely
actions -> PyPI : Authenticate with token
PyPI -> PyPI : Validate and publish package

note over actions, PyPI
  Token never exposed in logs
  Automatic rotation possible
end note

@enduml
----

== Воркфлоу полного развертывания

=== Последовательность развёртывания

[plantuml, deployment-sequence, svg]
----
@startuml
!theme plain

actor Developer as dev
participant "Локальный Git" as git
participant "GitHub" as github
participant "GitHub Действия" as actions
participant PyPI
participant "Конечные пользователи" as users

dev -> git : git tag v1.0.0
dev -> git : git push origin v1.0.0
git -> github : Push tag
dev -> github : Create release from tag
github -> actions : Trigger CD pipeline
actions -> actions : Checkout code
actions -> actions : Setup Python environment
actions -> actions : Install build tools
actions -> actions : Build distributions (sdist + wheel)
actions -> PyPI : Upload to PyPI with token
PyPI -> PyPI : Validate and publish
users -> PyPI : pip install playlist-downloader

note over dev, github
  Release creation can be automated
  or done manually through GitHub UI
end note

@enduml
----

=== Состояния трубопровода

[plantuml, pipeline-states, svg]
----
@startuml
!theme plain

[*] --> Idle

Idle --> CI_Running : Push/PR created
CI_Running --> CI_Success : All checks pass
CI_Running --> CI_Failed : Linting/Tests fail
CI_Success --> Idle : Merge completed
CI_Failed --> Idle : Fix and retry

Idle --> CD_Running : Release published
CD_Running --> CD_Success : Package published
CD_Running --> CD_Failed : Build/Upload error
CD_Success --> Idle : Package available on PyPI
CD_Failed --> Idle : Fix and retry release

note on link #red : Blocks merge
note on link #green : Allows deployment

@enduml
----

== Хорошие практики и оптимизации

=== Управление версиями

Используйте семантические теги Git :

git tag -a v1.2.3 -m "Release version 1.2.3" git push origin v1.2.3

=== 2. Тесты матрицы

Для тестирования на нескольких версиях Python :

----

strategy: matrix: python-version: [3.8, 3.9, "3.10", "3.11"]

=== 3. Кэш зависимостей

Ускорьте сборки с помощью кэша :

- name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}

=== 4. Среды развертывания

Используйте среды GitHub для контролируемых развертываний:

jobs: deploy: environment: production runs-on: ubuntu-latest

1. **Добавить секрет в GitHub** :

=== Диаграмма вариантов использования

[plantuml, use-cases, svg]
----
@startuml
!theme plain

left to right direction

actor "разработчик" as dev
actor "GitHub Actions" as ga
actor "Конечный пользователь" as user

package "Система CI/CD" {
  usecase "Запустить линтинг" as lint
  usecase "Выполнить тесты" as test
  usecase "Сборка пакета" as build
  usecase "Опубликовать в PyPI" as publish
  usecase "Создать релиз" as release
}

dev --> lint : Pushes code
dev --> test : Pushes code
dev --> release : Creates release
ga --> build : On release trigger
ga --> publish : After successful build
user --> publish : Downloads package

lint .> test : triggers
test .> build : on success
build .> publish : on success

@enduml
----

=== Архитектура развертывания

[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain

cloud "Гитхаб" {
  [Source Repository]
  [GitHub Actions]
  [Secrets Store]
}

cloud "PyPI" {
  [Package Registry]
  [Distribution Files]
}

node "CI/CD пайплайн" {
  [Linting]
  [Testing]
  [Building]
  [Publishing]
}

[Source Repository] --> [GitHub Actions] : Triggers
[GitHub Actions] --> [Linting]
[Linting] --> [Testing]
[Testing] --> [Building]
[Building] --> [Publishing]
[Publishing] --> [Package Registry] : Uploads
[Secrets Store] --> [Publishing] : Provides token

note as N1
  Secure token-based
  authentication
end note

[Secrets Store] .. N1

@enduml
----

== Мониторинг и отладка

=== Логи и мониторинг

GitHub Actions предоставляет подробные журналы для каждого шага. Для отладки:

1. **Проверьте логи**де каждого шага
2. **Активируйте отладку**с`ACTIONS_STEP_DEBUG`
3. **Используйте артефакты**для сохранения файлов сборки

- name: Upload build artifacts uses: actions/upload-artifact@v3 if: failure() with: name: build-logs path: build/

=== Уведомления

Добавьте уведомления Slack или email :

```yaml
----
----
----
----
- name: Notify on failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----

== Заключение

Внедрение надёжного CI/CD-пайплайна с использованием GitHub Actions кардинально преобразует опыт разработки. Автоматизируя линтинг, тесты и развёртывание, вы :

- **Сократите ошибки**в производстве - **Ускорьте циклы**разработки - **Улучшите доверие**в ваших релизах - **Упростите сотрудничество**в команде

Этот пайплайн можно адаптировать к различным типам проектов Python, настраивая инструменты линтинга, фреймворки тестирования или места развертывания.

Первоначальные инвестиции в настройку этих рабочих процессов быстро окупаются за счёт экономии времени и снижения количества ручных ошибок при развертывании.

== Дополнительные ресурсы

- https://docs.github.com/en/actions[Документация GitHub Actions] - https://packaging.python.org/[Руководство по упаковке Python] - https://docs.pytest.org/[Документация Pytest] - https://docs.astral.sh/ruff/[Документация Ruff] - https://twine.readthedocs.io/[Документация Twine]

✅ Функциональный конвейер достигнут! Теперь у вас есть простой конвейер CI/CD, который позволяет автоматизировать ваши тесты и публиковать ваш пакет Python на PyPI напрямую из GitHub Actions.

Однако этот конвейер сознательно остаётся минималистичным. Он ещё не покрывает некоторые необходимые аспекты в профессиональном контексте :

Тесты нескольких версий Python,

Автоматический анализ безопасности,

Постепенное развертывание через Test PyPI,

Мониторинг и метрики конвейера,

Автоматизация версионирования и интеграция современных лучших практик (pyproject.toml).

В следующей части мы перейдём на следующий уровень. Вы научитесь превращать этот базовый пайплайн в настоящую промышленную цепочку развёртывания, надёжную и безопасную, готовую для производственных проектов на Python.
----
----

Для тестирования на нескольких версиях Python:

----

strategy: matrix: python-version: [3.8, 3.9, "3.10", "3.11"]

=== 3. Кэширование зависимостей

Ускорьте сборку с помощью кэша:

```yaml
----
----
- name: Cache pip dependencies
  uses: actions/cache@v3
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
----

=== 4. Среды развертывания

Используйте среды GitHub для контролируемого развертывания:

----

jobs: deploy: environment: production runs-on: ubuntu-latest

== Сценарии использования и архитектура

=== Диаграмма вариантов использования

[plantuml, use-cases, svg]
----
@startuml
!theme plain

left to right direction

actor "Разработчик" as dev
actor "GitHub Actions" as ga
actor "Конечный пользователь" as user

package "Система CI/CD" {
  usecase "Запуск линтинга" as lint
  usecase "Выполнение тестов" as test
  usecase "Сборка пакета" as build
  usecase "Публикация в PyPI" as publish
  usecase "Создание релиза" as release
}

dev --> lint : Pushes code
dev --> test : Pushes code
dev --> release : Creates release
ga --> build : On release trigger
ga --> publish : After successful build
user --> publish : Downloads package

lint .> test : triggers
test .> build : on success
build .> publish : on success

@enduml
----

=== Архитектура развертывания

1. **Добавить секрет в GitHub**Пожалуйста, предоставьте текст для перевода.

== Мониторинг и отладка

=== Логи и мониторинг

GitHub Actions предоставляет подробные логи для каждого шага. Для отладки:

1. **Изучите логи**каждого шага
2. **Активируйте режим отладки**с`ACTIONS_STEP_DEBUG`
3. **Используйте артефакты**для сохранения файлов сборки

```yaml
----
----
- name: Upload build artifacts
  uses: actions/upload-artifact@v3
  if: failure()
  with:
    name: build-logs
    path: build/
----

=== Уведомления

Добавьте уведомления в Slack или по электронной почте:

----

- name: Notify on failure if: failure() uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} webhook_url: ${{ secrets.SLACK_WEBHOOK }}

== Заключение

Внедрение надежного CI/CD-конвейера с помощью GitHub Actions радикально меняет процесс разработки. Автоматизируя линтинг, тестирование и развертывание, вы:

- **Сократите количество ошибок**в продакшене - **Ускорьте циклы**разработки - **Повысьте доверие**в ваших релизах - **Облегчите сотрудничество**в команде

Этот конвейер может быть адаптирован к различным типам Python-проектов путем настройки инструментов линтинга, фреймворков для тестирования или целей развертывания.

Первоначальные инвестиции в настройку этих рабочих процессов быстро окупаются за счет экономии времени и сокращения количества ручных ошибок при развертывании.

== Дополнительные ресурсы

- https://docs.github.com/en/actions[Документация GitHub Actions] - https://packaging.python.org/[Руководство по упаковке Python] - https://docs.pytest.org/[Документация Pytest] - https://docs.astral.sh/ruff/[Документация Ruff] - https://twine.readthedocs.io/[Документация Twine]

✅ Функциональный конвейер достигнут! Теперь у вас есть простой CI/CD-конвейер, который позволяет автоматизировать тестирование и публиковать ваш Python-пакет в PyPI напрямую из GitHub Actions.

Однако этот пайплайн намеренно остается минималистичным. Он пока не охватывает некоторые аспекты, необходимые в профессиональном контексте:

Тесты для нескольких версий Python,

Автоматический анализ безопасности,

Поэтапное развертывание через Test PyPI,

Мониторинг и метрики конвейера,

Автоматизация версионирования и внедрение современных лучших практик (`pyproject.toml`).

В следующей части мы перейдем на новый уровень. Вы научитесь превращать этот базовый конвейер в полноценную промышленную цепочку развертывания — надежную и безопасную, готовую к производственным проектам на Python.

=== Диаграмма вариантов использования

[plantuml, use-cases, svg]
----
@startuml
!theme plain

left to right direction

actor "Разработчик" as dev
actor "GitHub Actions" as ga
actor "Конечный пользователь" as user

package "Система CI/CD" {
  usecase "Запустить линтинг" as lint
  usecase "Выполнить тесты" as test
  usecase "Собрать пакет" as build
  usecase "Опубликовать в PyPI" as publish
  usecase "Создать релиз" as release
}

dev --> lint : Pushes code
dev --> test : Pushes code
dev --> release : Creates release
ga --> build : On release trigger
ga --> publish : After successful build
user --> publish : Downloads package

lint .> test : triggers
test .> build : on success
build .> publish : on success

@enduml
----

=== Архитектура развертывания

[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain

cloud "GitHub" {
  [Source Repository]
  [GitHub Actions]
  [Secrets Store]
}

cloud "PyPI" {
  [Package Registry]
  [Distribution Files]
}

node "CI/CD конвейер" {
  [Linting]
  [Testing]
  [Building]
  [Publishing]
}

[Source Repository] --> [GitHub Actions] : Triggers
[GitHub Actions] --> [Linting]
[Linting] --> [Testing]
[Testing] --> [Building]
[Building] --> [Publishing]
[Publishing] --> [Package Registry] : Uploads
[Secrets Store] --> [Publishing] : Provides token

note as N1
Безопасная аутентификация на основе токенов
end note

[Secrets Store] .. N1

@enduml
----

== Мониторинг и отладка

=== Логи и мониторинг

GitHub Actions предоставляет подробные логи для каждого шага. Для отладки:

1. **Изучите логи**каждого step
2. **Активируйте debug**с`ACTIONS_STEP_DEBUG`
3. **Используйте артефакты**для сохранения файлов сборки

```yaml
----
- name: Upload build artifacts
  uses: actions/upload-artifact@v3
  if: failure()
  with:
    name: build-logs
    path: build/
----

=== Уведомления

Добавьте уведомления в Slack или по электронной почте:

```yaml
----
- name: Notify on failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----

== Заключение

Внедрение надежного CI/CD-конвейера с помощью GitHub Actions радикально меняет процесс разработки. Автоматизируя линтинг, тестирование и развертывание, вы:

- **Сократите количество ошибок**в продакшене - **Ускорьте циклы**разработки - **Повысьте уровень доверия**в ваших релизах - **Облегчите сотрудничество**в команде

Этот конвейер может быть адаптирован к различным типам Python-проектов путем настройки инструментов линтинга, тестовых фреймворков или целей развертывания.

Первоначальные инвестиции в настройку этих рабочих процессов быстро окупаются за счет экономии времени и сокращения количества ручных ошибок при развертывании.

== Дополнительные ресурсы

- https://docs.github.com/en/actions[Документация GitHub Actions] - https://packaging.python.org/[Руководство по упаковке Python] - https://docs.pytest.org/[Документация Pytest] - https://docs.astral.sh/ruff/[Документация Ruff] - https://twine.readthedocs.io/[Документация Twine]

✅ Функциональный конвейер достигнут! Теперь у вас есть простой CI/CD-конвейер, который позволяет автоматизировать тестирование и публиковать ваш Python-пакет в PyPI напрямую через GitHub Actions.

Тем не менее, этот конвейер намеренно остается минималистичным. Он пока не охватывает некоторые аспекты, необходимые в профессиональном контексте:

Тестирование нескольких версий Python,

Автоматический анализ безопасности,

Постепенное развертывание через Test PyPI,

Мониторинг и метрики конвейера,

Автоматизация версионирования и внедрение современных лучших практик (`pyproject.toml`).

В следующей части мы перейдем на следующий уровень. Вы научитесь превращать этот базовый пайплайн в полноценную промышленную цепочку развертывания, надежную и безопасную, готовую для продакшн-проектов на Python.

Похожие статьи