Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/actions/setup-nix/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Set up Nix
description: >
Nix with the PiFinder binary cache (cache.pifinder.io). Every workflow uses
this action, so all jobs get the same Nix settings and the same cache.
inputs:
attic-token:
description: Token that lets the job push to the cache. Empty means pull only.
required: false
default: ""
self-hosted:
description: '"true" on a self-hosted runner, which already has Nix installed.'
required: false
default: "false"
runs:
using: composite
steps:
- if: inputs.self-hosted != 'true'
uses: DeterminateSystems/nix-installer-action@main
with:
determinate: false
extra-conf: |
extra-system-features = big-parallel
extra-substituters = https://cache.pifinder.io/pifinder
extra-trusted-public-keys = pifinder:8UU/O3oLkaJHHUyqEcPGl+9F1m4MqDca39Ewl49jBmE=

- if: inputs.self-hosted == 'true'
shell: bash
run: |
echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"

- name: Attic login
shell: bash
env:
ATTIC_TOKEN: ${{ inputs.attic-token }}
run: |
if [ -z "$ATTIC_TOKEN" ]; then
echo "No Attic token: the job pulls from the cache but does not push"
exit 0
fi
export PATH="/nix/var/nix/profiles/default/bin:$HOME/.nix-profile/bin:$PATH"
nix profile install nixpkgs#attic-client
attic login pifinder https://cache.pifinder.io "$ATTIC_TOKEN"
attic use pifinder:pifinder
16 changes: 16 additions & 0 deletions .github/scripts/push_dev_shell.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Push a flake dev shell, with every package in it, to the PiFinder cache.
#
# Usage: push_dev_shell.sh <system> [shell]
#
# The mkShell output is one small text file that references no packages, so a
# push of that output leaves the packages out of the cache. The shell's
# inputDerivation references every package the shell uses, so this script
# pushes that.
set -euo pipefail

system="$1"
shell="${2:-default}"

path="$(nix build ".#devShells.$system.$shell.inputDerivation" --no-link --print-out-paths)"
attic push pifinder:pifinder "$path"
58 changes: 24 additions & 34 deletions .github/workflows/nixos-pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,18 @@ jobs:
# review gate for running contributor code.
allow-unsafe-pr-checkout: true

- uses: DeterminateSystems/nix-installer-action@main
# The shared CI action and scripts come from the base branch, which is
# trusted code, and never from the PR head.
- uses: actions/checkout@v4
with:
determinate: false
extra-conf: |
extra-system-features = big-parallel
extra-substituters = https://cache.pifinder.io/pifinder
extra-trusted-public-keys = pifinder:8UU/O3oLkaJHHUyqEcPGl+9F1m4MqDca39Ewl49jBmE=
ref: ${{ github.event.pull_request.base.ref }}
path: .ci
sparse-checkout: .github
persist-credentials: false

- name: Attic login for push
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
run: |
if [ -z "$ATTIC_TOKEN" ]; then
echo "No ATTIC_TOKEN — pull-only via the public substituter"
exit 0
fi
nix profile install nixpkgs#attic-client
attic login pifinder https://cache.pifinder.io "$ATTIC_TOKEN"
attic use pifinder:pifinder
- uses: ./.ci/.github/actions/setup-nix
with:
attic-token: ${{ secrets.ATTIC_TOKEN }}

- name: Build NixOS system and on-device dev shell closures
run: |
Expand All @@ -87,12 +80,10 @@ jobs:
run: |
STORE_PATH=$(nix build .#nixosConfigurations.pifinder.config.system.build.toplevel \
--json | jq -r '.[].outputs.out')
DEV_SHELL_PATH=$(nix build .#devShells.aarch64-linux.default \
--json | jq -r '.[].outputs.out')
echo "store_path=$STORE_PATH" >> "$GITHUB_OUTPUT"
if [ -n "$ATTIC_TOKEN" ]; then
attic push pifinder:pifinder "$STORE_PATH"
attic push pifinder:pifinder "$DEV_SHELL_PATH"
.ci/.github/scripts/push_dev_shell.sh aarch64-linux
else
echo "No ATTIC_TOKEN — skipping push; build is verify-only"
fi
Expand Down Expand Up @@ -122,18 +113,19 @@ jobs:
# review gate for running contributor code.
allow-unsafe-pr-checkout: true

- name: Ensure nix is on PATH (self-hosted runner)
run: |
echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"
# The shared CI action and scripts come from the base branch, which is
# trusted code, and never from the PR head.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.ref }}
path: .ci
sparse-checkout: .github
persist-credentials: false

- name: Setup Attic substituter (cache.pifinder.io)
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
run: |
nix profile install nixpkgs#attic-client
attic login pifinder https://cache.pifinder.io "$ATTIC_TOKEN"
attic use pifinder:pifinder
- uses: ./.ci/.github/actions/setup-nix
with:
attic-token: ${{ secrets.ATTIC_TOKEN }}
self-hosted: "true"

- name: Build NixOS system and on-device dev shell closures
run: |
Expand All @@ -146,10 +138,8 @@ jobs:
run: |
STORE_PATH=$(nix build .#nixosConfigurations.pifinder.config.system.build.toplevel \
--json | jq -r '.[].outputs.out')
DEV_SHELL_PATH=$(nix build .#devShells.aarch64-linux.default \
--json | jq -r '.[].outputs.out')
attic push pifinder:pifinder "$STORE_PATH"
attic push pifinder:pifinder "$DEV_SHELL_PATH"
.ci/.github/scripts/push_dev_shell.sh aarch64-linux
echo "store_path=$STORE_PATH" >> "$GITHUB_OUTPUT"

# Stamp the PR's build into the metadata-only nixos-manifest branch. Runs the
Expand Down
66 changes: 46 additions & 20 deletions .github/workflows/nox.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,70 @@
name: nox
# The nixos branch manages the Python environment with uv (pyproject.toml +
# uv.lock) instead of nox + requirements*.txt, so this runs the same checks
# (ruff, mypy, pytest) through uv. The workflow keeps upstream's "nox" name so
# The nixos branch manages the Python environment with uv2nix (pyproject.toml +
# uv.lock) instead of nox + requirements*.txt. This runs the ruff, mypy and
# pytest checks in the flake dev shell, the same Nix environment that
# developers and the PiFinder use. The workflow keeps upstream's "nox" name so
# PR check wiring stays identical across branches.
#
# Run on pushes to the long-lived branches and on pull requests. Restricting
# `push` to main/release means a push to a feature branch with an open PR only
# `push` to those branches means a push to a feature branch with an open PR only
# triggers the `pull_request` run (not also a `push` run), so a PR gets a single
# run per push instead of two.
#
# On a push, a job that passes puts its dev shell in the PiFinder cache, so
# developers and later jobs download the shell and do not build it.
on:
push:
branches:
- main
- nixos
- release
pull_request:
permissions:
contents: read
jobs:
nox:
runs-on: ubuntu-latest
timeout-minutes: 20
# aarch64, like the PiFinder.
runs-on: ubuntu-24.04-arm
timeout-minutes: 30
defaults:
run:
working-directory: ./python
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: ./.github/actions/setup-nix
with:
enable-cache: true
# Same ruff pin as upstream main's noxfile, so shared files keep one style.
- name: Lint
run: uvx ruff@0.4.8 check --config "builtins=['_']" .
- name: Format check
run: uvx ruff@0.4.8 format --check .
- name: Sync environment
run: uv sync --frozen
attic-token: ${{ github.event_name == 'push' && secrets.ATTIC_TOKEN || '' }}
- name: Build dev shell
run: nix develop ..#default -c true
- name: Lint and format check
run: scripts/check.sh lint
- name: Type check
run: uv run mypy PiFinder
run: scripts/check.sh types
- name: Smoke tests
run: uv run pytest -m smoke
run: scripts/check.sh smoke
- name: Unit tests
run: uv run pytest -m unit
# The web tests need a Selenium grid, which CI does not have.
run: scripts/check.sh unit
- name: Integration tests
run: uv run pytest -m integration --ignore-glob='tests/test_web_*'
run: scripts/check.sh integration
- name: Push dev shell to the cache
if: github.event_name == 'push'
working-directory: .
run: .github/scripts/push_dev_shell.sh aarch64-linux

# Developer desktops are x86. This job puts the x86 dev shells in the cache
# after the checks pass, so a desktop downloads libcamera and the Python
# environment and does not build them.
dev-shell-x86:
needs: nox
if: github.event_name == 'push'
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-nix
with:
attic-token: ${{ secrets.ATTIC_TOKEN }}
- name: Push dev shells to the cache
run: |
.github/scripts/push_dev_shell.sh x86_64-linux
.github/scripts/push_dev_shell.sh x86_64-linux web
50 changes: 26 additions & 24 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,18 @@ jobs:
id: sha
run: echo "source_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

- name: Ensure nix is on PATH (self-hosted runner)
run: |
echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
echo "$HOME/.nix-profile/bin" >> "$GITHUB_PATH"
# The shared CI action and scripts come from the ref that runs this
# workflow, because the source to build can be another repo or branch.
- uses: actions/checkout@v4
with:
path: .ci
sparse-checkout: .github
persist-credentials: false

- name: Setup Attic caches (cache.pifinder.io)
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
run: |
nix profile install nixpkgs#attic-client
attic login pifinder https://cache.pifinder.io "$ATTIC_TOKEN"
attic use pifinder:pifinder
- uses: ./.ci/.github/actions/setup-nix
with:
attic-token: ${{ secrets.ATTIC_TOKEN }}
self-hosted: "true"

- name: Build and push release closure to Attic
id: push
Expand All @@ -94,6 +94,9 @@ jobs:
fi
echo "store_path=$STORE_PATH" >> "$GITHUB_OUTPUT"

- name: Push dev shell to the cache
run: .ci/.github/scripts/push_dev_shell.sh aarch64-linux

# Lean image: the system and an empty PiFinder_data.
- name: Build SD image
run: |
Expand Down Expand Up @@ -163,21 +166,17 @@ jobs:
id: sha
run: echo "source_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

- uses: DeterminateSystems/nix-installer-action@main
# The shared CI action and scripts come from the ref that runs this
# workflow, because the source to build can be another repo or branch.
- uses: actions/checkout@v4
with:
determinate: false
extra-conf: |
extra-system-features = big-parallel
extra-substituters = https://cache.pifinder.io/pifinder
extra-trusted-public-keys = pifinder:8UU/O3oLkaJHHUyqEcPGl+9F1m4MqDca39Ewl49jBmE=
path: .ci
sparse-checkout: .github
persist-credentials: false

- name: Setup Attic caches (cache.pifinder.io)
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
run: |
nix profile install nixpkgs#attic-client
attic login pifinder https://cache.pifinder.io "$ATTIC_TOKEN"
attic use pifinder:pifinder
- uses: ./.ci/.github/actions/setup-nix
with:
attic-token: ${{ secrets.ATTIC_TOKEN }}

- name: Build and push release closure to Attic
id: push
Expand All @@ -191,6 +190,9 @@ jobs:
fi
echo "store_path=$STORE_PATH" >> "$GITHUB_OUTPUT"

- name: Push dev shell to the cache
run: .ci/.github/scripts/push_dev_shell.sh aarch64-linux

# Lean image: the system and an empty PiFinder_data.
- name: Build SD image
run: |
Expand Down
Loading