Yes this is what I meant! If you structure it correctly using task runners and an environment manager you can do everything locally using the same versions etc. E.g.
```yaml name: Continuous Integration (CI)
on: pull_request
permissions: contents: read
jobs: formatting: name: Formatting runs-on: ${{ matrix.architecture }} strategy: matrix: architecture: [ubuntu-24.04, ubuntu-24.04-arm] language: [rust, shell, python] steps: - name: Checkout code. uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Setup Nix. uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0 - name: Check formatting. run: nix develop -c make check-${{ matrix.language }}-formatting
linting:
name: Linting
runs-on: ${{ matrix.architecture }}
strategy:
matrix:
architecture: [ubuntu-24.04, ubuntu-24.04-arm]
language: [rust]
steps:
- name: Checkout code.
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Nix.
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0
- name: Check linting.
run: nix develop -c make check-${{ matrix.language }}-linting
compile:
name: Compile
runs-on: ${{ matrix.architecture }}
strategy:
matrix:
architecture: [ubuntu-24.04, ubuntu-24.04-arm]
steps:
- name: Checkout code.
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Nix.
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0
- name: Compile.
run: nix develop -c make compile
unit-test:
name: Unit Test
runs-on: ${{ matrix.architecture }}
strategy:
matrix:
architecture: [ubuntu-24.04, ubuntu-24.04-arm]
steps:
- name: Checkout code.
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Nix.
uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31.9.0
- name: Unit test.
run: nix develop -c make unit-test
...
```