fdroid-repo/apps.nix
randogoth 4f1a67bed3 Feed the F-Droid repo from Forgejo releases automatically
The scaffold here was a manual pipeline: copy an APK into repo/, run
`fdroid update`, rsync the result somewhere. Every app already builds and
signs its own APK in CI and publishes it as a Forgejo release, so all of
that copying was re-doing by hand what the forge already had.

Both halves of a listing now come from the same release: the APK from the
release asset, and the title, summary, description, changelog, icon and
screenshots from the fastlane/ tree at the same tag. A listing can no longer
describe a build other than the one it ships, because there is no second copy
of the text to drift.

fdroid-sync.py is the whole reconcile. It is a pure function of what the forge
currently holds — work out what should be published, make it so, re-sign the
index only if something moved — which is what makes it safe to drive from a
webhook that has no delivery guarantee and no retry. A missed delivery costs
latency, not correctness.

Three things were only found by running the real thing with an empty
environment, and all three fail late and confusingly:

- fdroidserver bundles apksigner but no JDK, and shells out to jar, keytool
  and jarsigner by bare name. The PATH is now set outright rather than
  inherited, because the bundled apksigner is a Gradle-style launcher that
  also needs xargs and sed — and without xargs fdroidserver reads every APK
  as having an invalid signature and quarantines the lot into archive/.
- index-v2 only carries a changelog for a version matching the last Builds
  entry, and a repo of prebuilt APKs has no build recipes. Without a declared
  entry every release shipped an empty "What's New".
- fdroidserver does not fall back to the APK's launcher icon, so an app whose
  fastlane tree has no images/icon.png was listed with no icon at all, which
  is two of these four. The sync now recovers one from the APK.

module.nix keeps the keystore password out of the Nix store via
fdroidserver's {env: ...} indirection, and serves the repo rooted at repo/
rather than at the working directory, which would also have handed out
config.yml and metadata/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-14 11:54:26 +03:00

56 lines
2.1 KiB
Nix

# The apps this repo serves. One entry per app; adding an app is adding an
# entry here and pushing.
#
# Everything in this file is the part of a listing that does not change when a
# release is cut: the package identity, where its releases live, its licence
# and where it belongs in F-Droid's category list. Everything that *does*
# change per release — name, summary, description, changelog, icon,
# screenshots — is deliberately absent, because it is read from the app repo's
# own fastlane/ tree at the released tag. Writing a description here would
# create a second copy of it that silently drifts from the one the app ships.
#
# Fields:
# id short slug; names log lines and the --app filter, nothing else
# packageId the Android applicationId. This is the app's identity to
# F-Droid and to every phone that has it installed, so it has to
# match `applicationId` in android/app/build.gradle{,.kts}
# exactly — a typo here publishes a second, unrelated app rather
# than an update to the existing one.
# repo owner/name on the forge
# license SPDX identifier, shown in the client
# categories F-Droid's fixed category vocabulary, not free text
# fastlane where the fastlane tree sits inside the repo (default
# "fastlane"; the-mews keeps its Flutter app under app/)
# webSite optional; omitted means the client shows only the source link
[
{
id = "muzzlevelocity";
packageId = "vision.flux.muzzlevelocity";
repo = "randogoth/muzzle-velocity";
license = "Apache-2.0";
categories = [ "Writing" ];
}
{
id = "plasmoid";
packageId = "com.randogoth.plasmoid";
repo = "randogoth/plasmoid";
license = "Apache-2.0";
categories = [ "System" ];
}
{
id = "themews";
packageId = "page.mews.mews";
repo = "randogoth/the-mews";
license = "Apache-2.0";
categories = [ "Internet" ];
fastlane = "app/fastlane";
webSite = "https://mews.page";
}
{
id = "kirakira";
packageId = "com.app.smol_mail";
repo = "randogoth/kirakira";
license = "MIT";
categories = [ "Internet" ];
}
]