Document that APK filenames must carry the versionCode, or the overwrite guard allows exactly one publish #13

Closed
opened 2026-09-10 01:35:52 +00:00 by claude · 1 comment
Member

What

publish.sh refuses to overwrite an existing APK object (#6), which is right — a published versionCode's artifact must be immutable. But nothing tells a consumer that this means the filename has to carry the versionCode.

Flutter, for example, always emits app-<flavor>-release.apk regardless of version. So a consumer's first publish into an empty prefix succeeds and every subsequent publish fails, with an error that reads like a bucket-state problem rather than a naming contract:

publish.sh: refusing to publish -- repo/app-dev-release.apk already exists in
s3://fdroid-weblib-dev (would overwrite an existing APK, fdroid-repo-ci#6)

weblib-viewer hit exactly this (weblib-viewer#29). It took a full CI cycle plus a log-forwarding workaround to diagnose, because the failure only appears on the second publish — long after the integration looks finished and working.

What to change

Nothing in the guard. Two documentation/ergonomics options:

  1. README: state that APKs must be named <applicationId>_<versionCode>.apk (F-Droid's own convention) before fdroid-update.sh/publish.sh run, and say why — the guard plus a constant filename means exactly one successful publish, ever.
  2. Better error: when the colliding object's name contains no digits, add a line to the refusal — something like "the filename does not appear to carry a versionCode; F-Droid's convention is <applicationId>_<versionCode>.apk". Turns a bucket-state puzzle into an instruction.

I would do both; (1) is the minimum.

Not a code defect

The guard behaved correctly and caught a real overwrite. This is about a contract that is currently only discoverable by tripping over it.

## What `publish.sh` refuses to overwrite an existing APK object (#6), which is right — a published versionCode's artifact must be immutable. But nothing tells a consumer that this means **the filename has to carry the versionCode**. Flutter, for example, always emits `app-<flavor>-release.apk` regardless of version. So a consumer's first publish into an empty prefix succeeds and **every subsequent publish fails**, with an error that reads like a bucket-state problem rather than a naming contract: ``` publish.sh: refusing to publish -- repo/app-dev-release.apk already exists in s3://fdroid-weblib-dev (would overwrite an existing APK, fdroid-repo-ci#6) ``` weblib-viewer hit exactly this (weblib-viewer#29). It took a full CI cycle plus a log-forwarding workaround to diagnose, because the failure only appears on the *second* publish — long after the integration looks finished and working. ## What to change Nothing in the guard. Two documentation/ergonomics options: 1. **README**: state that APKs must be named `<applicationId>_<versionCode>.apk` (F-Droid's own convention) before `fdroid-update.sh`/`publish.sh` run, and say why — the guard plus a constant filename means exactly one successful publish, ever. 2. **Better error**: when the colliding object's name contains no digits, add a line to the refusal — something like "the filename does not appear to carry a versionCode; F-Droid's convention is `<applicationId>_<versionCode>.apk`". Turns a bucket-state puzzle into an instruction. I would do both; (1) is the minimum. ## Not a code defect The guard behaved correctly and caught a real overwrite. This is about a contract that is currently only discoverable by tripping over it.
claude added the
Kind
Enhancement
Priority
Low
4
Type
Task
labels 2026-09-10 01:35:52 +00:00
Owner

Both

Both
bit closed this issue 2026-09-13 08:01:22 +00:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weblib/fdroid-repo-ci#13