Personal fork of LawnchairLauncher/lawnchair
rebranded as it.belloworld.cadrega so it installs side-by-side with upstream.
One-click via Obtainium — open the link on your Android device and the app source pre-fills with the right release filter and package ID.
Nightly — daily, package it.belloworld.cadrega.nightly:
Beta — per upstream v*-beta* tag, package it.belloworld.cadrega:
Both channels install side-by-side. Manual APKs: Releases.
Hybrid Codeberg-source / GitHub-CI / Codeberg-release setup:
user push (tooling / cadrega-patches*)
│
▼
┌──────────────────────┐ push mirror (hourly)
│ codeberg.org │ ─────────────────────────► ┌────────────────────────┐
│ BelloWorld/cadrega │ │ github.com │
│ (source of truth) │ ◄───── release upload ───── │ drizzt/cadrega │
└──────────────────────┘ via forgejo-release │ (CI-only mirror) │
▲ │ Actions on, │
│ │ Issues/Wiki/PR off │
Obtainium polls └────────────────────────┘
Codeberg releases
(no IP rate-limit)
- Codeberg holds the source.
tooling,cadrega-patches, and anycadrega-patches-<major>branches are pushed here by hand. - GitHub is a one-way mirror kept in sync by Codeberg's Push Mirror feature. Issues, Wiki, Projects, Discussions, PRs are off. Actions is the only enabled surface.
- GitHub Actions runs the nightly + beta workflows on
ubuntu-latest(fast hosted runners with Android SDK preinstalled), then uploads the signed APK back to Codeberg viaactions/forgejo-release. Obtainium polls Codeberg's release-asset URLs, which aren't IP rate-limited. - Build branches (
cadrega-dev,cadrega-<tag>) and thenightlyskip-detection tag live on GitHub only — they're regenerated by CI on every run and don't need to round-trip back to Codeberg.
| Branch | Owner | Where | Purpose |
|---|---|---|---|
tooling (default) |
maintainer | Codeberg → mirrored to GH | Workflows + rebrand script. Never built from. |
cadrega-patches |
maintainer | Codeberg → mirrored to GH | Default patches branch, written against upstream/16-dev. Sourced by nightly-rebase.yml and by beta-watch.yml as a fallback. |
cadrega-patches-<major> |
maintainer (optional) | Codeberg → mirrored to GH | Per-major patches branch, written against upstream/<major>-dev (e.g. cadrega-patches-15 against upstream/15-dev). Used by beta-watch.yml when present for a v<major>.* target tag. |
cadrega-dev |
CI (force-pushed) | GitHub only | Regenerated nightly = cadrega-patches rebased onto upstream/16-dev + the rebrand commit. Source of the nightly release. |
cadrega-<beta-tag> |
CI (force-pushed) | GitHub only | Regenerated on detection = resolved patches branch rebased onto <beta-tag> + the rebrand commit. Source of the <beta-tag>.0 release. |
All releases live on Codeberg at
https://codeberg.org/BelloWorld/cadrega/releases.
| Tag | Trigger |
|---|---|
nightly |
nightly-rebase.yml — daily cron, replaces the release + tag on each run via forgejo-release --override. |
<upstream-tag>.0 |
beta-watch.yml — daily cron polls upstream for new v*-beta* tags; each new tag becomes a one-shot release. |
The rebrand commit is never replayed. Each run:
upstream tip (fresh)
└─ user patch 1 <- from cadrega-patches, rebased onto upstream tip
└─ user patch 2
└─ ...
└─ cadrega rebrand <- regenerated from scratch every run
So:
git rebase --onto <target> <base>only ever replays your real commits fromcadrega-patches.<base>is computed as the merge-base ofcadrega-patchesandupstream/16-dev(the canonical upstream branch patches are written against), so the set of replayed commits stays constant regardless of which target (16-dev, a beta tag, ...) you rebase onto. If those collide with the target, that's the genuine rebase work you can't avoid — the workflow fails loudly and you rebasecadrega-patchesyourself.- The rebrand commit is rebuilt by running
rebrand.shon the post-rebase tree, so it can never conflict with anything.
cadrega-patches is your normal git branch. Add a commit to it from an
upstream clone and push to Codeberg — the push-mirror propagates to
GitHub on the next sync, then CI picks it up:
git clone https://github.com/LawnchairLauncher/lawnchair
cd lawnchair
git remote add cadrega https://codeberg.org/BelloWorld/cadrega.git
git fetch cadrega
git checkout -B cadrega-patches cadrega/cadrega-patches
# ... edit, commit ...
git push --force cadrega cadrega-patchesNext nightly (after the next mirror sync) picks up the new tip automatically.
When a patch's context doesn't survive cross-major rebases (e.g. it
modifies a file that was rewritten between v15 and v16), maintain a
parallel cadrega-patches-<major> branch rebased onto the matching
upstream release branch:
cd lawnchair
git fetch origin 15-dev
git checkout -B cadrega-patches-15 origin/15-dev
# replay / re-author each fork commit against the v15 tree
git push --force cadrega cadrega-patches-15beta-watch.yml resolves the target's major (e.g. v15.0.0-beta3.0
-> 15), prefers cadrega-patches-15 over cadrega-patches, and uses
upstream/15-dev as the merge-base reference for --onto. Without a
per-major branch the workflow falls back to cadrega-patches; without
either, it builds the bare upstream tag + rebrand.
.github/scripts/rebrand.sh rewrites only what's needed for side-by-side
install + user-visible name change:
build.gradle: the three flavorapplicationIdlines and thederived_app_nameresValue strings.lawnchair/AndroidManifest.xml: theapp.lawnchair.START_ACTIONandapp.lawnchair.APPLY_ICONSintent action strings, plus the matching Kotlin constants.lawnchair/res/values*/strings.xml: occurrences ofLawnchairinside<string>,<plurals>, and<item>element text across every locale. Comments and attribute values (e.g.name="lawnchair_foo") are left alone.
Internal Kotlin/Java FQNs (app.lawnchair.*) stay as-is — changing them would
break class loading and create constant rebase noise.
Added on github.com/drizzt/cadrega under Settings → Secrets and
variables → Actions:
| Secret | Notes |
|---|---|
KEYSTORE |
Base64-encoded JKS file. |
KEYSTORE_PASSWORD |
Store password. |
KEY_ALIAS |
Key alias inside the keystore. |
KEY_PASSWORD |
Key password. |
CODEBERG_TOKEN |
Codeberg PAT with the write:repository scope (Forgejo's repository scope covers releases — there is no separate write:release). Used by forgejo-release to upload assets + by beta-watch.yml to probe existing release tags. |
Both workflows abort if KEYSTORE is empty.
- Codeberg (
codeberg.org/BelloWorld/cadrega): create the repo, maketoolingthe default branch. Actions stays disabled here (Settings → Advanced Settings → uncheck "Enable Repository Actions") — CI runs on GitHub. - Push
toolingto Codeberg:git remote add origin https://codeberg.org/BelloWorld/cadrega.git git push -u origin tooling
- Push your fork commits to
cadrega-patcheson Codeberg from your lawnchair clone:(Workflows accept a missingcd /path/to/lawnchair # the clone that already has your commits git remote add cadrega https://codeberg.org/BelloWorld/cadrega.git git push cadrega <your-branch>:cadrega-patches
cadrega-patchesand fall back to bare upstream + rebrand, so you can also defer this step.) - GitHub (
github.com/drizzt/cadrega): re-forkLawnchairLauncher/lawnchair, then rename the fork tocadrega(Settings → General → Rename). GitHub does not restore deleted forks via Settings → Deleted Repositories, so re-forking is the only way to get the fork relationship back. Under Settings → General turn off Wiki, Issues, Projects, Discussions, Sponsorships. Disable Pull Requests too. Leave Actions on. - Add the five secrets above on GitHub.
- Push mirror Codeberg → GitHub (SSH — Codeberg-recommended): on
Codeberg repo → Settings → Mirroring → add push mirror with target
git@github.com:drizzt/cadrega.gitand authentication set to SSH. Codeberg generates an Ed25519 keypair for the mirror and shows the public key — copy it. On GitHub repo → Settings → Deploy keys → Add deploy key, paste the pubkey, tick "Allow write access", save. Back on Codeberg, click Sync Now. - Once the mirror has propagated, trigger Nightly rebase + release
and Beta watch + release via
workflow_dispatchon GitHub to seed thenightlyrelease and the current beta.
After that, both cron schedules take over.
git remote -v
# origin ssh://git@codeberg.org/BelloWorld/cadrega.git (push)
# github git@github.com:drizzt/cadrega.git (push, optional direct mirror)
# upstream git@github.com:LawnchairLauncher/lawnchair.git (fetch)You normally push only to origin (Codeberg). The github remote is
there if you want to bypass the push-mirror for an urgent change; in
the steady state it's redundant with Codeberg's automatic mirror.
Reproduce a build locally:
git clone https://github.com/LawnchairLauncher/lawnchair
cd lawnchair
git remote add cadrega https://codeberg.org/BelloWorld/cadrega.git
git fetch cadrega cadrega-patches
git checkout -B reproduce cadrega/cadrega-patches
git rebase 16-dev # or a beta tag
bash /path/to/rebrand.sh
./gradlew assembleLawnWithQuickstepGithubRelease