Android: describe the app to F-Droid from DESCRIPTION.md

4255c3f · Gabriel Morell · 2026-09-29 18:30

8 files +67 -2
Message
{commit_body(@commit)}

Files changed

modified .forgejo/workflows/build.yml
+22 −0
@@ -260,9 +260,31 @@ jobs:
260 260 TOKEN: ${{ github.token }}
261 261 run: |
262 262 set -euo pipefail
263 +
264 + # What F-Droid shows under the name and on the app's page.
265 + # android/DESCRIPTION.md: the summary on its first line, then
266 + # a blank line, then the description. The description header
267 + # is percent-encoded because a header can't carry newlines —
268 + # done in bash so the runner needs nothing it doesn't have.
269 + urlencode() {
270 + local LC_ALL=C s="$1" out="" c i
271 + for ((i = 0; i < ${#s}; i++)); do
272 + c=${s:i:1}
273 + case $c in
274 + [a-zA-Z0-9.~_-]) out+=$c ;;
275 + *) printf -v c '%%%02X' "'$c"; out+=$c ;;
276 + esac
277 + done
278 + printf '%s' "$out"
279 + }
280 + summary=$(head -n 1 android/DESCRIPTION.md)
281 + description=$(tail -n +3 android/DESCRIPTION.md)
282 +
263 283 curl --fail-with-body -sS \
264 284 -u "gitgud-actions:$TOKEN" \
265 285 -H "Content-Type: application/vnd.android.package-archive" \
286 + -H "X-Package-Summary: $summary" \
287 + -H "X-Package-Description: $(urlencode "$description")" \
266 288 --data-binary "@apk/app-release.apk" \
267 289 "$FORGE_URL/pkg/fdroid/$REPOSITORY/upload"
268 290 echo
added android/DESCRIPTION.md
+11 −0
@@ -0,0 +1,11 @@
1 +Issues, pull requests and CI for your GitGud forge, from your phone
2 +
3 +The companion app for a GitGud forge. Pair it once by scanning a QR code from your settings page, and every repository your account can reach is in your pocket.
4 +
5 +Watch CI as it happens: runs, jobs, steps and live logs, with re-run, re-run a single job, and cancel. Ask to be told when a run finishes, and keep a home-screen widget showing the status of the repositories and organizations you care about.
6 +
7 +Read and triage issues, comment, quote-reply, close and reopen. Review pull requests: read the description, reviews and line comments, approve or request changes, and merge, with the reasons a merge is blocked spelled out.
8 +
9 +Browse the wiki, and every package a repository publishes along with the line that installs it.
10 +
11 +Your token is stored encrypted with the Android Keystore and never leaves the device except to talk to your own forge.
modified android/README.md
+5 −0
@@ -18,6 +18,11 @@ B612-mono shell, so they feel like one product family.
18 18 | **Wiki** | Page index and rendered pages (read-only) |
19 19 | **Home-screen widget** | The Plasma widget's strip on a phone: the logo and one status circle per watched repository, or one per organization folded into a single circle. Stretch it taller and the recent runs list underneath — tap a circle to filter them, the logo for every run, a run to open it. Polls every 15 minutes, every 30 s while a run is in flight |
20 20
21 +The summary and description F-Droid shows come from
22 +[`DESCRIPTION.md`](DESCRIPTION.md): the summary on the first line (80
23 +characters at most), a blank line, then the description. CI sends both
24 +with every upload.
25 +
21 26 ## Stack
22 27
23 28 | Layer | Choice |
modified docs/fdroid-registry.md
+29 −2
@@ -124,8 +124,13 @@ An app's *other* metadata isn't in the APK at all. F-Droid's Links
124 124 section — source code, issue tracker, changelog, author — and the
125 125 description are things a publisher writes down, and on a forge they are
126 126 already written down: the repository is the source, its issues are the
127 −tracker, its default branch's log is the nearest honest changelog, and
128 −its description is the app's. Both index versions spell these fields
127 +tracker, and its default branch's log is the nearest honest changelog.
128 +The description is the *package's*, not the repository's: one tree can
129 +publish a phone app and a server, and they want different words. It is
130 +set on the packages page or sent with the upload (see Phase D), and the
131 +repository's description only stands in when nothing was. A summary
132 +that would just repeat the app's name is left out rather than shown
133 +under it. Both index versions spell these fields
129 134 the same way (`sourceCode`, `issueTracker`, `changelog`, `authorName`,
130 135 `authorWebSite`) and neither localizes them, while `name`, `summary`
131 136 and `description` are `{"en-US": …}` maps in v2 and plain strings in
@@ -363,6 +368,28 @@ The existing `deb` job is the template, down to the verify step:
363 368 "$FORGE_URL/pkg/fdroid/$REPOSITORY/upload"
364 369 ```
365 370
371 +What F-Droid shows under the app's name and on its page can ride along
372 +with the upload. `X-Package-Summary` is one line of at most 80
373 +characters; `X-Package-Description` is percent-encoded, since a header
374 +can't carry the newlines a description has. A header that isn't sent
375 +leaves the stored value alone, so a job that never sets them never
376 +clears what someone typed on the packages page:
377 +
378 +```yaml
379 + curl --fail-with-body -sS \
380 + -H "X-Package-Summary: $summary" \
381 + -H "X-Package-Description: $(urlencode "$description")" \
382 + …
383 +```
384 +
385 +This repository's own app does exactly that from `android/DESCRIPTION.md`
386 +— summary on the first line, a blank line, then the description — with
387 +a few lines of bash doing the encoding, so the runner needs no `jq`.
388 +See the `android` job in `.forgejo/workflows/build.yml`.
389 +
390 +A summary that fails validation refuses the whole upload with a 400
391 +naming the header, rather than publishing the APK without it.
392 +
366 393 Consuming it is one repo entry:
367 394
368 395 ```

Parents: a625083