Commit Graph
66 Commits
Author SHA1 Message Date
Ryan Hughes 5fb29fe547 Let sync PRs approve their own builds
The upstream and rebuild syncs push with GITHUB_TOKEN, so GitHub holds
their build and test runs for approval. Their approve job only released
those runs once a maintainer had applied build-approved, and never ran
for the push that opened the PR, so every sync PR sat waiting.

The sync now labels its own PR build-approved, and the approve job runs
for created PRs as well as updated ones.
2026-10-06 20:32:42 -04:00
Emir Beganovic f51d504a66 Flag a recipe change that will not ship without a version bump
When edge already holds the version, a PKGBUILD whose recipe changed
(comments and blank lines aside) builds nothing and publishes nothing.
Arch bumps pkgrel only when the built package changes, which is the
reviewer's call, so this is a warning annotation on the PKGBUILD and a
job summary line, not a failure. Comment-only and hook-only changes
stay silent.
2026-10-04 01:10:54 +02:00
Emir Beganovic 5bd85a785f Skip packing a PR build when edge already holds the version
A PR can change a package's directory without bumping its version: an
upstream hook, its tests, a README. bin/build then plans nothing, and
the pack step failed on the empty build output, turning the required
result check red (seen on #769). Make the same dry-run check
publish.yml's rebuild job already makes, and skip packing and uploading
when nothing was built. publish.yml finds no artifact for such a merge
and records the package as already published.
2026-10-04 01:03:49 +02:00
97925fbc84 Apply the IPU7 camera's ISP tuning, fix its gain, range and exposure, harden PSYS pinning, and support Lunar Lake (#723)
* Apply the Intel IPU7 camera's ISP tuning and fix its gain, range and exposure

The XPS 14 / 16 webcam looked soft and grainy because almost none of the
image pipeline was tuned:

- 0011: the graph asks for ISP tuning mode 4, which the OV08X40 tuning
  does not carry, so the generic AIC found no tunings and noise
  reduction, TNR and sharpening ran on library defaults. Fall back to
  the tuning's default ISP container.
- 0010: AIQ emits the raw analog gain register code, which the in-tree
  ov08x40 driver halves, so the sensor ran at twice the gain AE and the
  ISP noise model assumed.
- 0008: the HAL ignored the requested YUV range and always produced
  full-range frames that consumers decode as limited range.
- 0009 + relay config: icamerasrc pinned auto exposure to 1/30 s; a new
  fps-range property lets AE lengthen frames in dim light, with gain
  capped at 27 dB.

* Guard fps-range against NULL and correct two descriptions

Setting icamerasrc's new fps-range property to NULL, its own default, handed NULL to gst_camerasrc_parse_range, which crashed in strlen(). NULL now leaves the last range in effect, because the HAL has no way to drop a range once set. The value the relay sets goes through unchanged.

The relay comment said AE raises gain past 27 dB once frames reach 15 fps, but gain-range becomes a hard ISO ceiling (manual_iso_max), so gain never goes past it. The 0008 message credited the sensor JSON's yuvColorRangeMode, which only the mock HAL reads.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Free fps-range when icamerasrc is destroyed

finalize never freed the string the fps-range setter allocates, so every icamerasrc element that had the property set leaked it. The other string properties leak the same way upstream and are left to an upstream fix for all of them.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Harden IPU7 PSYS userptr pinning

(cherry picked from commit 5f1d0013b0e37d9229dfb906806dee0e98199035)

* Avoid unverified IPU7 permission assurances

(cherry picked from commit 9ce97d9788f2be508743fe785f8434ccfec7842e)

* Check IPU7 against Omarchy headers without a runtime dependency

Use linux-omarchy-headers only for check(), avoiding Arch headers on installed Omarchy systems and matching the supported kernel build configuration.

Signed-off-by: Afonso Oliveira <afonso.oliveira707@gmail.com>
(cherry picked from commit d0d382c07ea99eca5bb5c52240841db779d24b14)

* Test IPU7 build-only headers and kernel-tree selection

Signed-off-by: Afonso Oliveira <afonso.oliveira707@gmail.com>
(cherry picked from commit eb37cc828fac201a360c35aa1e87a1daf2d5fed1)

* Restrict the IPU7 PSYS node to root

Intel's PSYS driver has two buffer-lifecycle bugs that this package does not fix: a GETBUF that is never mapped leaves the buffer owned by both the PSYS handle and the exported dma-buf, so closing the two is a use-after-free and a double free, and UNMAPBUF drops its mapping reference before clearing the attachment, racing a concurrent dma-buf release. Any account that can open /dev/ipu7-psys0 can reach both.

Nothing but v4l2-relayd@ipu7, which runs as root, opens the node; applications use the v4l2loopback device. With the node at 0600 root:root the camera streams the same, so the video group and the seat user lose nothing and the bugs need root. GROUP and MODE are explicit so the upgrade's change event also tightens nodes on running machines.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Drop the DKMS Intel CVS driver now that linux-omarchy ships it

linux-omarchy and linux-omarchy-bore build drivers/media/i2c/cvs in-tree (CONFIG_VIDEO_INTEL_CVS=m) and carry the same wake-IRQ fix as our 0007 (0542), plus the Nova Lake ACPI ID (0541) that our copy lacks. The DKMS module has the same name and installs under updates/, so on every 7.2+ kernel it displaced the kernel's signed module with an unsigned, older copy: on Nova Lake that copy cannot bind the CVS device and the camera fails, and any later fix in the kernel's driver would be masked. Krzysztof Wilczyński reported the conflict on #723.

Skipping the build only on kernels that carry the driver (BUILD_EXCLUSIVE_CONFIG) would have kept it for stock Arch kernels, but the pacman dkms hook reports every such skip as "exited 77", so every Omarchy kernel update would print a warning. A stock Arch kernel left installed as the fallback boot entry now has no camera.

On upgrade the dkms hook removes intel-cvs and restores the kernel's original module. vision-drivers still covers kernels before 7.2.

* intel-ipu7-camera: build the Lunar Lake HAL plugin and stop rotating its frames

Two Panther Lake assumptions in this package break Lunar Lake boards, where it
is installed by the same hardware detection.

Build both HAL platforms. libcamhal picks its plugin by platform, and a Lunar
Lake machine asks for one that was never built:

  CamHAL[ERR] HalAdaptor: load_camera_hal_library, failed to open library:
    /usr/lib/libcamhal/plugins/ipu7x.so: No such file or directory
  CamHAL[WAR] CameraParserInvoker: parseSensors: No sensors available

so the camera cannot work at all. The proprietary side of it is already
shipped -- libia_aic-ipu7x.so and the rest of that set come from
ipu7-camera-bins today; only the plugin the HAL loads was missing. Upstream
builds both platforms from one configure run and `make install` lays down
/etc/camera/ipu7x/ alongside ipu75xa, including the tuning this hardware
wants (OV08X40_BBG802N3_LNL.aiqb, gcss/OV08X40_BBG802N3_LNL.IPU7X.bin), so the
change is the IPU_VERSIONS list plus 0008, the ipu7x twin of 0006: the
"Intel CVS" pad formats that 1.0.6 added to the ipu75xa sensor config are
needed in the ipu7x one for the same reason, or link validation fails at
stream-on behind the Linux 7.2 bridge entity.

Pick the relay pipeline per board. v4l2-relayd-ipu7.conf rotates every frame
180 degrees, which is right where the sensor is mounted inverted and wrong
here: the sensor reports camera_sensor_rotation = 0 and camera_orientation =
Front, and the picture arrives upside down in every application. camera-init
now writes VIDEOSRC to /run based on the bridge ACPI id and the relay drop-in
reads it. Only INTC10DE takes the new path; INTC10E1, INTC10CF, INTC10E0 and
anything unrecognised keep the packaged pipeline byte for byte, and a boot
where camera-init did not run falls back to it as well.

Verified on a Dell Pro 14 Premium PA14250 (Lunar Lake, INTC10DE, OV08X40 +
HM1092) against intel-ipu7-camera 1.0.6-2 on linux-omarchy 7.2.5-3: with the
package's own intel-cvs DKMS the sensor joins the graph behind "Intel CVS",
the ipu7x plugin built from the pinned commit with 0005 and 0008 resolves
ov08x40-uf on CSI port 0, v4l2-relayd streams 30 fps to /dev/video50 and the
image is upright in a browser.

Note for reviewers: necessary but not sufficient on Lunar Lake. Three more
things this board needs are not in this PR: the sensor probe races the
bridge's runtime suspend (camera-init's `sleep 2` lands while the I2C bus is
still owned by the bridge firmware and ov08x40 reads its chip id as -110),
the in-tree cvs driver's quirk for the Synaptics SVP7500 (06cb:0701) hands
the privacy LED to the host so it never lights, and ipu-bridge before 7.3
does not know the HM1092 IR sensor. Details in #366.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 9be51b47104da9d115a7d79e04bc2ae5445809fc)

* Derive the Lunar Lake relay pipeline from the packaged one

camera-videosrc-init wrote VIDEOSRC for every board, with a copy of the pipeline the relay config carried when it was written, and its file is read after /etc/v4l2-relayd.d/ipu7.conf. On Panther Lake that replaced this branch's fps-range, gain-range and color-range settings with the old sharpness=80 ev=-1 saturation=10 pipeline. It now writes nothing unless the board is Lunar Lake, and there it takes the packaged pipeline and drops only the rotation, so a later change to the relay config reaches both platforms. It also removes a file left by an earlier run, which camera-init's restart on resume would otherwise keep.

The ipu7x CVS format patch becomes 0012: 0008 is already the YUV range patch.

* Regenerate the Lunar Lake pipeline on every relay start

camera-videosrc-init ran from camera-init.service and sourced /etc/v4l2-relayd.d/ipu7.conf as bash. A config that is valid for systemd but not for bash, such as an unquoted VIDEOSRC, made it fail and Lunar Lake fell back to the rotated pipeline; and because camera-init stays active, editing the config and restarting only the relay kept the override cached since boot.

It now runs as the relay's ExecStartPre, where systemd hands it VIDEOSRC already parsed from the relay's own environment files, and writes the override quoted for systemd's parser. ExecStart re-reads the drop-in's EnvironmentFile and ExecStopPost removes it, so each start sees the current config.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Scale the Lunar Lake ov08x40's analog gain codes too

The Lunar Lake tuning (OV08X40_BBG802N3_LNL.aiqb) carries the same CMC gain table as the Panther Lake one, 1x = code 256, and both platforms use the same in-tree ov08x40 driver, which takes 1x = 128. Without the shift a 4x request ran the Lunar Lake sensor at 8x, the mismatch 0010 fixes on Panther Lake. 0010 now sets analogGainCodeShift in the ipu7x sensor config as well.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Remove the Lunar Lake override before the generator runs

systemd passes ExecStartPre the unit's environment files as they stand when
that command starts, so the generator saw a /run override left behind by a
crash or SIGKILL (anything that skipped ExecStopPost) and took its VIDEOSRC
for the configured one: an edited /etc/v4l2-relayd.d/ipu7.conf would lose to
the stale file. Removing the file in its own ExecStartPre first means the
generator's environment is re-read without it.

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Author the HAL and icamerasrc patches from the Omarchy address

---------

Signed-off-by: Afonso Oliveira <afonso.oliveira707@gmail.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Co-authored-by: Afonso Oliveira <afonso.oliveira707@gmail.com>
Co-authored-by: Kolbas <pkolbas@pm.me>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 21:27:53 -05:00
eee77d5a38 voxtype-bin: update to 1.1.0 (#640)
* voxtype-bin: update to 1.1.0

Ship the signed 1.1.0 release assets, baseline and ARM binaries, and the complete Quickshell and OSD style trees. Add OpenVINO optional dependencies from #526 and select the baseline binary automatically on pre-AVX2 hosts.

* voxtype-bin: bump pkgrel past the published 1.1.0-1

voxtype-bin 1.1.0-1 is already published to edge, rc and stable from master's upstream sync. This branch changes that package's contents (baseline binary, OSD styles and recipes, the install hook, OpenVINO optdepends) without changing its version, so publish.yml would call it already published and skip it, and publish-artifact refuses different bytes under an existing filename. pacman would not offer it as an upgrade either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* voxtype-bin: list accelerator optdepends for x86_64 only

makepkg appends optdepends_$CARCH to optdepends rather than replacing it, so optdepends_aarch64 did not drop the Vulkan, CUDA, ROCm and MIGraphX entries on aarch64: it listed all sixteen shared ones and then eleven of them a second time. The accelerator runtimes move to optdepends_x86_64 beside the OpenVINO ones, and the aarch64 array goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* voxtype-bin: move pre-AVX2 hosts to the baseline build on upgrade

The baseline pick in _set_default_backend only runs when no backend was saved, which is a fresh install. Every release before 1.1.0 gave a CPU without AVX2 voxtype-avx2, and pre_upgrade saves that path, so post_upgrade restored the build the host cannot run and the machines the baseline binary exists for never reached it. A saved AVX2 or AVX-512 build whose instruction set the CPU lacks is now picked again; GPU and ONNX choices are left alone.

tests/voxtype-bin-install.sh covers the fresh-install pick and the upgrade cases, and runs with the other self-tests. It borrows the hook's fixed /tmp/.voxtype-backend-upgrade, so it refuses to start when anything is already there, a dangling symlink included: CI runs it as root, and writing through a planted link would land outside the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>

* tests: keep voxtype-bin-install's upgrade state out of /tmp

The test borrowed the hook's /tmp/.voxtype-backend-upgrade and checked it was free only once, so a real voxtype-bin upgrade writing its state during the run could have that state overwritten or deleted, and the hook would then lose the user's backend. The test now redefines the sourced _preserve_or_set_backend with the path moved into its own directory, and fails outright if the hook stops using that path rather than passing without reading it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>

* tests: never parse voxtype-bin-install's temp path as code

The redefined _preserve_or_set_backend went through eval with the mktemp path pasted in, so a TMPDIR holding shell syntax -- a directory named $HOME, or $(...) -- was expanded or run when the function was called. It now carries a reference to $SAVED, which expands to the path only at run time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>

---------

Co-authored-by: Spencer Bull <spencer@omarchy.org>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
2026-09-27 23:55:23 -05:00
Marcelo Alcantara e0eb841a2e omarchy-settings: ship the full set on aarch64 for runtime-profile sources
A source with default/settings-runtime-profile decides at runtime which
platform-specific files apply, so its aarch64 package now gets the same files,
backup and optdepends as x86_64: the Thunderbolt request and the memory stack
stay, and its HOOKS files ship as they are. The check that a Mac's asahi line
survives still runs on every aarch64 build. Older sources, including the pinned
v4.0.4, keep #380's aarch64 package: Thunderbolt removed, the HOOKS line guarded
for asahi, the memory stack stripped. The keyboard backlight unit first-run
enables ships whenever the source has it.

pkgrel 4 so the recipe change builds: edge already holds 4.0.4-3 on both
architectures. The payload built from v4.0.4 is unchanged.
2026-09-28 13:17:22 +10:00
Ryan Hughes 7abad3786d Plan PR builds from the PR's own files, not a diff to master's tip
The planner took 'git diff base.sha head.sha', a two-dot diff between
the current master tip and the PR head. For a PR that branched before
later merges, that counts every package master has changed since, so
the PR plans those too and builds its own stale copies of them: wasted
builds, and 'already up to date' Pack failures that turn the PR red for
packages it never touched. #397 (lazyjournal) planned 22 packages for a
one-package change. The checkout is shallow, so ask GitHub for the PR's
files, which are listed against the merge base.
2026-09-27 21:45:40 -04:00
Ryan Hughes aa143d79b7 Stop the PR overlay preview failing stale PRs with SIGPIPE
'git status --short | head' under set -o pipefail: once the PR's
pkgbuilds/ differs from base in more than ten files, head exits, git
takes SIGPIPE and the step fails with 141 before anything builds. Every
PR branched far enough behind master hit it (omadev #423, llmman-bin
#428 and others on 2026-09-28). sed -n '1,10p' prints the same preview
and drains the stream.
2026-09-27 21:36:12 -04:00
Marcelo Alcantara 6eb4ad1a85 Merge pull request #380 from jdvmi00/spark/aarch64-settings-boot-dropins
omarchy-settings: keep the Limine and mkinitcpio drop-ins on aarch64
2026-09-28 11:29:04 +10:00
Ryan Hughes 31b10abd75 Merge pull request #663 from omacom/ci/sync-pr-churn
Keep sync PRs building across bot pushes
2026-09-27 20:07:45 -04:00
Marcelo Alcantara 919b084b93 Merge remote-tracking branch 'upstream/master' into spark/aarch64-settings-boot-dropins 2026-09-28 07:42:17 +10:00
Marcelo Alcantara 97bcb320ab Rebuild aarch64 natively when publish finds no artifact
A merged aarch64 tree without a PR build artifact (expired after 7 days,
or a dispatch) was rebuilt on the x86 droplet under QEMU: omarchy-mac-boot
took ~167 of the 240 minutes. A new job builds it on ubuntu-24.04-arm the
way build-pr.yml does and uploads it under the same label, so the publish
job signs and uploads it on the droplet like a PR artifact. The plan logs
reuse or rebuild for every package; x86_64, signing and the publish
concurrency are unchanged.
2026-09-28 06:41:39 +10:00
David Heinemeier HanssonandClaude Opus 5.5 7552b8be49 Skip packages a PR deletes when planning PR builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 12:21:37 -07:00
Ryan Hughes 13ed2e9f8d Use the existing controller PAT for branch tracking 2026-09-27 12:39:53 -04:00
Ryan Hughes 7fe542cde7 Keep branch syncs together and simplify tracker setup 2026-09-27 12:39:53 -04:00
Ryan Hughes d87686ca4f Track upstream branches as pinned releases on an unattended lane
Since publishing moved to CI on merge, a package whose PKGBUILD never
changes while its source moves was never rebuilt: omarchy-dev and
omarchy-settings-dev followed quattro through "#branch=" and a pkgver()
function, and nothing in this repository changed when quattro did. The
host timers that used to notice are off, so edge fell days behind.

The rule now: no git source without a commit or tag pin
(tests/pinned-sources.sh, run in CI). A package that has to follow a
branch declares a git_branch upstream watch, and the pin moves through
the same PR/build/publish path as every other version bump.

Watch (helpers/upstream-watch.py)
  git_branch gains tag_pattern: the newest release tag in the pinned
  commit's own history, exposed as {tag}/{version}/{distance}, so a
  branch build is versioned <tag>.r<n>.g<sha>, above the release it
  follows and below the next one. One blobless clone per branch per
  run, shared by every package on it. min_release_age selects the
  newest commit older than the window, so a push burst builds once.

Lane (helpers/package-metadata.sh, bin/sync-upstream --lane)
  "auto_merge": true moves a package from the reviewed 6-hourly sync
  PR to the unattended lane. Packages pinned from the same branch move
  together: a failure on one restores the others and fails the group,
  so the dev pair can never ship from two quattro commits.

Tracker (.github/workflows/track-branches.yml)
  Every two hours: pin, open one PR with a GitHub App token, enable
  auto-merge. Branch protection still gates the merge on result,
  self-tests and build-isolation. A tip that fails to build stays an
  open red PR until the next tick supersedes it. The App is required:
  a PR opened with GITHUB_TOKEN has its checks held for approval and
  its auto-merge would not fire publish.yml.

The reviewed workflows (sync-upstream, sync-rebuilds) open their PRs
with the same App so their builds start without a maintainer clicking
"Approve workflows to run"; without the App they fall back to
GITHUB_TOKEN and behave as before.

Recipes
  The dev pair pins _commit and a real sha256sum, keeps the OMARCHY_SRC
  override, and drops pkgver(). Its r-number stays the branch's total
  commit count because the published history used it and pacman must
  never see the version go down. omasnap-git is new: omacom/omasnap
  main, versioned <tag>.r<distance>.g<sha>, provides/conflicts omasnap.
2026-09-27 12:39:53 -04:00
Marcelo Alcantara 2ff4dda480 Match the runner comments to the measured times 2026-09-28 00:30:33 +10:00
Marcelo Alcantara ee001efd34 Build every aarch64 package natively
Native pilots of the heavy packages fit the arm64 runner: linux-aurora 30
minutes, strata 17, obs-studio 7, with over 90 GB disk free throughout.
2026-09-28 00:24:12 +10:00
Marcelo Alcantara 7c646625c2 Build aarch64 PR packages natively on GitHub's arm64 runners
The droplet pool is x86, so aarch64 builds ran under QEMU about 30x slower;
omarchy-mac-boot's check() took 2h47m of the 180-minute job limit. Heavy
packages stay on the droplets until a native build of each is shown to fit.
2026-09-27 23:44:28 +10:00
bjarneoandBjarne Oeverli c62e9d70fe Upload meson test logs when a package build fails (#661)
makepkg runs check() inside the build container and meson writes each
test's output to the build tree, not to stdout. A failing test therefore
leaves only a summary line in the job log. Diagnosing it means reading
the package source and inferring the cause.

bin/build bind-mounts $SRC_DIR at /src, so the logs outlive the
container at src/**/meson-logs/ on the runner. Upload them when the
build step fails.

owe 0.2.7 showed the cost: owe:transition failed on aarch64 and passed
on x86_64, and CI carried no record of which assertion tripped.

Co-authored-by: Bjarne Oeverli <1419214+bjarneo@users.noreply.github.com>
2026-09-27 08:50:59 +02:00
Ryan Hughes 4aca3bdbc7 Keep sync PRs building across bot pushes
Three things kept the upstream sync PR (#589) from ever finishing a build:

Scoped dispatches wiped the shared PR. A workflow_dispatch with `packages`
regenerates only those packages from master, and pushing that to
auto/sync-upstream replaced 38 pending updates with one. Scoped runs now
push to their own auto/sync-{upstream,rebuilds}-<packages> branch and PR;
scheduled runs keep the shared branch.

build-approved stopped working after the first bot push. A GITHUB_TOKEN
push creates pull_request runs held for approval but no pull_request_target
run, so approve-pr.yml never saw it: its last run on the branch was the
label itself (2026-09-25T19:26), and each of the next four syncs sat at
action_required. The sync workflows now release the held runs for the
commit they just pushed, from a separate job holding actions: write, and
only for their own bot-authored, same-repo PR while build-approved is on
it.

Each approved push cancelled the in-flight build. Approving the 21:43
sync's build cancelled the label-triggered one still queued on strata and
schist-bin. On auto/sync-* branches a new build now waits for the running
one instead, then reuses its artifacts. The approval script no longer
waits for a lone approved build to start before releasing tests, which a
queued build would have turned into a timeout.
2026-09-26 20:01:17 -04:00
Jim Martin 9d05b3fb06 Merge remote-tracking branch 'upstream/master' into spark/aarch64-settings-boot-dropins 2026-09-26 17:38:24 -05:00
Ryan Hughes d9748c6a15 Merge current package defaults into clipboard fix 2026-09-25 15:35:16 -04:00
Marcelo Alcantara baf6df3e80 limine-mkinitcpio-hook 1.39.0-2: Apple Silicon activation gate on aarch64
On aarch64 the Limine hooks and the mkinitcpio wrapper run through
limine-apple-gate. Only an Apple Silicon Mac (device tree "apple,")
behaves differently: Limine's kernel and removal hooks wait until
Omarchy activates Limine (/var/lib/omarchy/limine.enabled and
/etc/default/limine), mkinitcpio's own kernel hook keeps /boot current
before and after activation, Limine's EFI deploy hook is left to
omarchy-mac-boot, and the wrapper is plain mkinitcpio. Skipped hooks
drain the socket pacman streams targets over.

x86_64 packages exactly what 1.39.0-1 did; generic aarch64 and
Snapdragon keep upstream behaviour.
2026-09-25 18:20:07 +10:00
Jim Martin 19976635bc Merge remote-tracking branch 'upstream/master' into spark/aarch64-settings-boot-dropins
# Conflicts:
#	.github/workflows/test.yml
2026-09-22 18:35:30 -05:00
Ryan Hughes e0959b06f5 chore: vouch for tcballard and DanWahlin 2026-09-21 15:26:43 -04:00
Ryan Hughes c74c708f35 Reuse existing build artifacts when a PR's package tree is unchanged
Every push to a PR rebuilt every package the PR touches, on every
architecture, even when only one of them changed. The daily sync PR
carries around thirty package/arch pairs; fixing one package meant
rebuilding all of them, and an aarch64 build under QEMU takes up to an
hour. Nine runs of that PR cost about 36 droplet-hours in two days.

The planner now asks the artifact store for <pkg>-<arch>-<tree hash>
before adding an entry to the matrix and drops entries that already
have one. That is the same lookup publish.yml makes on merge, so a
reused entry publishes exactly the file it would have anyway. Dry run
against the current sync PR: 27 of 31 entries reused, 4 built.

Pack and Upload no longer run with always(): only a successful build
uploads, so an artifact's existence means that tree built.

workflow_dispatch always builds; it is an explicit request.
2026-09-20 21:09:55 -04:00
Ryan Hughes 4b60e4cd95 Merge pull request #551 from omacom/ci/daily-builder-images
Publish tested daily package builder images
2026-09-20 13:49:44 -07:00
Ryan Hughes 2c22669d65 Build PR tooling from the base branch tip, not the event's base sha
github.event.pull_request.base.sha is a snapshot taken when the PR was
last pushed, not the current tip of the base branch. A reopened or rerun
PR therefore builds with whatever master looked like at its last push,
and a tooling fix that landed on master since then never reaches it:
the daily sync PR reopened after #553 merged checked out a base without
helpers/artifact-helpers.sh and failed at "Pack artifact".

Check out base.ref instead. The plan's diff and the empty-PR check still
compare base.sha to head.sha, so the list of changed packages is
unaffected; only the tooling that runs on the droplet moves to the tip.
2026-09-20 16:40:23 -04:00
Ryan Hughes 124b067694 Carry PR build artifacts inside a tar so epoch package names survive
actions/upload-artifact rejects any path containing ':', and makepkg names
a package with an epoch `name-1:ver-rel-arch.pkg.tar.zst`. Every PR that
built such a package (cursor-cli in the sync PRs, omasnap once it gained an
epoch) failed at "Upload artifact" after a successful build, and publish
then rebuilt from scratch on merge.

The files now ride inside packages.tar for the artifact hop and come back
out with makepkg's names untouched: pacman clients and bin/publish-artifact
both require the filename to match PKGINFO, and the channels already carry
these names. publish.yml still accepts bare pre-packing artifacts until the
7-day retention drains them.

helpers/artifact-helpers.sh holds both halves; tests/artifact-helpers.sh
covers the round trip and runs with the other self-tests.
2026-09-20 15:52:02 -04:00
Ryan Hughes 30af71af24 Validate proposed builder images on both native architectures 2026-09-20 15:41:27 -04:00
Ryan Hughes ad328b725d Build and test daily package builder images 2026-09-20 15:36:18 -04:00
Ryan Hughes 158133f15a Keep unapproved PR builds pending instead of failing 2026-09-20 02:31:44 -04:00
Ryan Hughes 3628915c5d Make build-approved release pending PR workflows 2026-09-20 02:11:34 -04:00
Ryan Hughes 72e8b2b3bb Add maintainers to the vouched contributors list 2026-09-19 18:48:53 -04:00
fbfbda4eca Package Omawake 0.0.3 and Omaspeak 0.0.3 with service-removal cleanup hooks (#503)
* Package Omawake 0.0.3 and Omaspeak 0.0.2

Bump both -bin packages to the model-support roadmap delivery:

Omawake 0.0.3:
- W02-W05 setup/activation/cache gates audited and closed
- W07 pinned catalog URL health checks and import diagnostics
- W08 Moonshine Small/Medium benchmarked; both deferred (Tiny default)
- W09 Spanish wake profile (multilingual Whisper Base INT8, es)
- W10 connection-owned playback pauses (HoldPause)

Omaspeak 0.0.2:
- S09 Kokoro 82M: Kokoro-capable packaged provider (supertonic;kokoro_tts)
  with espeak-ng-data.bin shipped beside the executable, 54 named voices
- S10 catalog URL checks, Spanish speech profile, consistent status shape
- S07 streaming deferred at the current pin

Upstream: omawake v0.0.3, omaspeak v0.0.2 (aarch64 + x86_64 verified on
promaxgb10-d666 CUDA and local NPU installs).

* omaspeak-bin: install espeak-ng-data.bin beside the packaged library

* omaspeak-bin: bump to 0.0.3-rc.1 (catalog-managed eSpeak data)

- The tarball no longer ships espeak-ng-data.bin: the Kokoro catalog row
  pins the data package as a model asset (downloaded/verified/installed
  into the model directory with the GGUF), so the core package ships no
  model data at all.
- Both arch checksums taken from the v0.0.3-rc.1 SHA256SUMS.txt.

* omaspeak-bin: finalize at 0.0.3

* Stop setup-created Oma services before pacman removes their binaries

* Drop stale release-verification fixtures from the branch

These were swept in by git add -A during the version bumps: packaged
copies of old releases (0.0.1 tarballs and extracted trees, ~80 MB)
belong to the local verification workflow, not to the package repo.
The consolidated upstream PR should carry only the package changes,
hooks and the removal regression suite.

* Update removal-test fixture versions to the packaged finals

* Ask systemd to reset only an Oma unit that actually failed

The removal helper reset the failed state of every unit it stopped, but
systemd accepts ResetFailed for a unit that is in the failed state alone.
For any other state it answers that the unit is not loaded and exits
non-zero, and because the helper runs under errexit while the hook aborts
on failure, a healthy unit then aborted the whole transaction:

  (2/2) Stop and remove omaspeak user services before package removal
  Failed to reset failed state of unit omaspeak.service: Unit omaspeak.service not loaded.
  :: Could not clean up omaspeak for jacob; removal aborted.

That is the ordinary case, as the packaged service ships disabled and an
enabled one is commonly stopped rather than failed. Read the active state
after the stop and ask for the reset only where it applies, so a failed
unit still loses its failed state along with its rate and restart counters
while a clean unit no longer fails the removal. A reset that a reachable
manager still refuses stays fatal.

Model the rule in the removal suite, where reset-failed now follows the
active state the way a real manager does, and cover both outcomes: an
inactive unit must not be asked for, a failed one must be reset between
the stop and the disable, and a refused reset must still fail the hook.

* Keep removal cleanup faithful to how systemd reads configuration

Both defects from the review of e025111 sat in the shared package-remove
helper, so both packages were affected the same way.

An offline user's drop-in was recognised by grep '^ExecStart=', while the
configuration parser throws away the whitespace around an assignment
(parse_line() strips the line and both halves of the assignment).  A drop-in
naming a development build as

  ExecStart =
  ExecStart = /home/alice/build/omawake daemon

therefore went unmatched, and the helper cleared away the generated base unit
beside with its enablement links, right behind a service that was never meant
to be the package's.  Match an assignment the way the parser accepts one.  The
gate that decides whether a unit file is the generated one stays strict on
purpose: only the exact generated shape is ever deleted.

systemctl show-environment also prints every value the way a shell would read
it, through shell_maybe_quote(SHELL_ESCAPE_POSIX), so an XDG_CONFIG_HOME with a
space arrives as $'/home/alice/custom config'.  The XDG_CONFIG_HOME=/* case saw
neither form and kept the home's .config directory quietly, leaving the unit in
the directory the manager really reads pointing at the removed binary.  Decode
that quoting character by character, without letting the text become shell
syntax, and refuse a value that is neither a plain path nor a closed $'...'
quote rather than delete what would have to be guessed at.  A value that is not
an absolute path stays the fallback it is in systemd itself.

The fixtures now hand the helper the very text a manager prints, quoted by a
mirror of that printer, and cover a quoted path with a space, an apostrophe and
a backslash, an unreadable quoted value, a relative one, and each spacing of an
offline override.  Verified with the removal suite, 15 tests; the eight new
assertions fail against the helper as it was.  The other suites were not run
here, as they reach for the network.

pkgrel 3 -> 4 and the helper's checksum, in both recipes.
Reported-by: spencerbull

* Decode systemd control escapes during service removal

systemctl C-escapes control bytes in show-environment output. Rejecting those valid values aborted package removal for every user, even when the affected account had no Oma service. Decode the printer’s named and octal escapes without evaluating shell syntax or stripping trailing newlines, and cover the real printer format in the fixtures.

Co-Authored-By: GPT-6 XHigh <noreply@openai.com>

---------

Co-authored-by: Spencer Bull <spencer@omarchy.org>
Co-authored-by: GPT-6 XHigh <noreply@openai.com>
2026-09-18 20:32:11 -05:00
Ryan Hughes 868f2a1e18 Tests: note that publish, not strict protection, guards the merged tree 2026-09-18 18:46:54 -04:00
Ryan Hughes da4e1b55a8 Publish report: no PR comment on dispatch runs; append the log before commenting
A workflow_dispatch runs from master's head. That commit's PR merged
something unrelated, so looking the PR up by commit attached a failed
elsewhen report to #515, whose merge had nothing to do with elsewhen.
Dispatch runs now go to the log only. The log append also moves ahead
of the PR comment so the record exists by the time anyone follows the
comment to it.
2026-09-18 18:07:43 -04:00
Ryan Hughes a24c56cd52 Dispatch: a package already published at master's version is a no-op, not a failure
Re-running publish for a package that is already live (a dispatch for
something that turned out fine, or a retry after a partial failure) made
bin/build report nothing to build and exit 2, which the publish step
treated as an error. The collect step now dry-runs first: if the channel
already holds master's version the package is recorded as
already-published and skipped, and a run where every package is in that
state exits cleanly with a record saying so.
2026-09-18 14:01:07 -04:00
Ryan Hughes 4717cfec4e Publish record covers build failures, and says where each package came from
When a package had no PR artifact and its build failed, the publish
step never ran, no record was written, and the report job failed
looking for it. The collect step now records each package's source
(PR artifact, built here, or build-failed) and writes the record itself
when a build fails, so the report can say plainly that nothing was
published and why.
2026-09-18 13:39:56 -04:00
Ryan Hughes 54685a55a1 PR check fails when the PR changes no files relative to its base
A PR whose diff against its base is empty has already landed some other
way, typically a sync PR carrying the same bump or a merge from master
that swallowed it. Merging it records a change that isn't one and could
mask a real mistake. result now fails with a message saying to close it.
2026-09-18 12:55:18 -04:00
Ryan Hughes 902f6d3da9 Report each publish: comment on the merged PR, append to a JSON log in the bucket
The publish job now writes publish-record.json describing every
channel/architecture slot it touched: the packages, whether the slot was
published or failed, the target (live or a proof prefix), the commit and
the run. A report job renders that as a comment on the PR the merge
commit came from (looked up by commit, so squash and rebase merges work)
and appends the record as one line to publish-log.jsonl in the bucket,
served next to the packages at https://pkgs.omarchy.org/publish-log.jsonl.
Failures are reported too, with the slots that landed before the failure,
which is when a human most needs to know.
2026-09-18 12:42:47 -04:00
Ryan Hughes 5a701be9d1 PR plan job: bootstrap when the base branch has no bin/build-matrix yet 2026-09-18 11:46:50 -04:00
Ryan Hughes 537c377fa5 Build PRs on ephemeral droplets; publish merged packages from CI
Every pull request now builds the package directories it touches on
ephemeral DigitalOcean droplets, and every merge to master publishes the
resulting artifacts into the channels each package belongs to. The
repository host's timers become the fallback rather than the pipeline.

Build (.github/workflows/build-pr.yml)
  One job per package per architecture, always against edge. The artifact
  is labelled with the package directory's git tree hash. Tooling (bin/,
  helpers/, build/) is checked out from the base branch; the PR supplies
  only pkgbuilds/, so a PR can change what is built, never how. Builds
  run only for trusted authors: collaborators, .github/VOUCHED.td, or a
  PR carrying the build-approved label. A single required check, result,
  aggregates the matrix.

Publish (.github/workflows/publish.yml, bin/publish-artifact)
  One job per merge. It collects the PR artifacts for the merged tree,
  builds anything that has none, then walks each channel/architecture
  slot once: pull that database, repo-add every package that belongs in
  it, upload packages, signatures, then the database. A published
  filename is immutable; identical bytes under an existing name only
  gain a database entry, different bytes are refused. Fast-ring packages
  reach edge, rc and stable in the same run from the same file.

Matrix (bin/build-matrix)
  Package x architecture, with the channels the artifact ships to,
  decided by package_builds_for_mirror so CI and the host agree.
  arch=any packages build once and land in every architecture database.

Builder (build/build.sh, bin/build, build/Dockerfile)
  With no local published tree, plan against and resolve from the public
  channel over HTTPS. PACKAGER is set to Omarchy. rclone is in the image.

Runners (ci/)
  A controller droplet polls GitHub with curl and creates one g5 droplet
  per queued job from cloud-init, deleting them when off or over-age.
  Builders carry QEMU with credential support for aarch64. Operator SSH
  keys come from GitHub. tests/controller.sh and tests/publish-artifact.sh
  cover the decisions against fixtures and real makepkg output.

Tests run on pull requests only; branch protection requires result,
self-tests and build-isolation with up-to-date branches.
2026-09-18 11:25:32 -04:00
Basti b422d37fa2 Drop privileges when seeding Dell haptic config (#497)
The root-run package hook changed ownership of paths below a
user-controlled home directory. A config symlink could redirect chown to
an arbitrary root-owned file during installation or upgrade.

Run the config writer as the target desktop user and remove the privileged
ownership changes. This also prevents the missing-config path from writing
through a user-controlled pathname as root. Add regression coverage and
bump the package release.

Reported-by: piratemoo (Esther) <22439214+piratemoo@users.noreply.github.com>
Link: https://github.com/piratemoo/Arbitrary-File-Ownership-Change-via-Symlink-LPE
2026-09-18 15:24:41 +02:00
Birk Skyum 16b1a730f6 Run boot settings regression explicitly from tests 2026-09-16 20:54:59 +02:00
Birk Skyum 203b7340ab Test packaged boot settings on ARM and x86_64
Exercise both settings recipes with synthetic runtime files. Check the exact Limine templates, boot drop-ins and backup metadata, installer-owned configuration, notifier copies and architecture-specific Thunderbolt handling. Run package regressions in the existing self-test job.
2026-09-16 20:37:43 +02:00
Ryan Hughes 9d5c3eea19 Skip retained published archives when planning builds 2026-09-15 00:13:57 -04:00
Ryan Hughes b34de5c29e Replace scheduled AUR imports with direct upstream watches 2026-09-14 21:15:17 -04:00
Ryan Hughes d96b950901 Publish completed packages when a peer build fails 2026-09-14 02:30:11 -04:00