Documents
CI_CD_GUIDE
CI_CD_GUIDE
Type
External
Status
Published
Created
Jun 13, 2026
Updated
Jun 13, 2026
Source
View

CI/CD Guide — bootc-installer#

Complete reference for all CI workflows, release process, and the release qualification runbook.


Workflows#

python-test.yml — Python Tests#

Triggers: push/PR to dev/prod, merge queue, manual dispatch

JobWhat it does
unitpytest tests/unit/ with coverage (--cov-fail-under=47) — no display required
uipytest tests/ui/ via Xvfb + compiled GResources (meson/ninja)

Coverage gate is a ratchet — never lower --cov-fail-under. Measure with pytest tests/unit/ -q --cov=bootc_installer 2>&1 | tail -5 before raising it.


go-test.yml — Go Tests (fisherman)#

Triggers: push/PR to dev/prod, merge queue, manual dispatch

Runs inside fisherman/fisherman/:

  1. go vet ./...
  2. go test -v -count=1 -timeout=60s -coverprofile=coverage.out ./...
  3. Coverage gate: 20%
  4. go test -race -count=1 -timeout=60s ./... (race detector)

flatpak.yml — GNOME Flatpak Build#

Triggers: push to dev/prod, v* tags, PRs to dev/prod

JobConditionOutput
productionPR, prod push, or v* tagorg.bootcinstaller.Installer.flatpakcontinuous release
develPR or dev pushorg.bootcinstaller.Installer.Devel.flatpakcontinuous-dev release

Uses ghcr.io/flathub-infra/flatpak-github-actions:gnome-50 container with --privileged. Requires permissions: contents: write on the release job.


build-flatpaks.yml — Multi-Variant Flatpak Build#

Triggers: push to dev/prod, v* tags, manual dispatch

Builds all three variants in parallel via a matrix:

VariantApp IDManifest
GNOMEorg.bootcinstaller.Installerflatpak/org.bootcinstaller.Installer.json
XFCEorg.xfceinstaller.Installerflatpak/org.xfceinstaller.Installer.json
KDEorg.kdeinstaller.Installerflatpak/org.kdeinstaller.Installer.json

Publishes Flatpaks as GitHub release assets under the same continuous / continuous-dev / v* tags.


validate-flatpak.yml — Validate Flatpak Manifests#

Triggers: PRs/pushes that touch flatpak/*.json, meson.build, meson_options.txt

  • Validates all manifests are well-formed JSON
  • Checks required fields: app-id, runtime, command
  • Verifies app-id consistency per variant (GNOME / XFCE / KDE)
  • Posts a ✅ comment on the PR when all pass

nightly.yml — Nightly Tests#

Triggers: 06:00 UTC daily, manual dispatch

Runs fisherman tests on both dev and prod branches:

  1. go vet ./...
  2. go test -v -count=1 -timeout=60s ./...
  3. go test -race -count=1 -timeout=60s ./...

This catches race conditions and test drift that only appear under extended runs.


Branch Strategy#

feature/xyz ──► dev ──► prod
  • All feature PRs target dev
  • prod is promoted wholesale from dev when dev is shippable
  • Never open PRs directly against prod
  • Merge queue is enabled on dev — use gh pr merge --squash <N> to enqueue

Release Process#

Continuous (pre-release)#

Automatic on every push to dev or prod:

  • devcontinuous-dev pre-release
  • prodcontinuous pre-release

Tagged release#

git tag v0.3.0
git push origin v0.3.0

Both flatpak.yml and build-flatpaks.yml attach their Flatpak artifacts to the tagged release.


Release Qualification Runbook#

Software-only (automated — run locally)#

./QUALIFY_SOFTWARE.sh

This validates Flatpak JSON, runs all unit + UI tests, runs fisherman Go tests, and builds the production and devel Flatpaks. All steps must pass green before promoting dev → prod.

Hardware-only checks (manual — not automated in CI)#

These require real hardware and cannot be gated in CI:

CheckHow to test
TPM2 LUKS enrolmentInstall with tpm2-luks on real hardware; verify no password prompt on reboot
Recovery key displayInstall with tpm2-luks-passphrase; confirm key shown and copyable in GUI
Passphrase fallbackInstall with luks-passphrase; verify passphrase prompt on reboot
GRUB boot (XFS root)Install with filesystem=xfs; verify GRUB loads from ext4 /boot
systemd-boot (btrfs/composefs)Install with composeFsBackend=true; verify bootctl status clean
Windows slurpRun on machine with Windows NTFS partition; verify wallpapers + data migrated
Offline ISOBoot from live ISO with embedded OCI; verify install completes without internet
Post-reboot WiFiInstall on machine with saved WiFi; verify auto-reconnect after reboot
OEM first-bootInstall on ASUS/Framework hardware; verify OEM packages queued

For the full E2E integration tests (QEMU-backed, requires root):

go build -o /tmp/fisherman-test ./fisherman/fisherman/cmd/fisherman/
sudo FISHERMAN_BIN=/tmp/fisherman-test pytest tests/integration/test_e2e_install.py -v -s
# With QEMU boot verification (~5 min/image):
sudo FISHERMAN_BIN=/tmp/fisherman-test BOOT_VERIFY=1 pytest tests/integration/test_e2e_install.py -v -s

Common CI Failures#

SymptomCauseFix
"No checks reported" on PRBranch has merge conflicts — GitHub silently skips pull_request eventsgh pr view N --json mergeable → rebase onto dev
Coverage gate failsNew code not coveredAdd tests or measure actual floor before lowering gate
ModuleNotFoundError in Flatpak but not sourceNew .py not in meson.build sources = [...]Add the file to its subpackage's meson.build
fisherman submodule not updatedParent repo pointer not bumped after submodule pushgit add fisherman && git commit -m "chore: update fisherman submodule"
safe.bareRepository Flatpak build failureUsed "type": "git" in manifestSwitch to "type": "archive" with SHA256

Triggers:

  • Pushes to dev or prod branches
  • Any tag matching v*