diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml new file mode 100644 index 000000000000..47613b1f5d56 --- /dev/null +++ b/.github/actions/setup-nix/action.yml @@ -0,0 +1,34 @@ +name: Set up Nix +description: >- + Install Nix and point it at the shared `argo-workflows` Cachix cache, so that + a job entering the development shell downloads the toolchain instead of + building it. Every job that runs `nix develop` should use this action rather + than installing Nix itself, so there is one place to change the installer + version and the cache configuration. + + Pull-only unless the caller passes `cachix-auth-token`. GitHub does not give + secrets to workflows triggered by pull requests from forks, so those jobs read + the cache and never write to it, whatever the caller asks for. + +inputs: + cachix-auth-token: + description: >- + Cachix token with write access to the cache, i.e. + `secrets.CACHIX_AUTH_TOKEN`. Pass it only from jobs whose whole purpose is + to populate the cache; leave it unset everywhere else and the job pulls + without pushing. + default: "" + +runs: + using: composite + steps: + # The installer turns on `nix-command` and `flakes`, and passes the job's + # GITHUB_TOKEN to Nix so that flake inputs fetched from GitHub are not + # rate-limited. + - uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0 + - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 + with: + name: argo-workflows + authToken: ${{ inputs.cachix-auth-token }} + # Pushing without a token fails the job, and most jobs have no token. + skipPush: ${{ inputs.cachix-auth-token == '' }} diff --git a/.github/workflows/nix.yaml b/.github/workflows/nix.yaml new file mode 100644 index 000000000000..f428ed37c67c --- /dev/null +++ b/.github/workflows/nix.yaml @@ -0,0 +1,74 @@ +# Keeps the Cachix cache stocked with the development shell, so entering it is a +# download everywhere else: on a contributor's machine, in the dev container and +# in CI. Nothing depends on this workflow succeeding — a cold cache only means +# the next `nix develop` builds the tools itself, slowly. +# +# Pushing needs a CACHIX_AUTH_TOKEN repository secret with write access to the +# `argo-workflows` cache. Without one — on a fork — the jobs still build the +# shell, they only read from the cache. +name: Nix + +on: + push: + branches: + - main + paths: # keep in step with the pull_request list below + - flake.nix + - flake.lock + - go.mod # the flake takes the Go version from here + - .github/actions/setup-nix/action.yml + - .github/workflows/nix.yaml + # So that a change to the toolchain is built and reviewed before it is merged, + # rather than breaking everyone's shell afterwards. + pull_request: + paths: + - flake.nix + - flake.lock + - go.mod + - .github/actions/setup-nix/action.yml + - .github/workflows/nix.yaml + # The tools also stop being cached when nothing changes: Cachix evicts, and + # nixpkgs garbage-collects what our closure is built against. + schedule: + - cron: "0 4 * * 1" # Mondays, ahead of the working week + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + linux: + name: Build development shell (x86_64-linux) + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: ./.github/actions/setup-nix + with: + # Pull requests only read the cache, whoever opened them: a branch + # anyone can push to must not be able to write to a cache everyone + # else trusts. + cachix-auth-token: ${{ github.event_name != 'pull_request' && secrets.CACHIX_AUTH_TOKEN || '' }} + - name: Build the development shell + # Realises every tool the shell puts on PATH. Cachix pushes each one as + # it is built; anything substituted from cache.nixos.org is already + # public and is not copied into our cache. + run: nix develop --profile "$RUNNER_TEMP/devshell" --command true + + darwin: + name: Build development shell (aarch64-darwin) + # A macOS runner bills at ten times the Linux rate, so this one sits out + # pull requests and warms the cache once the change is merged. Apple + # silicon only: nobody develops on x86_64-darwin any more. + if: github.event_name != 'pull_request' + runs-on: macos-15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: ./.github/actions/setup-nix + with: + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + - name: Build the development shell + run: nix develop --profile "$RUNNER_TEMP/devshell" --command true diff --git a/docs/running-locally.md b/docs/running-locally.md index 552fa6554d85..1e8c2d0a18b8 100644 --- a/docs/running-locally.md +++ b/docs/running-locally.md @@ -41,6 +41,21 @@ whatever the shell provides is what `make codegen`, `make lint` and `make test` If you use [direnv](https://direnv.net), `direnv allow` once and the shell is entered whenever you `cd` into the repo. Install [nix-direnv](https://github.com/nix-community/nix-direnv) alongside it so that is instant. +#### Binary cache + +Most of the shell comes from the public nixpkgs cache, but the pinned tools are built by this project and nobody else, +so they are not in it. CI builds them for `x86_64-linux` and `aarch64-darwin` and pushes them to the +[`argo-workflows`](https://app.cachix.org/cache/argo-workflows) [Cachix](https://cachix.org) cache. Point Nix at it and +entering the shell is a download rather than a compile: + +```bash +nix run nixpkgs#cachix -- use argo-workflows +``` + +That writes the cache and its public key into your Nix configuration; on a multi-user install it will ask for `sudo`, +or tell you to add yourself to `trusted-users` first. It is optional — without it everything still works, it is just +slower the first time and after each tool upgrade. + #### Upgrading a tool Everything lives in `flake.nix`, in two tiers: