Introduction: Why CI/CD is Important for Rust Projects
Developing in Rust is not only about memory safety and high performance. In the modern world, any serious project requires automation of build, testing, and deployment processes. CI/CD (Continuous Integration / Continuous Deployment) allows teams to release updates faster, reducing the risk of human errors and ensuring codebase stability.
GitHub Actions is a built-in GitHub tool for automating workflows. It is ideal for Rust projects as it provides ready-made actions for installing the compiler, caching dependencies, and publishing crates to crates.io. In this article, we will walk through setting up a full CI/CD pipeline for a Rust application from scratch.
1. GitHub Actions Basics for Rust
Before diving into the code, let's understand the basic structure of GitHub Actions. Each workflow is defined by a YAML file located in the .github/workflows/ directory. A workflow consists of one or more jobs that run sequentially or in parallel on virtual machines (runners).
For Rust projects, a minimal workflow includes the following steps:
- Checkout — fetching the latest version of the code from the repository.
- Install Rust — via the
actions-rs/toolchainaction or the officialdtolnay/rust-toolchain. - Cache dependencies — speeding up builds by saving
target/and~/.cargo/. - Build and test — running
cargo buildandcargo test.
Example of a basic workflow (file .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 --checkThis workflow runs on every push to the main branch and on every pull request. It checks that the code compiles, passes tests, has no linter errors, and conforms to formatting style.
2. Advanced Strategies: Matrix Build and Caching
Rust is a cross-platform language, and it is often necessary to verify the build on multiple operating systems or architectures. For this, a matrix build is used.
Let's add support for Windows and macOS to our workflow:
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 --