GitHub Actions cache Rust artifacts

Viewed 2509

Using GitHub Actions, I am unable to see a significant improvement from using cached artifacts produced from previous builds, when building with Rust's cargo.

I suspect I forgot something in the following code, what could be the problem here?

EDIT: Here are the logs if you want to have a look at them!

name: Rust

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

env:
  CARGO_TERM_COLOR: always

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Cargo Cache
      uses: actions/cache@v1
      with:
        path: ~/.cargo
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
          ${{ runner.os }}-cargo

    - name: Cargo Target Cache
      uses: actions/cache@v1
      with:
        path: target
        key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.toml') }}-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.toml') }}
          ${{ runner.os }}-cargo-target

    - uses: actions/checkout@v2
    - name: Build
      run: cargo build --verbose --all --features "strict"
    - name: Run tests
      run: cargo test --verbose --all --features "strict"
3 Answers

You can cache the target and .cargo folders in one step. Here's an example of my setup for building and testing a back end web API.

name: Continuous Integration

on: [push, pull_request]

jobs:
  build_and_test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:10.12-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: pongstars
        ports:
          - 5432:5432
        # needed because the postgres container does not provide a healthcheck
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      - uses: actions/checkout@v2
      - name: ⚡ Cache
        uses: actions/cache@v2
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - uses: actions-rs/toolchain@v1
        with:
          toolchain: stable

      - name:  Build
        uses: actions-rs/cargo@v1
        with:
          command: build

      - name: Create env file
        run: mv .env.example .env

      - name:  Test
        uses: actions-rs/cargo@v1
        with:
          command: test

      - name: ⚙ Integration test
        uses: actions-rs/cargo@v1
        with:
          command: test
          args: --features "integration_tests"

Looking at https://github.com/actions/cache/blob/main/examples.md#rust---cargo as an example, I think you could switch to something like:

name: Rust

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

env:
  CARGO_TERM_COLOR: always

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

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

    - name: Build
      run: cargo build --verbose --all --features "strict"
    - name: Run tests
      run: cargo test --verbose --all --features "strict"

I tried it out on my own project because I was having trouble, but Mihai's suggestion of adding the checkout step first made a big difference.

I think I got it working now: build time reduced from 4 minutes down to 1m15s.

The fixes I applied were:

  • I needed to first check out the repository to have the Cargo.toml file used in the hashing function for the cache (!).
  • **/Cargo.toml was refactored to Cargo.toml, so that the file is found for hashing.

Here's the final rust.yaml:

name: Rust

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

env:
  CARGO_TERM_COLOR: always

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Cargo Cache
      uses: actions/cache@v1
      with:
        path: ~/.cargo
        key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
        restore-keys: |
          ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
          ${{ runner.os }}-cargo

    - name: Cargo Target Cache
      uses: actions/cache@v1
      with:
        path: target
        key: ${{ runner.os }}-cargo-target-${{ hashFiles('Cargo.toml') }}
        restore-keys: |
          ${{ runner.os }}-cargo-target-${{ hashFiles('Cargo.toml') }}
          ${{ runner.os }}-cargo-target

    - name: Build
      run: cargo build --verbose --all --features "strict"
    - name: Run tests
      run: cargo test --verbose --all --features "strict"

Related