Document and hint at the APK-filename/versionCode naming contract

publish.sh's overwrite guard (fdroid-repo-ci#6) is correct but implies a
contract nothing states: a colliding filename with no versionCode in it
means only the first publish into a prefix can ever succeed. Flutter's
constant app-<flavor>-release.apk hit this in weblib-viewer (#29), and the
failure only surfaces on the second publish with an error that reads like a
bucket-state problem.

Add the naming contract to the README, and append a hint to the refusal
message when the colliding object's basename has no digits at all -- a
pure text addition, never changing which publishes are refused.

Closes fdroid-repo-ci#13.

Co-authored-by: bit <bit@das-labor.org>
This commit is contained in:
2026-09-10 02:00:30 +00:00
co-authored by bit
parent 760583b7e3
commit af32b7ca12
3 changed files with 74 additions and 0 deletions
+40
View File
@@ -213,6 +213,45 @@ if [ "$have_python" = true ]; then
else
pass "publish.sh never starts pass 1 after refusing a colliding APK"
fi
# de.example.app_1.apk carries a digit (the versionCode "1"), so the
# no-digits hint below (fdroid-repo-ci#13) must not fire for it -- this is
# the negative control for that hint, proving it is not just always on.
if echo "$out" | grep -q "does not appear to carry a versionCode"; then
fail "publish.sh must not hint about a missing versionCode when the colliding filename has digits (it did!)"
else
pass "publish.sh does not add the no-versionCode hint when the colliding filename has digits"
fi
echo "--- a colliding filename with no digits gets the versionCode hint (fdroid-repo-ci#13) ---"
# The Flutter case the issue is about: a build that always emits the same
# filename regardless of version, e.g. app-dev-release.apk. The guard
# still refuses exactly as above; only the message grows a line pointing
# at the naming contract, since a bucket-state-shaped error is what took a
# full CI cycle to diagnose in weblib-viewer#29.
nodigits_dir="$work/nodigits"
mkdir -p "$nodigits_dir"
echo '{}' > "$nodigits_dir/index-v2.json"
echo 'unsigned bytes, same name every build' > "$nodigits_dir/app-dev-release.apk"
start_stub mybucket "myprefix/app-dev-release.apk"
out=$(bash "$here/publish.sh" "$nodigits_dir" mybucket "http://127.0.0.1:$stub_port" myprefix 2>&1) && rc=0 || rc=$?
kill "$stub_pid" 2>/dev/null || true
wait "$stub_pid" 2>/dev/null || true
if [ "${rc:-0}" -ne 0 ]; then
pass "publish.sh refuses to publish a colliding APK filename with no digits"
else
fail "publish.sh refuses to publish a colliding APK filename with no digits (got exit 0)"
fi
assert_contains "the refusal names the colliding key" "$out" "myprefix/app-dev-release.apk"
assert_contains "the refusal explains why" "$out" "already exists"
assert_contains "the refusal hints that the filename carries no versionCode" "$out" \
"does not appear to carry a versionCode"
assert_contains "the hint states F-Droid's naming convention" "$out" \
"<applicationId>_<versionCode>.apk"
if echo "$out" | grep -q "pass 1/2"; then
fail "publish.sh must not start pass 1 after refusing a colliding no-digits APK (it did!)"
else
pass "publish.sh never starts pass 1 after refusing a colliding no-digits APK"
fi
echo "--- negative control: a non-colliding APK does not trip the same check ---"
start_stub mybucket # nothing pre-exists
@@ -244,6 +283,7 @@ if [ "$have_python" = true ]; then
fi
else
skip "credential-check-is-real / APK-collision-refusal (no python3 available, even via with-nixpkgs.sh)"
skip "APK-collision refusal includes the no-versionCode hint for a digit-free filename"
skip "negative control: non-colliding APK does not trip the check"
skip "--index-only never runs the APK-collision check"
fi