Builds the webOS Homebrew Channel ipk from our own mirrors
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Owen Phillips 7ae90fa203
fix: serialize index updates and make publishing re-runnable
Two runs updating the index at once could each list the releases
before the other's existed, so the last upload dropped the other's app,
and both deleting before either uploaded left two apps.json assets.
release.yaml and app.yaml now share a `publish` concurrency group, so
runs queue instead of overlapping.

Publishing moves to scripts/publish-release.sh, shared by both
workflows. A release that lacks any of this run's files (an upload
failed half-way) now has its assets replaced instead of being kept
broken forever, a failed create stops the step, and a new tag is
created at the commit that was built rather than at mainline.

update-index.sh fails if the release it was called for has no ipk
asset, instead of leaving it out of the index silently, and matches
that tag exactly.

build-app.sh now applies apps/<app>/patches and packs the source
tarball before the build, so a local build matches CI and the tarball
holds the source as built, without build output. It reads appinfo.json
from usr/palm/applications/<id>/ only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 03:43:04 -07:00
.forgejo/workflows fix: serialize index updates and make publishing re-runnable 2026-10-25 03:43:04 -07:00
apps fix: serialize index updates and make publishing re-runnable 2026-10-25 03:43:04 -07:00
patches fix: disable dropbear password auth via a generic patch mechanism 2026-10-25 02:49:24 -07:00
scripts fix: serialize index updates and make publishing re-runnable 2026-10-25 03:43:04 -07:00
README.md fix: serialize index updates and make publishing re-runnable 2026-10-25 03:43:04 -07:00

webos-homebrew-channel-builder

Builds the webOS Homebrew Channel .ipk, and the apps in apps/, from our own mirrors and publishes them as releases here.

Nothing is fetched from GitHub at build time. If upstream disappears, the build still works.

Inputs

All are pull mirrors in https://git.owenap.com/webos (keep "Remove obsolete remote-tracking references" off so deleted upstream refs survive):

Mirror Upstream
webos-homebrew-channel webosbrew/webos-homebrew-channel
enyo, moonstone, spotlight, layout, svg, enyo-ilib, enyo-webos enyojs/* (the submodules)

The workflow rewrites https://github.com/enyojs/ to the mirror with a git insteadOf rule. No patch to upstream is needed.

The apps each have one mirror more, listed under Apps.

Release

Actions -> release -> Run workflow, with an upstream tag such as v0.7.3. Or push that tag to this repo.

Rebuilds

To publish a change in patches/ for an upstream version that is already released, add a 4th number: v0.7.3.1, v0.7.3.2, ... (up to .999). That builds upstream v0.7.3 with the current patches and publishes it as release v0.7.3.1.

The app on the TV shows "Update" when the version in the index differs from the installed app's version. ares-package only accepts x.y.z, so the rebuild number goes into the last part. Rebuild N of 0.7.3 gets app version 0.7.3NNN, so v0.7.3.1 is app version 0.7.3001 and v0.7.3.12 is 0.7.3012. The TV shows that version. A rebuild of an x.y.0 release is refused, because its app version would be the same as upstream's x.y.N.

Each release carries:

  • org.webosbrew.hbchannel_<app version>_all.ipk
  • org.webosbrew.hbchannel.manifest.json
  • webos-homebrew-channel-<release tag>-source.tar.gz (source plus submodules)
  • SHA256SUMS

The release notes list this repo's commit, the upstream commit, every submodule commit and the app version.

Running the workflow again for a release that already exists keeps it as it is. If the release is missing any of its files (an upload failed), the run replaces all of its assets with its own build instead.

release and app runs go one at a time (a shared concurrency group), so two runs never write the index at once. A run waits while another is going.

Apps

The Jellyfin clients and YouTube AdFree from repo.webosbrew.org, each built by .forgejo/workflows/app.yaml from a pull mirror in https://git.owenap.com/webos:

App apps/ Mirror Upstream
Breezyfin breezyfin Breezyfin botagas/Breezyfin
Jellyfin jellyfin jellyfin-webos jellyfin/jellyfin-webos
Litefin litefin litefin MoazSalem/litefin
Moonfin moonfin Smart-TV Moonfin-Client/Smart-TV
OcenFin ocenfin OcenFin seluce/OcenFin
YouTube AdFree youtube youtube-webos webosbrew/youtube-webos

Actions -> app -> Run workflow, pick the app and enter its upstream tag (v1.2.2; Moonfin and OcenFin tag without the v: 2.10.0, 2026.10.19). Or push a tag <app>-<upstream tag>, such as jellyfin-v1.2.2. The release is tagged that way and carries the .ipk, <app id>.manifest.json, a source tarball and SHA256SUMS.

Each apps/<app>/ has:

  • app.conf: the mirror, the app id, and the icon the index shows.
  • build.sh: runs in the checked-out source with $VERSION and $OUT set and leaves one .ipk in $OUT. It follows upstream's own release workflow, minus lint and tests.
  • patches/*.patch, optional: applied before the build, as in patches/.

scripts/build-app.sh applies the patches, packs the patched source into the source tarball, runs build.sh, checks that the ipk's appinfo.json has the id from app.conf and the version of the tag, and writes the manifest. To build one locally the same way, CI included, check the source out into src/ and run, in node:22-alpine with apk add git curl jq tar coreutils binutils:

sh scripts/build-app.sh jellyfin v1.2.2

The apps have no rebuilds like v0.7.3.1: the tag must be an upstream tag, and the ipk's version must equal it. To ship a new patch for an app version that is already released, delete that release (and its tag) and run the workflow again.

Notes on single apps:

  • Litefin has several webOS builds. We build "webOS Legacy", the one upstream lists in repo.webosbrew.org.
  • OcenFin does not bump the version in git; build.sh sets it from the tag.
  • YouTube AdFree installs as youtube.leanback.v4, the stock YouTube app's id, so it replaces that app. Its ares-package is a GitHub fork that its lockfile pins by commit, so its pnpm install does fetch from GitHub.

To add an app, add apps/<app>/, its mirror, and the app to the options and tags lists in app.yaml.

Updates from our Forgejo

The app does not update itself from the manifest. It reads repository indexes (JSON lists of apps) and offers the version each one lists. The default index is repo.webosbrew.org, which follows GitHub.

Each release also refreshes our own index, which lists every app this repo builds. It is an asset of a release tagged index, because the job token cannot push to a branch:

https://git.owenap.com/oap/webos-homebrew-channel-builder/releases/download/index/apps.json

On the TV, open Homebrew Channel -> Settings -> Repositories -> Add repository and enter that URL. Turn off the default repository if you want only our builds. From a shell you can also run ares-launch org.webosbrew.hbchannel -p '{"launchMode":"addRepository","url":"<index url>"}'.

scripts/update-index.sh rebuilds the index from all releases of this repo each time, and lists the newest release of each app id, by release tag (v0.7.3.1 comes after v0.7.3 and before v0.7.4). Rebuilding an older tag does not move it back.

The release manifest is patched after the build: its icon and project page point at the mirror instead of GitHub. The .ipk is unchanged by this, because the manifest is not part of the package. The apps' manifests are written by scripts/build-app.sh and point at the mirror too.

Forgejo does not send a CORS header on release downloads, and the official index does. Check on a real TV that the app can load the index. If it cannot, add Access-Control-Allow-Origin: * for that path in the reverse proxy.

Notes

  • The repo must stay owned by oap. The Actions runner is scoped to oap's repos; an organization-owned repo gets no runner.
  • The job uses the docker runner label because npm ci runs third-party code. It is not byte-for-byte identical to upstream's published .ipk (build output differs slightly), but it has the same files.
  • The npm dependencies still come from the npm registry. They are not archived.