CI/CD для Rust проектов: настройка GitHub Actions

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему CI/CD важен для Rust-проектов

Разработка на Rust — это не только про безопасность памяти и высокую производительность. В современном мире любой серьёзный проект требует автоматизации процессов сборки, тестирования и развёртывания. CI/CD (Continuous Integration / Continuous Deployment) позволяет командам быстрее выпускать обновления, снижая риск человеческих ошибок и обеспечивая стабильность кодовой базы.

GitHub Actions — это встроенный инструмент GitHub для автоматизации рабочих процессов. Он идеально подходит для Rust-проектов, так как предоставляет готовые экшены для установки компилятора, кэширования зависимостей и публикации крейтов в crates.io. В этой статье мы разберём, как настроить полноценный CI/CD пайплайн для Rust-приложения с нуля.

1. Основы GitHub Actions для Rust

Перед тем как погрузиться в код, давайте разберёмся с базовой структурой GitHub Actions. Каждый workflow определяется YAML-файлом, который лежит в директории .github/workflows/. Workflow состоит из одного или нескольких job (задач), которые выполняются последовательно или параллельно на виртуальных машинах (раннерах).

Для Rust-проектов минимальный workflow включает следующие шаги:

  • Checkout — получение последней версии кода из репозитория.
  • Установка Rust — через экшн actions-rs/toolchain или официальный dtolnay/rust-toolchain.
  • Кэширование зависимостей — ускорение сборки за счёт сохранения target/ и ~/.cargo/.
  • Сборка и тестирование — выполнение cargo build и cargo test.

Пример базового workflow (файл .github/workflows/ci.yml):

name: Rust CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        components: clippy, rustfmt
    
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: |
          ~/.cargo/
          target/
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Build
      run: cargo build --verbose
    
    - name: Run tests
      run: cargo test --verbose
    
    - name: Lint with clippy
      run: cargo clippy -- -D warnings
    
    - name: Check formatting
      run: cargo fmt --check

Этот workflow запускается при каждом push в ветку main и при создании pull request. Он проверяет, что код компилируется, проходит тесты, не содержит ошибок линтера и соответствует стилю форматирования.

2. Продвинутые стратегии: матричная сборка и кэширование

Rust — кроссплатформенный язык, и часто требуется проверять сборку на нескольких операционных системах или архитектурах. Для этого используется матричная сборка (matrix build).

Добавим в наш workflow поддержку Windows и macOS:

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        rust: [stable, beta]
    
    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: ${{ matrix.rust }}
        components: clippy
    
    - name: Cache
      uses: actions/cache@v3
      with:
        path: |
          ~/.cargo/registry/
          ~/.cargo/git/
          target/
        key: ${{ matrix.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Build
      run: cargo build --release
    
    - name: Test
      run: cargo test --release

Кэширование target/ и ~/.cargo/ — критически важный шаг для Rust. Без него каждый запуск CI будет скачивать все зависимости заново, что может занимать 5-10 минут. Ключ кэша включает хеш от Cargo.lock, поэтому при изменении зависимостей кэш автоматически инвалидируется.

Также полезно добавить проверку на наличие неиспользуемого кода с помощью cargo deadlinks или cargo udeps (для nightly Rust):

- name: Check for unused dependencies
  run: cargo +nightly udeps
  continue-on-error: true

3. Публикация крейта в crates.io

Одна из самых частых задач — автоматическая публикация новой версии крейта при создании git-тега. Для этого используется экшн actions-rs/cargo или прямое выполнение команды cargo publish.

Важно: для публикации потребуется API-токен от crates.io. Его нужно добавить в Secrets вашего репозитория (Settings → Secrets and variables → Actions) как CRATES_IO_TOKEN.

Пример workflow для публикации:

name: Publish to crates.io

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  publish:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    
    - name: Verify version
      run: |
        VERSION=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')
        TAG=${GITHUB_REF#refs/tags/v}
        if [ "$VERSION" != "$TAG" ]; then
          echo "Version mismatch: Cargo.toml has $VERSION, tag has $TAG"
          exit 1
        fi
    
    - name: Publish
      run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}

Этот workflow делает следующее:

  • Запускается только при создании тега вида v1.2.3.
  • Проверяет, что версия в Cargo.toml совпадает с тегом — это защита от случайной публикации.
  • Публикует крейт с использованием секретного токена.

Для дополнительной безопасности можно добавить шаг с запуском всех тестов перед публикацией:

- name: Run tests before publish
  run: cargo test --release

Блоги

Рекомендаций по книгам