Compare commits

...
21 Commits
Author SHA1 Message Date
theupriser 1a2d81c0a0 ci: stream the VM tests' progress into the job log 2026-09-30 10:50:48 +02:00
theupriser d12be7eaa2 ci: the VM tests only run on main and release branches (and by hand), not on pull requests 2026-09-30 10:28:24 +02:00
theupriser 0bbe97214e ci: wait for udev to apply the KVM rule, print what the runner has 2026-09-30 10:07:50 +02:00
theupriser c4631d6a23 ci: no strategy context in the composite action (vmpkg cache key per run) 2026-09-30 09:35:09 +02:00
theupriser ec993eca33 ci: VM tests: one job per boot loader and per suite, all parallel on their own GitHub runners; the ISO is fetched once and cached 2026-09-30 09:34:53 +02:00
theupriser 5c0cd7aa92 ci: the VM tests run on GitHub's runners (better resources), one matrix job per boot loader, not on the Gitea mirror
vmtest.yml: newest Steamify ISO release from the mirror (secret GIT_UPRISER_URL), KVM on the hosted runner, boot loaders limine/systemd-boot/grub two at a time, then the suites on a plain VM from the same ISO.
2026-09-30 09:34:03 +02:00
theupriser 2a213946ec ci: two fixed boot loader lanes (the runner ignores max-parallel) 2026-09-30 09:02:30 +02:00
theupriser 5585d92cf8 feat(ci): VM tests on the Gitea mirror: boot loaders and all suites on this commit, from the newest Steamify ISO release
vmtest.yml (Gitea only) runs steamify-cachyos-dev's vmbootloadertest.sh per loader (limine, systemd-boot, grub), then the vmtest.sh suites on a plain VM from the same ISO, on pushes to main and release/**, pull requests and by hand.
2026-09-30 08:47:30 +02:00
theupriser d44f29956a Merge pull request #63 from theupriser/release/2.9.4
Single-file build / bundle (push) Successful in 13s
Release 2.9.4
2026-09-29 23:08:59 +02:00
theupriser 2858d13429 docs: changelog hash for 2.9.4 2026-09-29 23:08:20 +02:00
theupriser 48cf3c7c7c Merge pull request #62 from theupriser/feature/docs-ci-and-cec-cache
docs: the CEC driver cache and the CI/ISO release flow
2026-09-29 23:08:12 +02:00
theupriser 619ef1f714 docs: AGENTS.md and TECHNICAL.md: the CEC driver cache, one workflow for GitHub and a Gitea mirror, a release starts the Steamify ISO's release 2026-09-29 23:07:28 +02:00
theupriser b6240539e6 chore: Version 2.9.4 2026-09-29 23:07:08 +02:00
theupriser 7d6df21627 Merge pull request #61 from theupriser/release/2.9.3
Single-file build / bundle (push) Successful in 13s
Release 2.9.3
2026-09-29 22:04:49 +02:00
theupriser 3cad70dcc4 docs: changelog hash for 2.9.3
Single-file build / bundle (push) Successful in 24s
2026-09-29 22:03:09 +02:00
theupriser b8742a5642 Merge pull request #60 from theupriser/feature/iso-release-on-steamify-release
feat(ci): a new Steamify release starts the Steamify ISO's release
2026-09-29 21:57:25 +02:00
theupriser 7f5d29c997 feat(ci): a new Steamify release starts the Steamify ISO's release (iso-release.yml in the ISO repo, feat/steamify; secret ISO_DISPATCH_TOKEN) 2026-09-29 21:56:42 +02:00
theupriser cfe3ce7bd0 chore: Version 2.9.3 2026-09-29 21:55:45 +02:00
theupriser 3e4133c14a Merge pull request #58 from theupriser/release/2.9.2
Single-file build / bundle (push) Successful in 14s
Release/2.9.2
2026-09-29 20:31:12 +02:00
theupriser c4b8db85dc Merge pull request #57 from theupriser/feature/gitea-release
Single-file build / bundle (push) Successful in 13s
feat(ci): a Gitea mirror publishes its own releases
2026-09-29 20:30:00 +02:00
theupriser 350011877b feat(ci): a Gitea mirror publishes its own release per version (never overwrites one, notes from the changelog) 2026-09-29 20:29:19 +02:00
7 changed files with 294 additions and 2 deletions

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
name: VM runner
description: KVM, qemu, the big disk for the VMs, the package cache and the cached Steamify ISO (at /mnt/work/iso/steamify.iso)
inputs:
iso-tag:
description: The Steamify ISO release the iso job cached
required: true
runs:
using: composite
steps:
- name: KVM, qemu, disk
shell: bash
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules && sudo udevadm trigger --name-match=kvm && sudo udevadm settle || true
for _ in $(seq 10); do [ -w /dev/kvm ] && break; sleep 1; done
ls -l /dev/kvm 2>&1 || true
grep -cE 'vmx|svm' /proc/cpuinfo || true
[ -w /dev/kvm ] || { echo "::error::no usable /dev/kvm on this runner (some GitHub runners have none: re-run the job)"; exit 1; }
sudo apt-get update -qq
sudo apt-get install -y -qq qemu-system-x86 qemu-utils ovmf libarchive-tools openssh-client
# The VMs and the ISO on /mnt (the big disk); ~/vms points there.
sudo mkdir -p /mnt/work && sudo chown "$USER" /mnt/work
mkdir -p /mnt/work/vms/pkg-cache /mnt/work/iso "$HOME/.ssh" && ln -s /mnt/work/vms "$HOME/vms"
ssh-keygen -q -t ed25519 -N "" -C steamify-vm -f "$HOME/.ssh/steamify-vm_ed25519"
nproc; free -g | sed -n 2p; df -h /mnt | tail -n 1
- name: Cache - the VMs' packages
uses: actions/cache@v4
with:
path: /mnt/work/vms/pkg-cache
key: vmpkg-${{ github.run_id }}
restore-keys: vmpkg-
- name: Cache - the ISO (from the iso job)
uses: actions/cache/restore@v4
with:
path: /mnt/work/iso
key: steamify-iso-${{ inputs.iso-tag }}
fail-on-cache-miss: true
+76
View File
@@ -133,3 +133,79 @@ jobs:
gh release create latest --title "Steamify CachyOS - latest (v$VERSION)" --notes "$latest_notes" --latest=false gh release create latest --title "Steamify CachyOS - latest (v$VERSION)" --notes "$latest_notes" --latest=false
fi fi
gh release upload latest dist/steamify.sh dist/steamify-app.sh dist/steamify-app.tar.gz assets/steam-gaming-settings.svg --clobber gh release upload latest dist/steamify.sh dist/steamify-app.sh dist/steamify-app.tar.gz assets/steam-gaming-settings.svg --clobber
# The mirror (Gitea) publishes its own release per version too, the same way: never overwrites one,
# notes from the changelog. gh can't talk to Gitea: its API for the check, a Gitea release action to
# publish. The token is the run's own (repository write); a secret RELEASE_TOKEN overrides it.
- name: Version (mirror)
id: mirror_version
if: github.server_url != 'https://github.com'
env:
TOKEN: ${{ secrets.RELEASE_TOKEN || github.token }}
run: |
version="$(grep -oP '^VERSION=\K.*' steamify.sh)"
echo "version=$version" >> "$GITHUB_OUTPUT"
if curl -fsS -o /dev/null -H "Authorization: token $TOKEN" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/tags/v$version"; then
echo "released=true" >> "$GITHUB_OUTPUT"
echo "::warning::v$version is already released on this server and won't be overwritten."
else
echo "released=false" >> "$GITHUB_OUTPUT"
fi
- name: Release notes (mirror)
if: >-
github.server_url != 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.mirror_version.outputs.released == 'false'
env:
VERSION: ${{ steps.mirror_version.outputs.version }}
run: |
changes="$(awk -v v="$VERSION" '
$0 ~ "^## " { if (found) exit; if (index($0, "## " v " ") == 1) { found = 1; next } }
found' CHANGELOG.md)"
cat > dist/release-notes.md <<NOTES
Single-file build of v$VERSION ($(git describe --always), $(git log -1 --format=%cs)).
Run this version with:
curl -fsSL ${{ github.server_url }}/${{ github.repository }}/releases/download/v$VERSION/steamify.sh | bash
## Changes in v$VERSION
$changes
NOTES
- name: Publish the v${{ steps.mirror_version.outputs.version }} release (mirror)
if: >-
github.server_url != 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.mirror_version.outputs.released == 'false'
uses: akkuman/gitea-release-action@v1.3.7
with:
token: ${{ secrets.RELEASE_TOKEN || github.token }}
tag_name: v${{ steps.mirror_version.outputs.version }}
target_commitish: ${{ github.sha }}
name: Steamify CachyOS v${{ steps.mirror_version.outputs.version }}
body_path: dist/release-notes.md
files: |
dist/steamify.sh
dist/steamify-app.sh
dist/steamify-app.tar.gz
assets/steam-gaming-settings.svg
# A new Steamify release starts the Steamify ISO's release with it (a test build from the ISO repo's
# feat/steamify, until that is its master): its iso-release.yml names it after this version, tags it,
# and the Gitea mirror builds and attaches the ISO. Needs a fine-grained token for that repo
# (Actions: read and write) as the secret ISO_DISPATCH_TOKEN; without it, this is skipped.
- name: Start the Steamify ISO's release
if: >-
github.server_url == 'https://github.com' &&
github.event_name != 'pull_request' && github.ref == 'refs/heads/main' &&
steps.version.outputs.released == 'false'
env:
GH_TOKEN: ${{ secrets.ISO_DISPATCH_TOKEN }}
run: |
if [ -z "$GH_TOKEN" ]; then
echo "::notice::No ISO_DISPATCH_TOKEN: the Steamify ISO isn't released with this version."; exit 0
fi
gh workflow run iso-release.yml -R theupriser/steammachine-cachyos-live-iso --ref feat/steamify
echo "Started the Steamify ISO's release (theupriser/steammachine-cachyos-live-iso, feat/steamify)"
+156
View File
@@ -0,0 +1,156 @@
# Steamify's own VM tests on GitHub's runners (4 vCPUs, 16 GB, KVM; skipped on the Gitea mirror): the same as
# `scripts/vmtest.sh` in steamify-cachyos-dev, on this commit's steamify.sh. The base is the newest Steamify ISO
# release (steamify-cachyos-live-iso, built and kept on the git.upriser.nl mirror: GitHub releases take at
# most 2 GB per file): the boot loader tests (limine, systemd-boot, grub) install it with this commit's
# Steamify, then the suites (cli, menu, hw, installer, toggles) run on a plain VM from the same ISO (its
# Steamify step skipped: the suites start from a system without Steamify).
# The ISO is fetched once (the iso job, cached) and restored by the others.
# Needs the secret GIT_UPRISER_URL (the mirror's address, for the ISO). Every job has its own runner, so everything runs in parallel: one job per boot loader and per suite, each with its own VMs (2 vCPUs, 4-6 GB).
name: Steamify VM tests
# Only on main and the release branches (and by hand): the runners' time is limited, so not on every pull request.
on:
push:
branches: [main, 'release/**']
workflow_dispatch:
# A new run on the same branch stops the old one.
concurrency:
group: vmtest-${{ github.ref }}
cancel-in-progress: true
jobs:
iso:
name: Newest Steamify ISO
if: github.server_url == 'https://github.com'
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.find.outputs.tag }}
steps:
- name: Find the newest ISO release on the mirror
id: find
env:
MIRROR: ${{ secrets.GIT_UPRISER_URL }}
run: |
[ -n "$MIRROR" ] || { echo "::error::the secret GIT_UPRISER_URL is not set"; exit 1; }
read -r tag url < <(curl -fsS "${MIRROR%/}/api/v1/repos/theupriser/steamify-cachyos-live-iso/releases?limit=20" | python3 -c '
import json, sys
for r in json.load(sys.stdin):
for a in r["assets"]:
if a["name"].endswith(".iso"):
print(r["tag_name"], a["browser_download_url"]); raise SystemExit
')
[ -n "$tag" ] || { echo "::error::no ISO release on the mirror"; exit 1; }
echo "Using $tag"
{ echo "tag=$tag"; echo "url=$url"; } >> "$GITHUB_OUTPUT"
- name: Cache - the ISO
id: cache
uses: actions/cache@v4
with:
path: /mnt/work/iso
key: steamify-iso-${{ steps.find.outputs.tag }}
- name: Download the ISO (once for every job)
if: steps.cache.outputs.cache-hit != 'true'
run: |
sudo mkdir -p /mnt/work/iso && sudo chown -R "$USER" /mnt/work
curl -fL --retry 5 --retry-all-errors -o /mnt/work/iso/steamify.iso "${{ steps.find.outputs.url }}"
ls -la /mnt/work/iso
boot:
name: Boot loader ${{ matrix.loader }}
needs: iso
runs-on: ubuntu-latest
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
loader: [limine, systemd-boot, grub]
steps:
- uses: actions/checkout@v4
with:
path: steamify-cachyos
- uses: actions/checkout@v4
with:
repository: theupriser/steamify-cachyos-dev
path: steamify-cachyos-dev
- uses: ./steamify-cachyos/.github/actions/vm-runner
with:
iso-tag: ${{ needs.iso.outputs.tag }}
- name: Boot loader test (${{ matrix.loader }})
env:
CI: "1"
VM_TIMEZONE: UTC
VM_CPUS: "4"
VM_INSTALL_MEM: 6G
run: |
cd steamify-cachyos-dev
touch ~/vms/test.log; tail -n +1 -F ~/vms/test.log & tailpid=$! # the test's progress, as it happens
trap 'kill $tailpid 2>/dev/null' EXIT
VM_ISO=/mnt/work/iso/steamify.iso scripts/vmbootloadertest.sh "${{ matrix.loader }}" --install
- name: Logs
if: always()
uses: actions/upload-artifact@v4
with:
name: boot-${{ matrix.loader }}
path: |
/mnt/work/vms/bl-${{ matrix.loader }}.test.log
/mnt/work/vms/bl-${{ matrix.loader }}/vm.log
retention-days: 7
if-no-files-found: ignore
suites:
name: Suite ${{ matrix.suite }}
needs: iso
runs-on: ubuntu-latest
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
suite: [toggles, hw, cli, 'menu installer']
steps:
- uses: actions/checkout@v4
with:
path: steamify-cachyos
- uses: actions/checkout@v4
with:
repository: theupriser/steamify-cachyos-dev
path: steamify-cachyos-dev
# vmtest.sh reads which boot loaders the ISO advertises from this repository.
- uses: actions/checkout@v4
with:
repository: theupriser/steamify-cachyos-live-iso
path: steamify-cachyos-live-iso
- uses: ./steamify-cachyos/.github/actions/vm-runner
with:
iso-tag: ${{ needs.iso.outputs.tag }}
# A plain VM for the suites: the ISO's installer with its Steamify step skipped (the suites start without Steamify).
- name: Base VM from the ISO
env:
CI: "1"
VM_TIMEZONE: UTC
VM_CPUS: "4"
VM_INSTALL_MEM: 6G
VM_STEAMIFY: skip
run: |
cd steamify-cachyos-dev
VM_DIR="$HOME/vms/steamify-vm" scripts/vminstall.sh --iso /mnt/work/iso/steamify.iso
- name: vmtest.sh ${{ matrix.suite }}
env:
CI: "1"
VM_CPUS: "2"
MAX_PARALLEL: "2"
run: |
cd steamify-cachyos-dev
touch ~/vms/test.log; tail -n +1 -F ~/vms/test.log & tailpid=$! # the suites' progress, as it happens
trap 'kill $tailpid 2>/dev/null' EXIT
scripts/vmtest.sh ${{ matrix.suite }}
- name: Logs
if: always()
uses: actions/upload-artifact@v4
with:
name: suite-${{ strategy.job-index }}
path: |
/mnt/work/vms/last-test.txt
/mnt/work/vms/run-*.log
retention-days: 7
if-no-files-found: ignore
+12
View File
@@ -68,6 +68,13 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
the entry point's `for lib in ...; do` source loop and wraps everything the entry point's `for lib in ...; do` source loop and wraps everything
after that loop in `main()`. Keep that loop on one line, keep all logic in after that loop in `main()`. Keep that loop on one line, keep all logic in
functions, and don't rely on `SCRIPT_DIR` for anything but sourcing. functions, and don't rely on `SCRIPT_DIR` for anything but sourcing.
The workflow is one file for GitHub and a Gitea mirror (`github.server_url`): build and check run on both
(shellcheck through `ludeeus/action-shellcheck`, which brings its own binary; the artifact with
`upload-artifact@v4` on GitHub and `christopherhx/gitea-upload-artifact@v4` elsewhere: never mention
`upload-artifact@v3`, GitHub fails a workflow for a deprecated version even in a skipped step); the
release is `gh` on GitHub and `akkuman/gitea-release-action` on Gitea. A new release on GitHub also starts the
Steamify ISO's release (`gh workflow run iso-release.yml` in steammachine-cachyos-live-iso, secret
`ISO_DISPATCH_TOKEN`; skipped without it): the ISO repo's GitHub tag names it, the Gitea mirror builds it.
CI (`.github/workflows/bundle.yml`) publishes the bundle as release CI (`.github/workflows/bundle.yml`) publishes the bundle as release
`v$VERSION` on pushes to `main`; an existing version is never overwritten, `v$VERSION` on pushes to `main`; an existing version is never overwritten,
so bump `VERSION` for every release. so bump `VERSION` for every release.
@@ -252,6 +259,11 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
kernel only pairs that with a named lookup ("Port C") when the CEC driver kernel only pairs that with a named lookup ("Port C") when the CEC driver
registered first, which never happens since amdgpu loads from the registered first, which never happens since amdgpu loads from the
initramfs. Without it `/dev/cec0` exists but stays at `f.f.f.f`. initramfs. Without it `/dev/cec0` exists but stays at `f.f.f.f`.
The source comes from one raw.githubusercontent.com download, which GitHub rate-limits (HTTP 429 after a
day of test installs, per address): it's kept in `/var/cache/steamify/cros-ec-cec-<sha256:12>.c` and reused
while its checksum matches. The name carries the checksum, so a new pin (commit + SHA-256 in `lib/cec.sh`)
downloads its own file once and removes the old one. The repo is an unofficial mirror of Valve's kernel
without releases: if it ever disappears, ship the file with Steamify. The test VMs share the host's cache.
- Power-off fix (`poweroff`, `lib/fremont-poweroff.sh`, a default sub-option - Power-off fix (`poweroff`, `lib/fremont-poweroff.sh`, a default sub-option
of `machine`): recent kernels (7.2 and the 6.x/7.0/7.1 updates with the of `machine`): recent kernels (7.2 and the 6.x/7.0/7.1 updates with the
backport) keep the firmware's S4/S5 wake bit on GPIO backport) keep the firmware's S4/S5 wake bit on GPIO
+11
View File
@@ -5,8 +5,19 @@ All notable changes, per version and per commit. Versions follow
`steamify.sh`. Versions before 0.7.0 were numbered afterwards, `steamify.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request. one per merged pull request.
## 2.9.4 - 2026-09-29
- `619ef1f` **docs: AGENTS.md and TECHNICAL.md: the CEC driver cache, the one workflow for GitHub and a Gitea mirror, and that a new release starts the Steamify ISO's release**
- `b624053` **chore: Version 2.9.4**
## 2.9.3 - 2026-09-29
- `7f5d29c` **feat(ci): a new Steamify release starts the Steamify ISO's release (a test build from the ISO repo's feat/steamify; secret ISO_DISPATCH_TOKEN)**
- `cfe3ce7` **chore: Version 2.9.3**
## 2.9.2 - 2026-09-29 ## 2.9.2 - 2026-09-29
- **feat(ci): a Gitea mirror publishes its own release per version (akkuman/gitea-release-action; never overwrites one, notes from the changelog, links to the mirror)**
- **fix(ci): the build also runs on a Gitea mirror (act_runner): shellcheck through ludeeus/action-shellcheck, which brings its own binary; the artifact goes up there with christopherhx/gitea-upload-artifact (GitHub refuses a workflow that mentions the deprecated upload-artifact@v3); releases are only published on GitHub** - **fix(ci): the build also runs on a Gitea mirror (act_runner): shellcheck through ludeeus/action-shellcheck, which brings its own binary; the artifact goes up there with christopherhx/gitea-upload-artifact (GitHub refuses a workflow that mentions the deprecated upload-artifact@v3); releases are only published on GitHub**
- `fe4f3f4` **chore: Version 2.9.2** - `fe4f3f4` **chore: Version 2.9.2**
+1 -1
View File
@@ -514,7 +514,7 @@ immediately, which can turn into a loop - see
| `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README | | `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README |
| `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README | | `patches/` | Module sources and patches the scripts build or apply (`patch_file`); see its README |
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`), with `patches/` and `services/` embedded | | `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`), with `patches/` and `services/` embedded |
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` | | `.github/workflows/bundle.yml` | Builds and checks it on every push (GitHub and a Gitea mirror); publishes it on `main`, and starts the Steamify ISO's release |
The single-file version is generated: on every push to `main`, GitHub The single-file version is generated: on every push to `main`, GitHub
Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and Actions runs `.github/tools/bundle.sh`, checks the result with `bash -n` and
+1 -1
View File
@@ -15,7 +15,7 @@
set -uo pipefail set -uo pipefail
# Release version, see CHANGELOG.md. # Release version, see CHANGELOG.md.
VERSION=2.9.2 VERSION=2.9.4
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"