CI/CD для Rust проектов: GitHub Actions продвинутый уровень

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

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

Начать курс

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

Базовый CI/CD пайплайн для Rust — это хорошо, но в реальных проектах, особенно с несколькими платформами, зависимостями и необходимостью быстрой обратной связи, простого cargo test недостаточно. Продвинутая настройка GitHub Actions позволяет сократить время сборки в 2-3 раза, автоматически проверять код на разных архитектурах, публиковать крейты и выполнять линтинг.

В этой статье мы разберём продвинутые техники: кэширование зависимостей, матрицу сборок для Windows/macOS/Linux, параллельный запуск тестов, публикацию в crates.io и интеграцию с Clippy.

1. Оптимизация времени сборки: кэширование и инкрементальные компиляции

Самая затратная операция в CI для Rust — это компиляция зависимостей. Без кэширования каждый запуск будет скачивать и собирать все крейты заново. Решение — использовать встроенный кэш GitHub Actions.

Базовое кэширование target директории

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions-rust-lang/setup-rust-toolchain@v1
      - name: Cache Rust dependencies
        uses: actions/cache@v3
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - run: cargo build --release

Ключевой момент: ключ кэша включает хеш Cargo.lock. Если зависимости не менялись, кэш восстанавливается мгновенно.

Продвинутое разделение кэша для тестов и сборки

Для больших проектов имеет смысл разделять кэш для cargo build и cargo test, чтобы не пересобирать тестовые бинарники при сборке релиза:

- name: Cache cargo build
  uses: actions/cache@v3
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
      target/debug/.fingerprint
      target/debug/build
    key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.lock') }}

2. Матрица сборок: тестирование на всех платформах

Rust компилируется под множество платформ. Чтобы гарантировать корректную работу на Windows, macOS и Linux, используем матрицу стратегий (matrix strategy).

Пример матрицы для трёх ОС

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        toolchain: [stable, beta]
        features:
          - default
          - all
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.toolchain }}
      - name: Run tests
        run: cargo test --features ${{ matrix.features }}

Такой подход автоматически создаёт 6 параллельных джоб (3 ОС × 2 тулчейна). Вы можете добавить проверку на nightly, архитектуры arm64 или кросс-компиляцию для WASM.

Исключение ненужных комбинаций

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    toolchain: [stable, nightly]
    exclude:
      - os: macos-latest
        toolchain: nightly  # Не тестируем nightly на macOS

3. Линтинг, форматирование и безопасность

Помимо тестов, продвинутый CI включает статический анализ. Добавим проверки clippy, rustfmt и cargo-audit для уязвимостей.

Отдельный job для линтинга

lint:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions-rust-lang/setup-rust-toolchain@v1
      with:
        components: clippy, rustfmt
    - name: Check formatting
      run: cargo fmt --check
    - name: Clippy with warnings as errors
      run: cargo clippy -- -D warnings

Проверка безопасности зависимостей

security:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Install cargo-audit
      run: cargo install cargo-audit
    - name: Audit dependencies
      run: cargo audit

Эти джобы выполняются параллельно с тестами, экономя время.

4. Автоматическая публикация в crates.io

Когда код прошёл все проверки, можно автоматически публиковать новый релиз. Для этого используем условный запуск по тегу (semver) или по пушу в main.

Публикация по созданию тега

publish:
  if: startsWith(github.ref, 'refs/tags/v')
  runs-on: ubuntu-latest
  needs: [test, lint, security]
  steps:
    - uses: actions/checkout@v4
    - uses: actions-rust-lang/setup-rust-toolchain@v1
    - name: Login to crates.io
      run: cargo login ${{ secrets.CARGO_REGISTRY_TOKEN }}
    - name: Publish crate
      run: cargo publish

Не забудьте добавить секрет CARGO_REGISTRY_TOKEN в настройках репозитория (Settings → Secrets and variables).

Создание GitHub Release

- name: Create Release
  uses: softprops/action-gh-release@v1
  with:
    files: target/release/my-rust-binary
    body_path: CHANGELOG.md
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

5. Параллельные тесты и Code Coverage

Для ускорения тестов можно разделить их на несколько джобов, используя cargo test --test для каждого файла тестов. Но более практичный вариант — собирать coverage с помощью tarpaulin или cargo-llvm-cov.

Пример с cargo-llvm-cov

coverage:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions-rust-lang/setup-rust-toolchain@v1
      with:
        components: llvm-tools-preview
    - name: Install cargo-llvm-cov                

Блоги

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