From e165202075a4b5bd6d5f462aa67a93aace766604 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:20:51 +0200 Subject: [PATCH 01/24] feat(ci): Gitea flow is build -> test (boot loader test per loader, parallel) -> release; drop upstream build.yml iso-2-gitea-build.yml now has three jobs. The ISO goes between them as an artifact; the test job runs steamify-cachyos-dev's vmbootloadertest.sh --install for limine, systemd-boot and grub (needs /dev/kvm on the runner, fails at once with a reason without it); the release is only made when every test passed. --- .github/workflows/build.yml | 141 ---------------------- .github/workflows/iso-2-gitea-build.yml | 148 ++++++++++++++++++++++-- AGENTS.md | 8 +- 3 files changed, 143 insertions(+), 154 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 059be29..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: Desktop ISO -on: - push: - branches: - - master - pull_request: - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - # CachyOS's plain ISO and its quicktest matrix: only in CachyOS's own repo, not in this fork - # (the Steamify ISO is iso-2-gitea-build.yml). - if: github.repository == 'CachyOS/CachyOS-Live-ISO' - runs-on: ubuntu-latest - container: - image: archlinux:base-devel - options: --privileged - name: Build - outputs: - builddate: ${{ steps.date.outputs.builddate }} - steps: - - name: Get build date - id: date - run: | - echo "builddate=$(date +'%y%m%d')" >> $GITHUB_OUTPUT - - - name: Clone CachyOS-Live-ISO - id: clone - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Add CachyOS keyring - id: keyring - run: | - pacman-key --init - pacman-key --recv-keys F3B607488DB35A47 --keyserver keyserver.ubuntu.com - pacman-key --lsign-key F3B607488DB35A47 - - sed -i '/^\[core\]$/i[cachyos]\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n' /etc/pacman.conf - - - name: Install dependencies - id: dependencies - run: | - sudo pacman -Syu --noconfirm archiso cachyos-keyring mkinitcpio-archiso squashfs-tools grub - - - name: Create build user - id: user-archiso - run: | - useradd builder -m - echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers - chmod -R a+rw . - - - name: Build ISO (${{ steps.date.outputs.builddate }}) - id: build - run: | - sudo -H -E -u builder ./buildiso.sh - - - name: Upload ISO to artifacts - id: upload - uses: actions/upload-artifact@v4 - with: - name: cachyos-desktop-linux-${{ steps.date.outputs.builddate }} - path: out/desktop/* - quicktest: - name: Testing (${{ matrix.bootloader }} / ${{ matrix.filesystem }}) - runs-on: ubuntu-latest - needs: build - container: - image: archlinux:base-devel - options: --privileged - strategy: - fail-fast: false - max-parallel: 4 - matrix: - bootloader: [grub, systemd-boot, refind, limine] - filesystem: [btrfs, xfs, ext4, f2fs, zfs] - steps: - - name: Clone CachyOS-Live-ISO - id: clone - uses: actions/checkout@v6 - - - name: Install dependencies - id: dependencies - run: | - pacman -Syu --noconfirm git ffmpeg imagemagick tesseract-data-eng qemu-desktop - - - name: Create build user - id: user - run: | - useradd builder -m - echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers - chmod -R a+rw . - - - name: Build quickemu - id: quickemu - run: | - sudo -u builder git clone https://aur.archlinux.org/quickemu.git - cd quickemu - sudo -H -E -u builder makepkg --syncdeps --noconfirm - pacman -U --noconfirm quickemu*.pkg.tar.zst - cd .. - - - name: Clone quicktest - id: clone-quicktest - uses: actions/checkout@v6 - with: - repository: 'quickemu-project/quicktest' - path: 'quicktest' - - - name: Download ISO - id: download - uses: actions/download-artifact@v4 - with: - path: machines/cachyos-dailylive - merge-multiple: true - - - name: Run quicktest - id: quicktest - run: | - ./quicktest/quicktest test_install_calamares cachyos dailylive - env: - QT_NOTIFY: "false" - QT_OPEN_RESULTS: "false" - QT_QUICKGET_SKIP: "true" - QT_TESTCASES_DIR: "./testcases" - QUICKEMU_DISPLAY: "none" - QUICKEMU_VM_DIR: "./machines" - TEST_BOOTLOADER: "${{ matrix.bootloader }}" - TEST_FILESYSTEM: "${{ matrix.filesystem }}" - - - name: Upload results to artifacts - id: upload-results - if: always() - uses: actions/upload-artifact@v4 - with: - name: cachyos-desktop-linux-results-${{needs.build.outputs.builddate}}-${{ matrix.bootloader }}-${{ matrix.filesystem }} - path: results/* diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index edae835..75bb992 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -4,9 +4,11 @@ # checksums and package list to the mirror's release for that tag. The tag names the Steamify version and # the time: v-- (master) or v-dev.<...> (feat/steamify, a pre-release); # the ISO gets exactly that Steamify release, and its label the same moment. GitHub skips it. -# The runner needs privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's +# Three jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in +# parallel when the runner's capacity allows) -> release, only when every test passed. +# The runner needs /dev/kvm, privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's # [repository.release] FILE_MAX_SIZE must allow the ISO (default 2 GB). -name: ISO 2/2 · Build and publish (Gitea) +name: ISO 2/2 · Build, test and publish (Gitea) on: push: @@ -18,7 +20,8 @@ concurrency: cancel-in-progress: true jobs: - iso: + build: + name: Build the ISO if: github.server_url != 'https://github.com' runs-on: ubuntu-latest container: @@ -27,6 +30,8 @@ jobs: defaults: run: shell: bash + outputs: + steamify: ${{ steps.tag.outputs.steamify }} steps: - name: Tools run: | @@ -34,6 +39,132 @@ jobs: # nodejs: the actions below run in this container pacman -Syu --noconfirm --needed archiso mkinitcpio-archiso git squashfs-tools grub sudo nodejs curl jq + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Version and time from the tag + id: tag + run: | + tag="${{ github.ref_name }}" + [[ "$tag" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)-(dev\.)?([0-9]{4})\.([0-9]{2})\.([0-9]{2})-([0-9]{4})$ ]] || + { echo "::error::$tag is not a Steamify ISO release tag (v-[dev.]-)"; exit 1; } + m=("${BASH_REMATCH[@]}") + { + echo "STEAMIFY_VERSION=${m[1]}" + # One moment for the ISO's label (profiledef.sh) and the release's name: the tag's (UTC). + echo "STEAMIFY_BUILD_STAMP=${m[3]}${m[4]}${m[5]}_${m[6]}" + echo "ISO_PRERELEASE=$([ -n "${m[2]}" ] && echo true || echo false)" + # The ISO's file name: the tag without its v (profiledef.sh). + echo "STEAMIFY_ISO_VERSION=${tag#v}" + } >> "$GITHUB_ENV" + + echo "steamify=${m[1]}" >> "$GITHUB_OUTPUT" + + - name: Steamify on the ISO (the version the tag names) + run: ./steamify-prepare.sh + + - name: Build + run: | + ./build-live-modules.sh + ./build-calamares-modules.sh + ./buildiso.sh -p desktop -w || ./buildiso.sh -p desktop -c -w + + + - name: Keep the ISO for the tests and the release + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: iso + path: | + out/desktop/*.iso + out/desktop/*.iso.sha256 + out/desktop/*.iso.sha1 + out/desktop/*.pkgs.txt + retention-days: 3 + + test: + name: Test ${{ matrix.loader }} + needs: build + runs-on: ubuntu-latest + timeout-minutes: 90 + container: + image: docker.io/cachyos/cachyos:latest + options: --privileged + strategy: + fail-fast: false + matrix: + loader: [limine, systemd-boot, grub] + defaults: + run: + shell: bash + steps: + - name: Tools and KVM + run: | + pacman-key --init && pacman-key --populate + # nodejs: the actions below run in this container + pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git nodejs sudo + # Fail at once, with a reason, when the runner cannot run a VM with KVM. + [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } + nproc; free -g | sed -n 2p; df -h . | tail -n 1 + + # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), + # steamify-cachyos at the Steamify version the ISO has (shared into the VM, 9p `repo`). + - uses: actions/checkout@v4 + with: + repository: theupriser/steamify-cachyos-dev + path: steamify-cachyos-dev + - uses: actions/checkout@v4 + with: + repository: theupriser/steamify-cachyos + ref: v${{ needs.build.outputs.steamify }} + path: steamify-cachyos + + - uses: christopherhx/gitea-download-artifact@v4 + with: + name: iso + path: iso + + - name: Boot loader test (${{ matrix.loader }}) + env: + CI: "1" + VM_TIMEZONE: UTC + VM_ISO_DIR: ${{ github.workspace }}/iso + run: | + mkdir -p ~/.ssh ~/vms/pkg-cache + ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 + iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" + cd steamify-cachyos-dev + VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install + + - name: Logs + if: always() + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: test-${{ matrix.loader }} + path: | + /root/vms/bl-${{ matrix.loader }}.test.log + /root/vms/bl-${{ matrix.loader }}/vm.log + retention-days: 7 + if-no-files-found: ignore + + release: + name: Release + needs: [build, test] + runs-on: ubuntu-latest + container: + image: docker.io/cachyos/cachyos:latest + defaults: + run: + shell: bash + steps: + - name: Tools + run: | + pacman-key --init && pacman-key --populate + # nodejs: the actions below run in this container + pacman -Syu --noconfirm --needed git nodejs curl jq + + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -53,14 +184,11 @@ jobs: echo "STEAMIFY_ISO_VERSION=${tag#v}" } >> "$GITHUB_ENV" - - name: Steamify on the ISO (the version the tag names) - run: ./steamify-prepare.sh - - name: Build - run: | - ./build-live-modules.sh - ./build-calamares-modules.sh - ./buildiso.sh -p desktop -w || ./buildiso.sh -p desktop -c -w + - uses: christopherhx/gitea-download-artifact@v4 + with: + name: iso + path: out/desktop - name: Release name and notes id: rel diff --git a/AGENTS.md b/AGENTS.md index 3724971..4a112fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -118,8 +118,10 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. release, whose `bundle.yml` needs the secret `ISO_DISPATCH_TOKEN`) names the release: the Steamify version plus GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. -- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) builds the ISO for that - tag and attaches it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` +- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that + tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install`, one job per boot loader, + parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and + steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label (`STEAMIFY_BUILD_STAMP`), boot menu and `/etc/steammachine-iso-build`. The build reads no clock; without a tag everything says `local`. @@ -129,4 +131,4 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. GitHub doesn't have, and the release with them. GitHub releases can't hold the ISO (2 GB per file). - Gitea needs `[repository.release] FILE_MAX_SIZE` above the ISO (413 otherwise) and the runner `container: privileged: true` (archiso mounts `/proc`); the workflow's `--privileged` option is ignored. -- CachyOS's own `Desktop ISO` workflow (`build.yml`) only runs in `CachyOS/CachyOS-Live-ISO`. +- CachyOS's own `Desktop ISO` workflow (`build.yml`) is removed here; the test job of iso-2-gitea-build.yml replaces it. From edb58b5ba9d1290e55107336ffeed6b9d70e115a Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:21:08 +0200 Subject: [PATCH 02/24] ci: boot loader tests two at a time (8 GB VMs, ~20 GB of RAM) --- .github/workflows/iso-2-gitea-build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 75bb992..b218355 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -93,6 +93,9 @@ jobs: options: --privileged strategy: fail-fast: false + # The runner has ~20 GB of RAM for this: an install VM takes 8 GB, so two at a time (needs the + # runner's `capacity: 2`; with 1 they run one after the other). + max-parallel: 2 matrix: loader: [limine, systemd-boot, grub] defaults: @@ -129,6 +132,7 @@ jobs: env: CI: "1" VM_TIMEZONE: UTC + VM_MEM: 8G VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache From 8a98315bd5b8dcaf336591884bf195c817aff83d Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:24:06 +0200 Subject: [PATCH 03/24] ci: boot loader test VMs with 3 vCPUs each (the runner has 8 threads) --- .github/workflows/iso-2-gitea-build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index b218355..855a8e6 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -133,6 +133,8 @@ jobs: CI: "1" VM_TIMEZONE: UTC VM_MEM: 8G + # The runner is 4 cores / 8 threads: two VMs with 3 vCPUs leave 2 threads for the host and the runner. + VM_CPUS: "3" VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache From 29ec7d2cdee6e51399c9a18b142abf7d075dc3d2 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:24:27 +0200 Subject: [PATCH 04/24] ci: boot loader test VMs keep their own RAM defaults (8 GB to install, 4 GB to test) --- .github/workflows/iso-2-gitea-build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 855a8e6..c5ac5f7 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -93,7 +93,7 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner has ~20 GB of RAM for this: an install VM takes 8 GB, so two at a time (needs the + # The runner has ~20 GB of RAM for this: an install VM peaks at 8 GB (4 GB once installed), so two at a time (needs the # runner's `capacity: 2`; with 1 they run one after the other). max-parallel: 2 matrix: @@ -132,7 +132,6 @@ jobs: env: CI: "1" VM_TIMEZONE: UTC - VM_MEM: 8G # The runner is 4 cores / 8 threads: two VMs with 3 vCPUs leave 2 threads for the host and the runner. VM_CPUS: "3" VM_ISO_DIR: ${{ github.workspace }}/iso From 028416b760afd423e531cb9e7054f258022f774d Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:25:14 +0200 Subject: [PATCH 05/24] ci: 6 GB for the installer VM (VM_INSTALL_MEM) --- .github/workflows/iso-2-gitea-build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index c5ac5f7..32d94b8 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -93,7 +93,7 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner has ~20 GB of RAM for this: an install VM peaks at 8 GB (4 GB once installed), so two at a time (needs the + # The runner has ~20 GB of RAM for this: an install VM peaks at 6 GB (4 GB once installed), so two at a time (needs the # runner's `capacity: 2`; with 1 they run one after the other). max-parallel: 2 matrix: @@ -134,6 +134,8 @@ jobs: VM_TIMEZONE: UTC # The runner is 4 cores / 8 threads: two VMs with 3 vCPUs leave 2 threads for the host and the runner. VM_CPUS: "3" + # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB was the local default + VM_INSTALL_MEM: 6G VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache From d002c7d332ed85e5c456386f25172540469fe490 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:25:28 +0200 Subject: [PATCH 06/24] ci: lean test VMs: 2 vCPUs and 4 GB each, also to install --- .github/workflows/iso-2-gitea-build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 32d94b8..c0a3f24 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -93,7 +93,7 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner has ~20 GB of RAM for this: an install VM peaks at 6 GB (4 GB once installed), so two at a time (needs the + # The runner has ~20 GB of RAM for this: an install VM takes 4 GB (4 GB once installed too), so two at a time (needs the # runner's `capacity: 2`; with 1 they run one after the other). max-parallel: 2 matrix: @@ -132,10 +132,10 @@ jobs: env: CI: "1" VM_TIMEZONE: UTC - # The runner is 4 cores / 8 threads: two VMs with 3 vCPUs leave 2 threads for the host and the runner. - VM_CPUS: "3" - # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB was the local default - VM_INSTALL_MEM: 6G + # The runner is 4 cores / 8 threads: two VMs with 2 vCPUs leave 4 threads for the host and the runner. + VM_CPUS: "2" + # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB is the local default, this is the lean end: raise it if an install dies out of memory + VM_INSTALL_MEM: 4G VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache From cfacfb2493661f1b78e37886a33b46dd86e06d21 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:25:53 +0200 Subject: [PATCH 07/24] ci: 6 GB to install, 4 GB to test, 2 vCPUs: lean with headroom --- .github/workflows/iso-2-gitea-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index c0a3f24..94dd57c 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -93,7 +93,7 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner has ~20 GB of RAM for this: an install VM takes 4 GB (4 GB once installed too), so two at a time (needs the + # The runner has ~20 GB of RAM for this: an install VM takes 6 GB (4 GB once installed), so two at a time (needs the # runner's `capacity: 2`; with 1 they run one after the other). max-parallel: 2 matrix: @@ -134,8 +134,8 @@ jobs: VM_TIMEZONE: UTC # The runner is 4 cores / 8 threads: two VMs with 2 vCPUs leave 4 threads for the host and the runner. VM_CPUS: "2" - # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB is the local default, this is the lean end: raise it if an install dies out of memory - VM_INSTALL_MEM: 4G + # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB is the local default, lean with headroom: lower it only after a run shows the install stays well under + VM_INSTALL_MEM: 6G VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache From 779ee972cf4baf9512c2031ee99ff99cdd669f52 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:27:34 +0200 Subject: [PATCH 08/24] ci: a suites stage after the boot loader tests (vmtest.sh: cli, menu, hw, installer, toggles on a plain CachyOS VM) --- .github/workflows/iso-2-gitea-build.yml | 81 ++++++++++++++++++++++++- AGENTS.md | 4 +- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 94dd57c..872f7aa 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -4,8 +4,8 @@ # checksums and package list to the mirror's release for that tag. The tag names the Steamify version and # the time: v-- (master) or v-dev.<...> (feat/steamify, a pre-release); # the ISO gets exactly that Steamify release, and its label the same moment. GitHub skips it. -# Three jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in -# parallel when the runner's capacity allows) -> release, only when every test passed. +# Four jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in +# parallel when the runner's capacity allows) -> the vmtest.sh suites -> release, only when every test passed. # The runner needs /dev/kvm, privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's # [repository.release] FILE_MAX_SIZE must allow the ISO (default 2 GB). name: ISO 2/2 · Build, test and publish (Gitea) @@ -155,9 +155,84 @@ jobs: retention-days: 7 if-no-files-found: ignore + suites: + name: Test suites (vmtest.sh) + # After the boot loader tests, not next to them: the runner is small, and a broken ISO needs no suites. + needs: [build, test] + runs-on: ubuntu-latest + timeout-minutes: 150 + container: + image: docker.io/cachyos/cachyos:latest + options: --privileged + defaults: + run: + shell: bash + steps: + - name: Tools and KVM + run: | + pacman-key --init && pacman-key --populate + # nodejs: the actions below run in this container + pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git nodejs sudo + # Fail at once, with a reason, when the runner cannot run a VM with KVM. + [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } + nproc; free -g | sed -n 2p; df -h . | tail -n 1 + + # vmtest.sh wants its repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at the + # ISO's Steamify version (shared into the VMs) and this repository (which boot loaders the ISO advertises). + - uses: actions/checkout@v4 + with: + path: steamify-cachyos-live-iso + - uses: actions/checkout@v4 + with: + repository: theupriser/steamify-cachyos-dev + path: steamify-cachyos-dev + - uses: actions/checkout@v4 + with: + repository: theupriser/steamify-cachyos + ref: v${{ needs.build.outputs.steamify }} + path: steamify-cachyos + + # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; + # every block then starts from a fresh overlay of that VM. + - name: Plain CachyOS VM + env: + CI: "1" + VM_TIMEZONE: UTC + VM_CPUS: "2" + VM_INSTALL_MEM: 6G + VM_STEAMIFY: skip + run: | + mkdir -p ~/.ssh ~/vms/pkg-cache + ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 + cd steamify-cachyos-dev + ./get-iso.sh + VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso cachyos.iso + rm -f cachyos.iso + + # Two suites at a time, 4 GB and 2 vCPUs each (vmsuite.sh). + - name: vmtest.sh (every suite) + env: + CI: "1" + VM_CPUS: "2" + MAX_PARALLEL: "2" + run: | + cd steamify-cachyos-dev + scripts/vmtest.sh cli menu hw installer toggles + + - name: Logs + if: always() + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: test-suites + path: | + /root/vms/last-test.txt + /root/vms/run-*.log + retention-days: 7 + if-no-files-found: ignore + release: name: Release - needs: [build, test] + needs: [build, test, suites] runs-on: ubuntu-latest container: image: docker.io/cachyos/cachyos:latest diff --git a/AGENTS.md b/AGENTS.md index 4a112fb..90e052f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -118,10 +118,10 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. release, whose `bundle.yml` needs the secret `ISO_DISPATCH_TOKEN`) names the release: the Steamify version plus GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. -- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that +- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs four jobs for that tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install`, one job per boot loader, parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and - steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` + steamify-cachyos at the ISO's version from the mirror), then, after those, the suites (`scripts/vmtest.sh cli menu hw installer toggles` on a plain CachyOS VM installed from the newest CachyOS ISO, two at a time), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label (`STEAMIFY_BUILD_STAMP`), boot menu and `/etc/steammachine-iso-build`. The build reads no clock; without a tag everything says `local`. From a74500b692a5b456b4f104fdc97e20a540cc99ca Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:28:27 +0200 Subject: [PATCH 09/24] ci: a new run of the ISO workflow cancels the running one (one concurrency group, not per tag) --- .github/workflows/iso-2-gitea-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 872f7aa..9393992 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -15,8 +15,9 @@ on: tags: ['v*'] workflow_dispatch: +# One run at a time for the whole workflow (not per tag): a new run stops the running one and takes over. concurrency: - group: steamify-iso-${{ github.ref }} + group: steamify-iso cancel-in-progress: true jobs: From af30018bd90935be8683116660e17757c83edee5 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:29:41 +0200 Subject: [PATCH 10/24] ci: cache pacman packages (build, test, suites), the VMs' packages and the CachyOS ISO --- .github/workflows/iso-2-gitea-build.yml | 79 +++++++++++++++++++++---- AGENTS.md | 1 + 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 9393992..6351930 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -34,11 +34,19 @@ jobs: outputs: steamify: ${{ steps.tag.outputs.steamify }} steps: - - name: Tools + # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. + - name: Node and git run: | pacman-key --init && pacman-key --populate - # nodejs: the actions below run in this container - pacman -Syu --noconfirm --needed archiso mkinitcpio-archiso git squashfs-tools grub sudo nodejs curl jq + pacman -Syu --noconfirm --needed nodejs git + - name: Cache - pacman packages + uses: actions/cache@v4 + with: + path: /var/cache/pacman/pkg + key: pacman-build-${{ github.run_id }} + restore-keys: pacman-build- + - name: Tools + run: pacman -S --noconfirm --needed archiso mkinitcpio-archiso squashfs-tools grub sudo curl jq - uses: actions/checkout@v4 @@ -103,11 +111,29 @@ jobs: run: shell: bash steps: - - name: Tools and KVM + # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. + - name: Node and git run: | pacman-key --init && pacman-key --populate - # nodejs: the actions below run in this container - pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git nodejs sudo + pacman -Syu --noconfirm --needed nodejs git + - name: Cache - pacman packages + uses: actions/cache@v4 + with: + path: /var/cache/pacman/pkg + key: pacman-test-${{ github.run_id }} + restore-keys: pacman-test- + # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. + - name: Cache - the VMs' packages + uses: actions/cache@v4 + with: + path: /root/vms/pkg-cache + key: vmpkg-${{ needs.build.outputs.steamify }}-${{ github.run_id }} + restore-keys: | + vmpkg-${{ needs.build.outputs.steamify }}- + vmpkg- + - name: Tools and KVM + run: | + pacman -S --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo # Fail at once, with a reason, when the runner cannot run a VM with KVM. [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } nproc; free -g | sed -n 2p; df -h . | tail -n 1 @@ -169,11 +195,29 @@ jobs: run: shell: bash steps: - - name: Tools and KVM + # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. + - name: Node and git run: | pacman-key --init && pacman-key --populate - # nodejs: the actions below run in this container - pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git nodejs sudo + pacman -Syu --noconfirm --needed nodejs git + - name: Cache - pacman packages + uses: actions/cache@v4 + with: + path: /var/cache/pacman/pkg + key: pacman-test-${{ github.run_id }} + restore-keys: pacman-test- + # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. + - name: Cache - the VMs' packages + uses: actions/cache@v4 + with: + path: /root/vms/pkg-cache + key: vmpkg-${{ needs.build.outputs.steamify }}-${{ github.run_id }} + restore-keys: | + vmpkg-${{ needs.build.outputs.steamify }}- + vmpkg- + - name: Tools and KVM + run: | + pacman -S --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo # Fail at once, with a reason, when the runner cannot run a VM with KVM. [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } nproc; free -g | sed -n 2p; df -h . | tail -n 1 @@ -195,6 +239,20 @@ jobs: # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; # every block then starts from a fresh overlay of that VM. + # The CachyOS ISO (~3 GB) is cached per release (the release get-iso.sh would download). + - name: CachyOS release + id: cachyos + run: | + rel="$(curl -fsL https://cachyos.org/download/ | grep -oE 'cachyos-desktop-linux-[0-9]+' | head -n 1)" + echo "release=${rel:?no CachyOS release found}" >> "$GITHUB_OUTPUT" + - name: Cache - the CachyOS ISO + uses: actions/cache@v4 + with: + path: | + steamify-cachyos-dev/cachyos.iso + steamify-cachyos-dev/cachyos.iso.version + key: cachyos-iso-${{ steps.cachyos.outputs.release }} + - name: Plain CachyOS VM env: CI: "1" @@ -206,9 +264,8 @@ jobs: mkdir -p ~/.ssh ~/vms/pkg-cache ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 cd steamify-cachyos-dev - ./get-iso.sh + ./get-iso.sh # does nothing when the cached ISO is the current release VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso cachyos.iso - rm -f cachyos.iso # Two suites at a time, 4 GB and 2 vCPUs each (vmsuite.sh). - name: vmtest.sh (every suite) diff --git a/AGENTS.md b/AGENTS.md index 90e052f..a9d05a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -131,4 +131,5 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. GitHub doesn't have, and the release with them. GitHub releases can't hold the ISO (2 GB per file). - Gitea needs `[repository.release] FILE_MAX_SIZE` above the ISO (413 otherwise) and the runner `container: privileged: true` (archiso mounts `/proc`); the workflow's `--privileged` option is ignored. +- Caches (`actions/cache`, the runner's cache server): pacman's package cache per job kind (build, test), the VMs' packages (`VM_CACHE`, `~/vms/pkg-cache`) and the CachyOS ISO for the suites, per release. Each job first installs only node and git, restores the caches, then installs the rest. - CachyOS's own `Desktop ISO` workflow (`build.yml`) is removed here; the test job of iso-2-gitea-build.yml replaces it. From 2b72d90d30842697f978c08d9984da20e4a0e92a Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:38:04 +0200 Subject: [PATCH 11/24] ci: cache keys per ISO week instead of per run (no new multi-GB entry on every run) --- .github/workflows/iso-2-gitea-build.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 6351930..607ec5c 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -36,14 +36,17 @@ jobs: steps: # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. - name: Node and git + id: node run: | pacman-key --init && pacman-key --populate pacman -Syu --noconfirm --needed nodejs git + # The caches' keys: one entry per ISO week (an exact hit saves nothing, a new week restores the old one and saves once). + echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" - name: Cache - pacman packages uses: actions/cache@v4 with: path: /var/cache/pacman/pkg - key: pacman-build-${{ github.run_id }} + key: pacman-build-${{ steps.node.outputs.week }} restore-keys: pacman-build- - name: Tools run: pacman -S --noconfirm --needed archiso mkinitcpio-archiso squashfs-tools grub sudo curl jq @@ -113,21 +116,24 @@ jobs: steps: # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. - name: Node and git + id: node run: | pacman-key --init && pacman-key --populate pacman -Syu --noconfirm --needed nodejs git + # The caches' keys: one entry per ISO week (an exact hit saves nothing, a new week restores the old one and saves once). + echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" - name: Cache - pacman packages uses: actions/cache@v4 with: path: /var/cache/pacman/pkg - key: pacman-test-${{ github.run_id }} + key: pacman-test-${{ steps.node.outputs.week }} restore-keys: pacman-test- # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. - name: Cache - the VMs' packages uses: actions/cache@v4 with: path: /root/vms/pkg-cache - key: vmpkg-${{ needs.build.outputs.steamify }}-${{ github.run_id }} + key: vmpkg-${{ needs.build.outputs.steamify }}-${{ steps.node.outputs.week }} restore-keys: | vmpkg-${{ needs.build.outputs.steamify }}- vmpkg- @@ -197,21 +203,24 @@ jobs: steps: # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. - name: Node and git + id: node run: | pacman-key --init && pacman-key --populate pacman -Syu --noconfirm --needed nodejs git + # The caches' keys: one entry per ISO week (an exact hit saves nothing, a new week restores the old one and saves once). + echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" - name: Cache - pacman packages uses: actions/cache@v4 with: path: /var/cache/pacman/pkg - key: pacman-test-${{ github.run_id }} + key: pacman-test-${{ steps.node.outputs.week }} restore-keys: pacman-test- # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. - name: Cache - the VMs' packages uses: actions/cache@v4 with: path: /root/vms/pkg-cache - key: vmpkg-${{ needs.build.outputs.steamify }}-${{ github.run_id }} + key: vmpkg-${{ needs.build.outputs.steamify }}-${{ steps.node.outputs.week }} restore-keys: | vmpkg-${{ needs.build.outputs.steamify }}- vmpkg- From 448e2a5d799a93a35b3b91a25dee9959977903bc Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:43:07 +0200 Subject: [PATCH 12/24] ci: the CachyOS ISO cache gets an entry per workflow run --- .github/workflows/iso-2-gitea-build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 607ec5c..9fd5c1c 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -248,7 +248,8 @@ jobs: # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; # every block then starts from a fresh overlay of that VM. - # The CachyOS ISO (~3 GB) is cached per release (the release get-iso.sh would download). + # The CachyOS ISO (~3 GB): one cache entry per workflow run; it starts from the newest earlier entry of the same + # release (get-iso.sh replaces it when CachyOS has a newer one). - name: CachyOS release id: cachyos run: | @@ -260,7 +261,8 @@ jobs: path: | steamify-cachyos-dev/cachyos.iso steamify-cachyos-dev/cachyos.iso.version - key: cachyos-iso-${{ steps.cachyos.outputs.release }} + key: cachyos-iso-${{ steps.cachyos.outputs.release }}-${{ github.run_id }} + restore-keys: cachyos-iso- - name: Plain CachyOS VM env: From 34e3d2ae4a99875a811ed28eaa38aca6827cd11e Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:43:23 +0200 Subject: [PATCH 13/24] ci: the CachyOS ISO cache per CachyOS release again (the Steamify ISO of the run goes to the jobs as an artifact) --- .github/workflows/iso-2-gitea-build.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 9fd5c1c..557f18f 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -248,8 +248,8 @@ jobs: # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; # every block then starts from a fresh overlay of that VM. - # The CachyOS ISO (~3 GB): one cache entry per workflow run; it starts from the newest earlier entry of the same - # release (get-iso.sh replaces it when CachyOS has a newer one). + # The CachyOS ISO (~3 GB), only the base of the suites' plain VM (not the Steamify ISO this run builds: that one + # goes to the other jobs as the artifact `iso`): cached per CachyOS release. - name: CachyOS release id: cachyos run: | @@ -261,8 +261,7 @@ jobs: path: | steamify-cachyos-dev/cachyos.iso steamify-cachyos-dev/cachyos.iso.version - key: cachyos-iso-${{ steps.cachyos.outputs.release }}-${{ github.run_id }} - restore-keys: cachyos-iso- + key: cachyos-iso-${{ steps.cachyos.outputs.release }} - name: Plain CachyOS VM env: From 85205dd614e1ad1d435dad7ffe5b2ee63c7a7e61 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:46:11 +0200 Subject: [PATCH 14/24] ci: the suites' base VM is installed from the ISO this run built (Steamify step skipped); no CachyOS ISO download or cache --- .github/workflows/iso-2-gitea-build.yml | 26 ++++++++++--------------- AGENTS.md | 4 ++-- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 557f18f..4a97d87 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -248,22 +248,16 @@ jobs: # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; # every block then starts from a fresh overlay of that VM. - # The CachyOS ISO (~3 GB), only the base of the suites' plain VM (not the Steamify ISO this run builds: that one - # goes to the other jobs as the artifact `iso`): cached per CachyOS release. - - name: CachyOS release - id: cachyos - run: | - rel="$(curl -fsL https://cachyos.org/download/ | grep -oE 'cachyos-desktop-linux-[0-9]+' | head -n 1)" - echo "release=${rel:?no CachyOS release found}" >> "$GITHUB_OUTPUT" - - name: Cache - the CachyOS ISO - uses: actions/cache@v4 + - uses: christopherhx/gitea-download-artifact@v4 with: - path: | - steamify-cachyos-dev/cachyos.iso - steamify-cachyos-dev/cachyos.iso.version - key: cachyos-iso-${{ steps.cachyos.outputs.release }} + name: iso + path: iso - - name: Plain CachyOS VM + # The suites test steamify.sh from a plain system, so the base VM is installed from the ISO this run built + # with its Steamify step skipped (VM_STEAMIFY=skip): the ISO's installer, kernels, packages and boot loader + # are tested, every block then starts from a fresh overlay of that VM. (The boot loader jobs test the + # ISO with Steamify installed.) + - name: Base VM from the new ISO env: CI: "1" VM_TIMEZONE: UTC @@ -273,9 +267,9 @@ jobs: run: | mkdir -p ~/.ssh ~/vms/pkg-cache ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 + iso="$(ls "$GITHUB_WORKSPACE"/iso/*.iso | head -n 1)" cd steamify-cachyos-dev - ./get-iso.sh # does nothing when the cached ISO is the current release - VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso cachyos.iso + VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso "$iso" # Two suites at a time, 4 GB and 2 vCPUs each (vmsuite.sh). - name: vmtest.sh (every suite) diff --git a/AGENTS.md b/AGENTS.md index a9d05a9..9e2c4ad 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -121,7 +121,7 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. - `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs four jobs for that tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install`, one job per boot loader, parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and - steamify-cachyos at the ISO's version from the mirror), then, after those, the suites (`scripts/vmtest.sh cli menu hw installer toggles` on a plain CachyOS VM installed from the newest CachyOS ISO, two at a time), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` + steamify-cachyos at the ISO's version from the mirror), then, after those, the suites (`scripts/vmtest.sh cli menu hw installer toggles` on a plain VM installed from the new ISO with `VM_STEAMIFY=skip`, two at a time), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label (`STEAMIFY_BUILD_STAMP`), boot menu and `/etc/steammachine-iso-build`. The build reads no clock; without a tag everything says `local`. @@ -131,5 +131,5 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. GitHub doesn't have, and the release with them. GitHub releases can't hold the ISO (2 GB per file). - Gitea needs `[repository.release] FILE_MAX_SIZE` above the ISO (413 otherwise) and the runner `container: privileged: true` (archiso mounts `/proc`); the workflow's `--privileged` option is ignored. -- Caches (`actions/cache`, the runner's cache server): pacman's package cache per job kind (build, test), the VMs' packages (`VM_CACHE`, `~/vms/pkg-cache`) and the CachyOS ISO for the suites, per release. Each job first installs only node and git, restores the caches, then installs the rest. +- Caches (`actions/cache`, the runner's cache server): pacman's package cache per job kind (build, test) and the VMs' packages (`VM_CACHE`, `~/vms/pkg-cache`), keys per ISO week. Each job first installs only node and git, restores the caches, then installs the rest. - CachyOS's own `Desktop ISO` workflow (`build.yml`) is removed here; the test job of iso-2-gitea-build.yml replaces it. From 55a1c6ab61407aecb7c2512159d5602c2d797b2f Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:54:06 +0200 Subject: [PATCH 15/24] ci: sync the git.upriser.nl mirror on pushes to master, feat/steamify and release branches (the mirror has no interval of its own) --- .github/workflows/git-upriser-sync.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/git-upriser-sync.yml diff --git a/.github/workflows/git-upriser-sync.yml b/.github/workflows/git-upriser-sync.yml new file mode 100644 index 0000000..37114fa --- /dev/null +++ b/.github/workflows/git-upriser-sync.yml @@ -0,0 +1,26 @@ +name: Sync git.upriser.nl mirror + +# Trigger the Gitea pull-mirror immediately instead of waiting for its interval, +# so Gitea builds/tests right after main, a release branch or a tag lands on GitHub (the mirror has no sync interval of its own). +on: + push: + branches: [master, feat/steamify, 'release/**'] + tags: ['*'] + workflow_dispatch: + +jobs: + sync: + # Gitea also reads .github/workflows on the mirror; only run on GitHub + if: github.server_url == 'https://github.com' + runs-on: ubuntu-latest + steps: + - name: Trigger mirror-sync + env: + GITEA_URL: ${{ secrets.GIT_UPRISER_URL }} + GIT_UPRISER_TOKEN: ${{ secrets.GIT_UPRISER_TOKEN }} + # Gitea "owner/repo"; defaults to the same path as on GitHub + GITEA_REPO: ${{ vars.GITEA_REPO || github.repository }} + run: | + curl --fail-with-body -sS --retry 5 --retry-delay 10 --retry-all-errors -X POST \ + -H "Authorization: token ${GIT_UPRISER_TOKEN}" \ + "${GITEA_URL%/}/api/v1/repos/${GITEA_REPO}/mirror-sync" From 13e4bbd0d6fcff98c7d8007e0c857a8d5d45ff8b Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 08:54:43 +0200 Subject: [PATCH 16/24] ci: sync the git.upriser.nl mirror on every branch and tag --- .github/workflows/git-upriser-sync.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/git-upriser-sync.yml b/.github/workflows/git-upriser-sync.yml index 37114fa..50ad01f 100644 --- a/.github/workflows/git-upriser-sync.yml +++ b/.github/workflows/git-upriser-sync.yml @@ -1,10 +1,10 @@ name: Sync git.upriser.nl mirror # Trigger the Gitea pull-mirror immediately instead of waiting for its interval, -# so Gitea builds/tests right after main, a release branch or a tag lands on GitHub (the mirror has no sync interval of its own). +# so Gitea builds/tests right after any branch or tag lands on GitHub (the mirror has no sync interval of its own). on: push: - branches: [master, feat/steamify, 'release/**'] + branches: ['**'] tags: ['*'] workflow_dispatch: From 02c207c9e5b59d50d39ff448913340873de86964 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 09:02:23 +0200 Subject: [PATCH 17/24] ci: two fixed boot loader lanes (the runner ignores max-parallel) --- .github/workflows/iso-2-gitea-build.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 4a97d87..67afddd 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -96,7 +96,7 @@ jobs: retention-days: 3 test: - name: Test ${{ matrix.loader }} + name: Test ${{ matrix.lane }} needs: build runs-on: ubuntu-latest timeout-minutes: 90 @@ -105,11 +105,10 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner has ~20 GB of RAM for this: an install VM takes 6 GB (4 GB once installed), so two at a time (needs the - # runner's `capacity: 2`; with 1 they run one after the other). - max-parallel: 2 + # The runner ignores max-parallel, so two fixed lanes: two VMs at a time (~12 GB of RAM at most), the + # loaders of a lane one after the other. matrix: - loader: [limine, systemd-boot, grub] + lane: ["limine grub", "systemd-boot"] defaults: run: shell: bash @@ -161,7 +160,7 @@ jobs: name: iso path: iso - - name: Boot loader test (${{ matrix.loader }}) + - name: Boot loader test (${{ matrix.lane }}) env: CI: "1" VM_TIMEZONE: UTC @@ -175,16 +174,20 @@ jobs: ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" cd steamify-cachyos-dev - VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install + rc=0 + for loader in ${{ matrix.lane }}; do + VM_ISO="$iso" scripts/vmbootloadertest.sh "$loader" --install || rc=1 + done + exit $rc - name: Logs if: always() uses: christopherhx/gitea-upload-artifact@v4 with: - name: test-${{ matrix.loader }} + name: test-${{ strategy.job-index }} path: | - /root/vms/bl-${{ matrix.loader }}.test.log - /root/vms/bl-${{ matrix.loader }}/vm.log + /root/vms/bl-*.test.log + /root/vms/bl-*/vm.log retention-days: 7 if-no-files-found: ignore From ea7cbfd179f5d137c28a574ed0f665f7579543f9 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 09:33:09 +0200 Subject: [PATCH 18/24] ci: drop the suites stage from the ISO flow (steamify-cachyos tests steamify.sh in its own vmtest.yml) --- .github/workflows/iso-2-gitea-build.yml | 110 +----------------------- AGENTS.md | 4 +- 2 files changed, 5 insertions(+), 109 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 67afddd..e7ccf5b 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -4,8 +4,8 @@ # checksums and package list to the mirror's release for that tag. The tag names the Steamify version and # the time: v-- (master) or v-dev.<...> (feat/steamify, a pre-release); # the ISO gets exactly that Steamify release, and its label the same moment. GitHub skips it. -# Four jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in -# parallel when the runner's capacity allows) -> the vmtest.sh suites -> release, only when every test passed. +# Three jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in +# parallel when the runner's capacity allows) -> release, only when every test passed. (The suites that test steamify.sh run in steamify-cachyos, vmtest.yml.) # The runner needs /dev/kvm, privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's # [repository.release] FILE_MAX_SIZE must allow the ISO (default 2 GB). name: ISO 2/2 · Build, test and publish (Gitea) @@ -191,113 +191,9 @@ jobs: retention-days: 7 if-no-files-found: ignore - suites: - name: Test suites (vmtest.sh) - # After the boot loader tests, not next to them: the runner is small, and a broken ISO needs no suites. - needs: [build, test] - runs-on: ubuntu-latest - timeout-minutes: 150 - container: - image: docker.io/cachyos/cachyos:latest - options: --privileged - defaults: - run: - shell: bash - steps: - # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. - - name: Node and git - id: node - run: | - pacman-key --init && pacman-key --populate - pacman -Syu --noconfirm --needed nodejs git - # The caches' keys: one entry per ISO week (an exact hit saves nothing, a new week restores the old one and saves once). - echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" - - name: Cache - pacman packages - uses: actions/cache@v4 - with: - path: /var/cache/pacman/pkg - key: pacman-test-${{ steps.node.outputs.week }} - restore-keys: pacman-test- - # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. - - name: Cache - the VMs' packages - uses: actions/cache@v4 - with: - path: /root/vms/pkg-cache - key: vmpkg-${{ needs.build.outputs.steamify }}-${{ steps.node.outputs.week }} - restore-keys: | - vmpkg-${{ needs.build.outputs.steamify }}- - vmpkg- - - name: Tools and KVM - run: | - pacman -S --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo - # Fail at once, with a reason, when the runner cannot run a VM with KVM. - [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } - nproc; free -g | sed -n 2p; df -h . | tail -n 1 - - # vmtest.sh wants its repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at the - # ISO's Steamify version (shared into the VMs) and this repository (which boot loaders the ISO advertises). - - uses: actions/checkout@v4 - with: - path: steamify-cachyos-live-iso - - uses: actions/checkout@v4 - with: - repository: theupriser/steamify-cachyos-dev - path: steamify-cachyos-dev - - uses: actions/checkout@v4 - with: - repository: theupriser/steamify-cachyos - ref: v${{ needs.build.outputs.steamify }} - path: steamify-cachyos - - # The suites run on a plain CachyOS VM (Plasma, no Steamify): the newest CachyOS ISO, installed once; - # every block then starts from a fresh overlay of that VM. - - uses: christopherhx/gitea-download-artifact@v4 - with: - name: iso - path: iso - - # The suites test steamify.sh from a plain system, so the base VM is installed from the ISO this run built - # with its Steamify step skipped (VM_STEAMIFY=skip): the ISO's installer, kernels, packages and boot loader - # are tested, every block then starts from a fresh overlay of that VM. (The boot loader jobs test the - # ISO with Steamify installed.) - - name: Base VM from the new ISO - env: - CI: "1" - VM_TIMEZONE: UTC - VM_CPUS: "2" - VM_INSTALL_MEM: 6G - VM_STEAMIFY: skip - run: | - mkdir -p ~/.ssh ~/vms/pkg-cache - ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 - iso="$(ls "$GITHUB_WORKSPACE"/iso/*.iso | head -n 1)" - cd steamify-cachyos-dev - VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso "$iso" - - # Two suites at a time, 4 GB and 2 vCPUs each (vmsuite.sh). - - name: vmtest.sh (every suite) - env: - CI: "1" - VM_CPUS: "2" - MAX_PARALLEL: "2" - run: | - cd steamify-cachyos-dev - scripts/vmtest.sh cli menu hw installer toggles - - - name: Logs - if: always() - uses: christopherhx/gitea-upload-artifact@v4 - with: - name: test-suites - path: | - /root/vms/last-test.txt - /root/vms/run-*.log - retention-days: 7 - if-no-files-found: ignore - release: name: Release - needs: [build, test, suites] + needs: [build, test] runs-on: ubuntu-latest container: image: docker.io/cachyos/cachyos:latest diff --git a/AGENTS.md b/AGENTS.md index 9e2c4ad..639ff7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -118,10 +118,10 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. release, whose `bundle.yml` needs the secret `ISO_DISPATCH_TOKEN`) names the release: the Steamify version plus GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. -- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs four jobs for that +- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install`, one job per boot loader, parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and - steamify-cachyos at the ISO's version from the mirror), then, after those, the suites (`scripts/vmtest.sh cli menu hw installer toggles` on a plain VM installed from the new ISO with `VM_STEAMIFY=skip`, two at a time), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` + steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label (`STEAMIFY_BUILD_STAMP`), boot menu and `/etc/steammachine-iso-build`. The build reads no clock; without a tag everything says `local`. From 5dea6ac7d9bd2e7d99010275c8e553e2e9fe5655 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 09:38:42 +0200 Subject: [PATCH 19/24] ci: the ISO flow only tests that the ISO installs correctly (vmbootloadertest.sh --quick) --- .github/workflows/iso-2-gitea-build.yml | 4 ++-- AGENTS.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index e7ccf5b..12decb4 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -4,7 +4,7 @@ # checksums and package list to the mirror's release for that tag. The tag names the Steamify version and # the time: v-- (master) or v-dev.<...> (feat/steamify, a pre-release); # the ISO gets exactly that Steamify release, and its label the same moment. GitHub skips it. -# Three jobs: build the ISO -> test it (the boot loader test of steamify-cachyos-dev, one job per loader, in +# Three jobs: build the ISO -> test that it installs correctly (vmbootloadertest.sh --quick of steamify-cachyos-dev per loader, in # parallel when the runner's capacity allows) -> release, only when every test passed. (The suites that test steamify.sh run in steamify-cachyos, vmtest.yml.) # The runner needs /dev/kvm, privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's # [repository.release] FILE_MAX_SIZE must allow the ISO (default 2 GB). @@ -176,7 +176,7 @@ jobs: cd steamify-cachyos-dev rc=0 for loader in ${{ matrix.lane }}; do - VM_ISO="$iso" scripts/vmbootloadertest.sh "$loader" --install || rc=1 + VM_ISO="$iso" scripts/vmbootloadertest.sh "$loader" --install --quick || rc=1 done exit $rc diff --git a/AGENTS.md b/AGENTS.md index 639ff7b..9c447db 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -119,7 +119,7 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. - `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that - tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install`, one job per boot loader, + tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install --quick` (only that the ISO installs correctly: boot entry, OS name, loader, Steamify state and modules; steamify.sh itself is tested in steamify-cachyos), two lanes, parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label From f37dcf6aa686ce7a06c86bcf435dd041747f5332 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 09:40:59 +0200 Subject: [PATCH 20/24] ci: the ISO's install test is a plain matrix again (one job per loader, 5 GB to install) --- .github/workflows/iso-2-gitea-build.yml | 26 +++++++++++-------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 12decb4..44b74b5 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -96,7 +96,7 @@ jobs: retention-days: 3 test: - name: Test ${{ matrix.lane }} + name: Test ${{ matrix.loader }} needs: build runs-on: ubuntu-latest timeout-minutes: 90 @@ -105,10 +105,10 @@ jobs: options: --privileged strategy: fail-fast: false - # The runner ignores max-parallel, so two fixed lanes: two VMs at a time (~12 GB of RAM at most), the - # loaders of a lane one after the other. + # max-parallel is ignored by this runner (it starts all three), so the VMs are lean: 3 x 5 GB to install. + max-parallel: 2 matrix: - lane: ["limine grub", "systemd-boot"] + loader: [limine, systemd-boot, grub] defaults: run: shell: bash @@ -160,34 +160,30 @@ jobs: name: iso path: iso - - name: Boot loader test (${{ matrix.lane }}) + - name: Boot loader test (${{ matrix.loader }}) env: CI: "1" VM_TIMEZONE: UTC - # The runner is 4 cores / 8 threads: two VMs with 2 vCPUs leave 4 threads for the host and the runner. + # The runner is 4 cores / 8 threads: three VMs with 2 vCPUs leave 2 threads for the host and the runner. VM_CPUS: "2" # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB is the local default, lean with headroom: lower it only after a run shows the install stays well under - VM_INSTALL_MEM: 6G + VM_INSTALL_MEM: 5G VM_ISO_DIR: ${{ github.workspace }}/iso run: | mkdir -p ~/.ssh ~/vms/pkg-cache ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" cd steamify-cachyos-dev - rc=0 - for loader in ${{ matrix.lane }}; do - VM_ISO="$iso" scripts/vmbootloadertest.sh "$loader" --install --quick || rc=1 - done - exit $rc + VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install --quick - name: Logs if: always() uses: christopherhx/gitea-upload-artifact@v4 with: - name: test-${{ strategy.job-index }} + name: test-${{ matrix.loader }} path: | - /root/vms/bl-*.test.log - /root/vms/bl-*/vm.log + /root/vms/bl-${{ matrix.loader }}.test.log + /root/vms/bl-${{ matrix.loader }}/vm.log retention-days: 7 if-no-files-found: ignore From 21e52ec81c43c4db27068adeab1b5542861dd0f9 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 09:43:12 +0200 Subject: [PATCH 21/24] ci: keep the install and serial logs of the boot loader VMs --- .github/workflows/iso-2-gitea-build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 44b74b5..f1918f4 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -184,6 +184,9 @@ jobs: path: | /root/vms/bl-${{ matrix.loader }}.test.log /root/vms/bl-${{ matrix.loader }}/vm.log + /root/vms/bl-${{ matrix.loader }}/vm-install.log + /root/vms/bl-${{ matrix.loader }}/serial.log + /root/vms/bl-${{ matrix.loader }}/install.log retention-days: 7 if-no-files-found: ignore From a7f84cd5a0d5b0769e2f63c4682914fda60c640b Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 10:03:17 +0200 Subject: [PATCH 22/24] ci: the test jobs use no actions (the runner's shared action clone broke parallel jobs); logs go into the job log --- .github/workflows/iso-2-gitea-build.yml | 77 ++++++++----------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index f1918f4..9fba4cd 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -112,53 +112,29 @@ jobs: defaults: run: shell: bash + # No `uses:` in this job on purpose: the three jobs start in the same second, and the runner clones every + # action into one shared folder (they broke each other's checkout of actions/cache). Plain git and curl instead. steps: - # First only what the cache action needs (node, git), then the caches, then the rest from the restored cache. - - name: Node and git - id: node - run: | - pacman-key --init && pacman-key --populate - pacman -Syu --noconfirm --needed nodejs git - # The caches' keys: one entry per ISO week (an exact hit saves nothing, a new week restores the old one and saves once). - echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" - - name: Cache - pacman packages - uses: actions/cache@v4 - with: - path: /var/cache/pacman/pkg - key: pacman-test-${{ steps.node.outputs.week }} - restore-keys: pacman-test- - # The guests' packages (VM_CACHE, shared into the VMs): downloaded once for every run. - - name: Cache - the VMs' packages - uses: actions/cache@v4 - with: - path: /root/vms/pkg-cache - key: vmpkg-${{ needs.build.outputs.steamify }}-${{ steps.node.outputs.week }} - restore-keys: | - vmpkg-${{ needs.build.outputs.steamify }}- - vmpkg- - name: Tools and KVM run: | - pacman -S --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo + pacman-key --init && pacman-key --populate + pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo curl unzip # Fail at once, with a reason, when the runner cannot run a VM with KVM. [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } nproc; free -g | sed -n 2p; df -h . | tail -n 1 - # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), - # steamify-cachyos at the Steamify version the ISO has (shared into the VM, 9p `repo`). - - uses: actions/checkout@v4 - with: - repository: theupriser/steamify-cachyos-dev - path: steamify-cachyos-dev - - uses: actions/checkout@v4 - with: - repository: theupriser/steamify-cachyos - ref: v${{ needs.build.outputs.steamify }} - path: steamify-cachyos - - - uses: christopherhx/gitea-download-artifact@v4 - with: - name: iso - path: iso + # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at + # the Steamify version the ISO has (shared into the VM, 9p `repo`), and the ISO this run built (its artifact). + - name: Scripts, Steamify and the ISO + run: | + base="${{ github.server_url }}" + git clone -q --depth 1 "$base/theupriser/steamify-cachyos-dev" steamify-cachyos-dev + git clone -q --depth 1 --branch "v${{ needs.build.outputs.steamify }}" "$base/theupriser/steamify-cachyos" steamify-cachyos + api="$base/api/v1/repos/${{ github.repository }}/actions" + id="$(curl -fsS "$api/runs/${{ github.run_id }}/artifacts" | python3 -c "import json,sys; print(next(a['id'] for a in json.load(sys.stdin)['artifacts'] if a['name']=='iso'))")" + curl -fsSL --retry 5 --retry-all-errors -o iso.zip "$api/artifacts/$id/zip" + unzip -q iso.zip -d iso && rm iso.zip + ls -la iso - name: Boot loader test (${{ matrix.loader }}) env: @@ -166,7 +142,7 @@ jobs: VM_TIMEZONE: UTC # The runner is 4 cores / 8 threads: three VMs with 2 vCPUs leave 2 threads for the host and the runner. VM_CPUS: "2" - # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM); 8 GB is the local default, lean with headroom: lower it only after a run shows the install stays well under + # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM). VM_INSTALL_MEM: 5G VM_ISO_DIR: ${{ github.workspace }}/iso run: | @@ -176,19 +152,14 @@ jobs: cd steamify-cachyos-dev VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install --quick - - name: Logs + # The logs go into this job's log (public), no artifact action needed. + - name: VM logs if: always() - uses: christopherhx/gitea-upload-artifact@v4 - with: - name: test-${{ matrix.loader }} - path: | - /root/vms/bl-${{ matrix.loader }}.test.log - /root/vms/bl-${{ matrix.loader }}/vm.log - /root/vms/bl-${{ matrix.loader }}/vm-install.log - /root/vms/bl-${{ matrix.loader }}/serial.log - /root/vms/bl-${{ matrix.loader }}/install.log - retention-days: 7 - if-no-files-found: ignore + run: | + for f in ~/vms/bl-${{ matrix.loader }}/install.log ~/vms/bl-${{ matrix.loader }}/serial.log ~/vms/bl-${{ matrix.loader }}/vm.log; do + [ -s "$f" ] && { echo "::group::$f (last 150 lines)"; tail -n 150 "$f" | sed 's/\x1b\[[0-9;]*m//g'; echo "::endgroup::"; } + done + true release: name: Release From 504f066a3fba7546ddcc85d35d53ab983c0f35f6 Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 10:12:52 +0200 Subject: [PATCH 23/24] ci: the ISO's install test runs on Steam Machine hardware and on a plain PC (3 VMs at a time each, the plain PC after) --- .github/workflows/iso-2-gitea-build.yml | 76 +++++++++++++++++++++++-- AGENTS.md | 2 +- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index 9fba4cd..f503c2a 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -95,8 +95,8 @@ jobs: out/desktop/*.pkgs.txt retention-days: 3 - test: - name: Test ${{ matrix.loader }} + test-fremont: + name: Steam Machine ${{ matrix.loader }} needs: build runs-on: ubuntu-latest timeout-minutes: 90 @@ -136,7 +136,7 @@ jobs: unzip -q iso.zip -d iso && rm iso.zip ls -la iso - - name: Boot loader test (${{ matrix.loader }}) + - name: Boot loader test, Steam Machine (${{ matrix.loader }}) env: CI: "1" VM_TIMEZONE: UTC @@ -161,9 +161,77 @@ jobs: done true + test-generic: + name: Plain PC ${{ matrix.loader }} + # After the Steam Machine tests (RAM: 3 VMs at a time), also when one of those failed. + needs: [build, test-fremont] + if: ${{ !cancelled() && needs.build.result == 'success' }} + runs-on: ubuntu-latest + timeout-minutes: 90 + container: + image: docker.io/cachyos/cachyos:latest + options: --privileged + strategy: + fail-fast: false + # max-parallel is ignored by this runner (it starts all three), so the VMs are lean: 3 x 5 GB to install. + max-parallel: 2 + matrix: + loader: [limine, systemd-boot, grub] + defaults: + run: + shell: bash + # No `uses:` in this job on purpose: the three jobs start in the same second, and the runner clones every + # action into one shared folder (they broke each other's checkout of actions/cache). Plain git and curl instead. + steps: + - name: Tools and KVM + run: | + pacman-key --init && pacman-key --populate + pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo curl unzip + # Fail at once, with a reason, when the runner cannot run a VM with KVM. + [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } + nproc; free -g | sed -n 2p; df -h . | tail -n 1 + + # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at + # the Steamify version the ISO has (shared into the VM, 9p `repo`), and the ISO this run built (its artifact). + - name: Scripts, Steamify and the ISO + run: | + base="${{ github.server_url }}" + git clone -q --depth 1 "$base/theupriser/steamify-cachyos-dev" steamify-cachyos-dev + git clone -q --depth 1 --branch "v${{ needs.build.outputs.steamify }}" "$base/theupriser/steamify-cachyos" steamify-cachyos + api="$base/api/v1/repos/${{ github.repository }}/actions" + id="$(curl -fsS "$api/runs/${{ github.run_id }}/artifacts" | python3 -c "import json,sys; print(next(a['id'] for a in json.load(sys.stdin)['artifacts'] if a['name']=='iso'))")" + curl -fsSL --retry 5 --retry-all-errors -o iso.zip "$api/artifacts/$id/zip" + unzip -q iso.zip -d iso && rm iso.zip + ls -la iso + + - name: Boot loader test, plain PC (${{ matrix.loader }}) + env: + CI: "1" + VM_TIMEZONE: UTC + # The runner is 4 cores / 8 threads: three VMs with 2 vCPUs leave 2 threads for the host and the runner. + VM_CPUS: "2" + # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM). + VM_INSTALL_MEM: 5G + VM_ISO_DIR: ${{ github.workspace }}/iso + run: | + mkdir -p ~/.ssh ~/vms/pkg-cache + ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 + iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" + cd steamify-cachyos-dev + VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install --quick --generic + + # The logs go into this job's log (public), no artifact action needed. + - name: VM logs + if: always() + run: | + for f in ~/vms/bl-${{ matrix.loader }}-generic/install.log ~/vms/bl-${{ matrix.loader }}-generic/serial.log ~/vms/bl-${{ matrix.loader }}-generic/vm.log; do + [ -s "$f" ] && { echo "::group::$f (last 150 lines)"; tail -n 150 "$f" | sed 's/\x1b\[[0-9;]*m//g'; echo "::endgroup::"; } + done + true + release: name: Release - needs: [build, test] + needs: [build, test-fremont, test-generic] runs-on: ubuntu-latest container: image: docker.io/cachyos/cachyos:latest diff --git a/AGENTS.md b/AGENTS.md index 9c447db..afa2f0e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -119,7 +119,7 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. - `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that - tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install --quick` (only that the ISO installs correctly: boot entry, OS name, loader, Steamify state and modules; steamify.sh itself is tested in steamify-cachyos), two lanes, + tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install --quick` (only that the ISO installs correctly: boot entry, OS name, loader, Steamify state and modules; steamify.sh itself is tested in steamify-cachyos) per loader on a VM that reports Steam Machine hardware (`--fremont`: poweroff, cec and the 3 DKMS modules must be there), then the same with `--generic` on a plain PC (they must not), parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label From 11e2ba62e9c93d981ce7920f2d6bc6154cfc410c Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Wed, 30 Sep 2026 10:27:07 +0200 Subject: [PATCH 24/24] ci: the Gitea flow only builds and releases; the VM tests run on GitHub --- .github/workflows/iso-2-gitea-build.yml | 144 +----------------------- AGENTS.md | 9 +- 2 files changed, 9 insertions(+), 144 deletions(-) diff --git a/.github/workflows/iso-2-gitea-build.yml b/.github/workflows/iso-2-gitea-build.yml index f503c2a..f91e15a 100644 --- a/.github/workflows/iso-2-gitea-build.yml +++ b/.github/workflows/iso-2-gitea-build.yml @@ -4,11 +4,11 @@ # checksums and package list to the mirror's release for that tag. The tag names the Steamify version and # the time: v-- (master) or v-dev.<...> (feat/steamify, a pre-release); # the ISO gets exactly that Steamify release, and its label the same moment. GitHub skips it. -# Three jobs: build the ISO -> test that it installs correctly (vmbootloadertest.sh --quick of steamify-cachyos-dev per loader, in -# parallel when the runner's capacity allows) -> release, only when every test passed. (The suites that test steamify.sh run in steamify-cachyos, vmtest.yml.) -# The runner needs /dev/kvm, privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's +# Two jobs: build the ISO -> release it. The VM tests run on GitHub (steamify-cachyos vmtest.yml, the newest ISO release of +# this mirror), where the runners are bigger. +# The runner needs privileged containers (archiso mounts loop devices) and ~20 GB of disk; Gitea's # [repository.release] FILE_MAX_SIZE must allow the ISO (default 2 GB). -name: ISO 2/2 · Build, test and publish (Gitea) +name: ISO 2/2 · Build and publish (Gitea) on: push: @@ -95,143 +95,9 @@ jobs: out/desktop/*.pkgs.txt retention-days: 3 - test-fremont: - name: Steam Machine ${{ matrix.loader }} - needs: build - runs-on: ubuntu-latest - timeout-minutes: 90 - container: - image: docker.io/cachyos/cachyos:latest - options: --privileged - strategy: - fail-fast: false - # max-parallel is ignored by this runner (it starts all three), so the VMs are lean: 3 x 5 GB to install. - max-parallel: 2 - matrix: - loader: [limine, systemd-boot, grub] - defaults: - run: - shell: bash - # No `uses:` in this job on purpose: the three jobs start in the same second, and the runner clones every - # action into one shared folder (they broke each other's checkout of actions/cache). Plain git and curl instead. - steps: - - name: Tools and KVM - run: | - pacman-key --init && pacman-key --populate - pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo curl unzip - # Fail at once, with a reason, when the runner cannot run a VM with KVM. - [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } - nproc; free -g | sed -n 2p; df -h . | tail -n 1 - - # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at - # the Steamify version the ISO has (shared into the VM, 9p `repo`), and the ISO this run built (its artifact). - - name: Scripts, Steamify and the ISO - run: | - base="${{ github.server_url }}" - git clone -q --depth 1 "$base/theupriser/steamify-cachyos-dev" steamify-cachyos-dev - git clone -q --depth 1 --branch "v${{ needs.build.outputs.steamify }}" "$base/theupriser/steamify-cachyos" steamify-cachyos - api="$base/api/v1/repos/${{ github.repository }}/actions" - id="$(curl -fsS "$api/runs/${{ github.run_id }}/artifacts" | python3 -c "import json,sys; print(next(a['id'] for a in json.load(sys.stdin)['artifacts'] if a['name']=='iso'))")" - curl -fsSL --retry 5 --retry-all-errors -o iso.zip "$api/artifacts/$id/zip" - unzip -q iso.zip -d iso && rm iso.zip - ls -la iso - - - name: Boot loader test, Steam Machine (${{ matrix.loader }}) - env: - CI: "1" - VM_TIMEZONE: UTC - # The runner is 4 cores / 8 threads: three VMs with 2 vCPUs leave 2 threads for the host and the runner. - VM_CPUS: "2" - # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM). - VM_INSTALL_MEM: 5G - VM_ISO_DIR: ${{ github.workspace }}/iso - run: | - mkdir -p ~/.ssh ~/vms/pkg-cache - ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 - iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" - cd steamify-cachyos-dev - VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install --quick - - # The logs go into this job's log (public), no artifact action needed. - - name: VM logs - if: always() - run: | - for f in ~/vms/bl-${{ matrix.loader }}/install.log ~/vms/bl-${{ matrix.loader }}/serial.log ~/vms/bl-${{ matrix.loader }}/vm.log; do - [ -s "$f" ] && { echo "::group::$f (last 150 lines)"; tail -n 150 "$f" | sed 's/\x1b\[[0-9;]*m//g'; echo "::endgroup::"; } - done - true - - test-generic: - name: Plain PC ${{ matrix.loader }} - # After the Steam Machine tests (RAM: 3 VMs at a time), also when one of those failed. - needs: [build, test-fremont] - if: ${{ !cancelled() && needs.build.result == 'success' }} - runs-on: ubuntu-latest - timeout-minutes: 90 - container: - image: docker.io/cachyos/cachyos:latest - options: --privileged - strategy: - fail-fast: false - # max-parallel is ignored by this runner (it starts all three), so the VMs are lean: 3 x 5 GB to install. - max-parallel: 2 - matrix: - loader: [limine, systemd-boot, grub] - defaults: - run: - shell: bash - # No `uses:` in this job on purpose: the three jobs start in the same second, and the runner clones every - # action into one shared folder (they broke each other's checkout of actions/cache). Plain git and curl instead. - steps: - - name: Tools and KVM - run: | - pacman-key --init && pacman-key --populate - pacman -Syu --noconfirm --needed qemu-desktop edk2-ovmf openssh libarchive procps-ng util-linux python git sudo curl unzip - # Fail at once, with a reason, when the runner cannot run a VM with KVM. - [ -c /dev/kvm ] || { echo "::error::no /dev/kvm in this container: the runner needs KVM (and privileged containers)"; exit 1; } - nproc; free -g | sed -n 2p; df -h . | tail -n 1 - - # The test scripts expect their repos side by side: steamify-cachyos-dev (the scripts), steamify-cachyos at - # the Steamify version the ISO has (shared into the VM, 9p `repo`), and the ISO this run built (its artifact). - - name: Scripts, Steamify and the ISO - run: | - base="${{ github.server_url }}" - git clone -q --depth 1 "$base/theupriser/steamify-cachyos-dev" steamify-cachyos-dev - git clone -q --depth 1 --branch "v${{ needs.build.outputs.steamify }}" "$base/theupriser/steamify-cachyos" steamify-cachyos - api="$base/api/v1/repos/${{ github.repository }}/actions" - id="$(curl -fsS "$api/runs/${{ github.run_id }}/artifacts" | python3 -c "import json,sys; print(next(a['id'] for a in json.load(sys.stdin)['artifacts'] if a['name']=='iso'))")" - curl -fsSL --retry 5 --retry-all-errors -o iso.zip "$api/artifacts/$id/zip" - unzip -q iso.zip -d iso && rm iso.zip - ls -la iso - - - name: Boot loader test, plain PC (${{ matrix.loader }}) - env: - CI: "1" - VM_TIMEZONE: UTC - # The runner is 4 cores / 8 threads: three VMs with 2 vCPUs leave 2 threads for the host and the runner. - VM_CPUS: "2" - # RAM of the live installer VM (the ISO is read from its cdrom, only the overlay and the installer use RAM). - VM_INSTALL_MEM: 5G - VM_ISO_DIR: ${{ github.workspace }}/iso - run: | - mkdir -p ~/.ssh ~/vms/pkg-cache - ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f ~/.ssh/steamify-vm_ed25519 - iso="$(ls "$VM_ISO_DIR"/*.iso | head -n 1)" - cd steamify-cachyos-dev - VM_ISO="$iso" scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install --quick --generic - - # The logs go into this job's log (public), no artifact action needed. - - name: VM logs - if: always() - run: | - for f in ~/vms/bl-${{ matrix.loader }}-generic/install.log ~/vms/bl-${{ matrix.loader }}-generic/serial.log ~/vms/bl-${{ matrix.loader }}-generic/vm.log; do - [ -s "$f" ] && { echo "::group::$f (last 150 lines)"; tail -n 150 "$f" | sed 's/\x1b\[[0-9;]*m//g'; echo "::endgroup::"; } - done - true - release: name: Release - needs: [build, test-fremont, test-generic] + needs: build runs-on: ubuntu-latest container: image: docker.io/cachyos/cachyos:latest diff --git a/AGENTS.md b/AGENTS.md index afa2f0e..3f11d4c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -118,10 +118,9 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. release, whose `bundle.yml` needs the secret `ISO_DISPATCH_TOKEN`) names the release: the Steamify version plus GitHub's UTC time, `vX.Y.Z-[dev.]YYYY.MM.DD-HHMM`, an **annotated** tag and a release with notes and the direct download link. `feat/steamify` makes a `dev.` pre-release, `master` a real one. -- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs three jobs for that - tag: build the ISO, test it (steamify-cachyos-dev's `scripts/vmbootloadertest.sh --install --quick` (only that the ISO installs correctly: boot entry, OS name, loader, Steamify state and modules; steamify.sh itself is tested in steamify-cachyos) per loader on a VM that reports Steam Machine hardware (`--fremont`: poweroff, cec and the 3 DKMS modules must be there), then the same with `--generic` on a plain PC (they must not), - parallel up to the runner's capacity; needs `/dev/kvm` on the runner and checks out steamify-cachyos-dev `main` and - steamify-cachyos at the ISO's version from the mirror), and only when all tests passed attach it to the mirror's release. The tag decides everything: Steamify version (`steamify-prepare.sh` +- `.github/workflows/iso-2-gitea-build.yml` (Gitea, `on: push: tags: v*`, skipped on GitHub) runs two jobs for that + tag: build the ISO, then attach it to the mirror's release. It is not tested there (the runner is small): the VM tests + run on GitHub, in steamify-cachyos `vmtest.yml`, on the newest ISO release of the mirror. The tag decides everything: Steamify version (`steamify-prepare.sh` takes `STEAMIFY_VERSION`), file name (`STEAMIFY_ISO_VERSION` -> `iso_version` in `profiledef.sh`), label (`STEAMIFY_BUILD_STAMP`), boot menu and `/etc/steammachine-iso-build`. The build reads no clock; without a tag everything says `local`. @@ -132,4 +131,4 @@ Full write-up, with every trap: `steamify-iso-release` in steamify-cachyos-dev. - Gitea needs `[repository.release] FILE_MAX_SIZE` above the ISO (413 otherwise) and the runner `container: privileged: true` (archiso mounts `/proc`); the workflow's `--privileged` option is ignored. - Caches (`actions/cache`, the runner's cache server): pacman's package cache per job kind (build, test) and the VMs' packages (`VM_CACHE`, `~/vms/pkg-cache`), keys per ISO week. Each job first installs only node and git, restores the caches, then installs the rest. -- CachyOS's own `Desktop ISO` workflow (`build.yml`) is removed here; the test job of iso-2-gitea-build.yml replaces it. +- CachyOS's own `Desktop ISO` workflow (`build.yml`) is removed here; the VM tests live in steamify-cachyos (GitHub).