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
45 changes: 39 additions & 6 deletions .github/workflows/cachix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,27 @@ name: Build and Push to cachix

on:
push:
branches:
- main
- develop
tags:
- "v*"

# Build pull requests before they are merged. Pull requests from forks and
# Dependabot run without secrets, so their builds only read from the cache.
pull_request:
branches:
- main
- develop

workflow_dispatch:

concurrency:
group: build-to-cachix
cancel-in-progress: false
# Pushes share one queue, so that a build reuses what the previous one pushed
# to the cache. Each pull request has a queue of its own, where a new push
# cancels the build of the previous one.
group: ${{ github.event_name == 'pull_request' && format('build-to-cachix-pr-{0}', github.event.pull_request.number) || 'build-to-cachix' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build-raspberrypi-kernel:
Expand All @@ -25,7 +41,7 @@ jobs:
- uses: ./.github/actions/setup-nix-action
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: "${{ secrets.CACHIX_CACHE_NAME }}"
name: nixos-raspberrypi
# # if you chose signing key for write access
# signingkey: "${{ secrets.cachix_signing_key }}"
# # if you chose api tokens for write access or if you have a private cache
Expand Down Expand Up @@ -68,7 +84,7 @@ jobs:
- uses: ./.github/actions/setup-nix-action
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: "${{ secrets.CACHIX_CACHE_NAME }}"
name: nixos-raspberrypi
# # if you chose signing key for write access
# signingkey: "${{ secrets.cachix_signing_key }}"
# # if you chose api tokens for write access or if you have a private cache
Expand All @@ -95,7 +111,7 @@ jobs:
- uses: ./.github/actions/setup-nix-action
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: "${{ secrets.CACHIX_CACHE_NAME }}"
name: nixos-raspberrypi
# # if you chose signing key for write access
# signingkey: "${{ secrets.cachix_signing_key }}"
# # if you chose api tokens for write access or if you have a private cache
Expand All @@ -121,9 +137,26 @@ jobs:
- uses: ./.github/actions/setup-nix-action
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with:
name: "${{ secrets.CACHIX_CACHE_NAME }}"
name: nixos-raspberrypi
# # if you chose signing key for write access
# signingkey: "${{ secrets.cachix_signing_key }}"
# # if you chose api tokens for write access or if you have a private cache
authtoken: ${{ secrets.cachix_auth_token }}
- run: nix --accept-flake-config build .#nixosConfigurations.rpi${{ matrix.version }}-installer.config.system.build.toplevel

# The one status check to require in the branch rules, instead of each of
# the builds above
all-builds:
name: All builds passed
if: always()
needs:
- build-raspberrypi-kernel
- build-vendor-packages-1
- build-vendor-packages-2
- build-installer-system

runs-on: ubuntu-latest

steps:
- if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')
run: exit 1
17 changes: 17 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,20 @@ jobs:

- name: Run formatter
run: nix fmt . -- --ci

flake-check:
name: Flake check
# aarch64, to run the bootloader tests too
runs-on: ubuntu-24.04-arm

steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install Nix
uses: ./.github/actions/setup-nix-action

# evaluates the configurations matrix and runs the bootloader tests,
# see `checks/`
- name: Run flake checks
run: nix --accept-flake-config flake check -L
28 changes: 28 additions & 0 deletions .github/workflows/update-flake-lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
# Optional GitHub App token: PRs opened with the default GITHUB_TOKEN
# don't trigger CI, PRs opened with an app token do.
# To enable: create a GitHub App with read and write access to "Contents"
# and "Pull requests", install it on the repository, then set the
# `BOT_APP_CLIENT_ID` variable and the `BOT_APP_PRIVATE_KEY` secret.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token
if: vars.BOT_APP_CLIENT_ID != ''
with:
client-id: ${{ vars.BOT_APP_CLIENT_ID }}
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: DeterminateSystems/determinate-nix-action@e847f25223456b3058e12f7fc9d777b6a6f25060 # v3.23.2
- uses: DeterminateSystems/update-flake-lock@da03c0f078bc4b2c37ee4f7e072d34bf8f188bb3 # v29
id: update
with:
token: ${{ steps.app-token.outputs.token || github.token }}
# Optional: merge the PR once its required checks pass.
# To enable: set the `BOT_AUTO_MERGE` variable to `true` and allow
# auto-merge in the repository settings, but only after requiring the CI
# checks on the target branch: without required checks there's nothing
# for auto-merge to wait for.
- name: Enable auto-merge
if: >-
vars.BOT_AUTO_MERGE == 'true' && steps.app-token.outputs.token != ''
&& (steps.update.outputs.pull-request-operation == 'created'
|| steps.update.outputs.pull-request-operation == 'updated')
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ steps.update.outputs.pull-request-number }}
run: gh pr merge --auto --merge --repo "$GITHUB_REPOSITORY" "$PR_NUMBER"
35 changes: 32 additions & 3 deletions .github/workflows/update-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,29 @@ jobs:
# args: "--version=branch=pios/trixie"

steps:
# Optional GitHub App token: PRs opened with the default GITHUB_TOKEN
# don't trigger CI, PRs opened with an app token do.
# To enable: create a GitHub App with read and write access to "Contents"
# and "Pull requests", install it on the repository, then set the
# `BOT_APP_CLIENT_ID` variable and the `BOT_APP_PRIVATE_KEY` secret.
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token
if: vars.BOT_APP_CLIENT_ID != ''
with:
client-id: ${{ vars.BOT_APP_CLIENT_ID }}
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ./.github/actions/setup-nix-action

- name: Run nix-update for ${{ matrix.attr }}
run: nix run nixpkgs#nix-update -- --flake ${{ matrix.args }} ${{ matrix.attr }}

- name: Create pull request
id: create-pr
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ steps.app-token.outputs.token || github.token }}
branch: update-packages/${{ matrix.attr }}
delete-branch: true
commit-message: "${{ matrix.attr }}: update via nix-update"
Expand All @@ -62,6 +76,21 @@ jobs:
Review the version/hash diff and let CI build before merging.

> [!NOTE]
> Because this PR is created with the default `GITHUB_TOKEN`, other
> workflows (e.g. CI) do not run on it automatically. Close/reopen the
> PR, push to its branch, or wire a PAT/GitHub App token to trigger them.
> If CI didn't run on this PR, it was opened with the default
> `GITHUB_TOKEN` (see `update-packages.yml` to set up an app token
> instead): close and reopen the PR, or push to its branch, to run CI.

# Optional: merge the PR once its required checks pass.
# To enable: set the `BOT_AUTO_MERGE` variable to `true` and allow
# auto-merge in the repository settings, but only after requiring the CI
# checks on the target branch: without required checks there's nothing
# for auto-merge to wait for.
- name: Enable auto-merge
if: >-
vars.BOT_AUTO_MERGE == 'true' && steps.app-token.outputs.token != ''
&& (steps.create-pr.outputs.pull-request-operation == 'created'
|| steps.create-pr.outputs.pull-request-operation == 'updated')
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
PR_NUMBER: ${{ steps.create-pr.outputs.pull-request-number }}
run: gh pr merge --auto --merge --repo "$GITHUB_REPOSITORY" "$PR_NUMBER"
94 changes: 94 additions & 0 deletions checks/bootloader.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Populates firmware and boot partitions with the configuration's bootloader
# the way `sd-image-raspberrypi.nix` does, but for a fake system generation, so
# that no kernel has to be built, then checks what ended up on them.
# The result is the populated partitions, handy to inspect when changing the
# bootloader:
# nix build .#checks.aarch64-linux.bootloader-rpi5-kernel && tree result
{
pkgs,
name,
nixos,
# device tree file the vendor firmware provides for the board
dtb,
}:

let
inherit (pkgs) lib;
inherit (nixos) config;
cfg = config.boot.loader.raspberry-pi;

fw = "${cfg.firmwarePackage}/share/raspberrypi/boot";
kernelParams = toString config.boot.kernelParams;

# only the parts of `system.build.toplevel` the installers read
generation = pkgs.runCommand "fake-generation-${name}" { } ''
mkdir -p $out/dtbs/broadcom $out/dtbs/overlays
echo kernel > $out/kernel
echo initrd > $out/initrd
echo init > $out/init
echo -n ${lib.escapeShellArg kernelParams} > $out/kernel-params
echo -n ${lib.escapeShellArg config.system.nixos.label} > $out/nixos-version
echo dtb > $out/dtbs/broadcom/${dtb}
echo overlay > $out/dtbs/overlays/test.dtbo
'';

cmdline = lib.escapeShellArg "${kernelParams} init=${generation}/init";

# what each bootloader is expected to install
expected = {
kernel = ''
hasLine $out/firmware/config.txt "os_prefix=${cfg.nixosGenerationsDir}/default/"
hasLine $out/firmware/config.txt "kernel=kernel.img"
hasLine $out/firmware/config.txt "initramfs initrd followkernel"

gen=$out/firmware/${cfg.nixosGenerationsDir}/default
sameFile ${generation}/kernel $gen/kernel.img
sameFile ${generation}/initrd $gen/initrd
hasLine $gen/cmdline.txt ${cmdline}
# device tree of the generation's kernel
sameFile ${generation}/dtbs/broadcom/${dtb} $gen/${dtb}
sameFile ${generation}/dtbs/overlays/test.dtbo $gen/overlays/test.dtbo
'';

kernelboot = ''
hasLine $out/firmware/config.txt "kernel=kernel.img"
hasLine $out/firmware/config.txt "initramfs initrd followkernel"

sameFile ${generation}/kernel $out/firmware/kernel.img
sameFile ${generation}/initrd $out/firmware/initrd
hasLine $out/firmware/cmdline.txt ${cmdline}
# device tree of the vendor firmware
sameFile ${fw}/${dtb} $out/firmware/${dtb}
hasOverlays $out/firmware/overlays
'';

uboot = ''
hasLine $out/firmware/config.txt "kernel=u-boot-rpi-arm64.bin"

sameFile ${cfg.ubootPackage}/u-boot.bin $out/firmware/u-boot-rpi-arm64.bin
# device tree of the vendor firmware
sameFile ${fw}/${dtb} $out/firmware/${dtb}
hasOverlays $out/firmware/overlays
grep -qF "init=${generation}/init" $out/boot/extlinux/extlinux.conf \
|| fail "extlinux.conf doesn't boot the generation"
'';
};
in
pkgs.runCommand "bootloader-${name}" { } ''
fail() { echo "FAIL: $*" >&2; exit 1; }
sameFile() { cmp -s "$1" "$2" || fail "$2 isn't a copy of $1"; }
hasLine() { grep -qxF -- "$2" "$1" || fail "$1 has no line '$2'"; }
hasOverlays() { [ -n "$(ls -A "$1")" ] || fail "no device tree overlays in $1"; }

mkdir -p $out/firmware $out/boot
${cfg.firmwarePopulateCmd} -c ${generation} -f $out/firmware
${cfg.bootPopulateCmd} -c ${generation} -b $out/boot

# boot code and config.txt, whatever the bootloader
sameFile ${cfg.configTxtPackage} $out/firmware/config.txt
for f in ${fw}/bootcode.bin ${fw}/start*.elf ${fw}/fixup*.dat; do
sameFile "$f" "$out/firmware/$(basename "$f")"
done

${expected.${cfg.bootloader}}
''
Loading