@@ -259,26 +259,152 @@ jobs:
259259 steps :
260260 - uses : actions/checkout@v4
261261
262- - uses : actions/setup-python@v5
262+ - name : Set up Python and F-Droid CLI
263+ uses : actions/setup-python@v5
263264 with :
264265 python-version : ' 3.12'
266+ - name : Install fdroidserver
267+ run : pip install fdroidserver
265268
266- - name : Generate F-Droid repo metadata
269+ - name : Download APK
270+ uses : actions/download-artifact@v4
271+ with :
272+ name : android-apk
273+
274+ - name : Restore F-Droid keystore cache
275+ id : fdroid-cache
276+ uses : actions/cache@v4
277+ with :
278+ path : fdroid-workspace
279+ key : fdroid-keystore-v1-${{ runner.os }}
280+
281+ - name : Prepare F-Droid workspace
282+ run : |
283+ REPO_URL="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/repo"
284+ mkdir -p fdroid-workspace/repo fdroid-workspace/metadata
285+ if [ ! -f fdroid-workspace/keystore.jks ]; then
286+ keytool -genkeypair -keystore fdroid-workspace/keystore.jks -alias fdroidrepo \
287+ -keyalg RSA -keysize 2048 -validity 10000 \
288+ -storepass android -keypass android \
289+ -dname "CN=RequestTracker Repo, OU=CI, O=GitHub"
290+ fi
291+ cat > fdroid-workspace/config.yml << CONFIG
292+ repo_url: "$REPO_URL"
293+ repo_name: "RequestTracker"
294+ repo_description: "Android app for browsing and analyzing Copilot session logs. Supports phone and tablet layouts."
295+ repo_keyalias: fdroidrepo
296+ keystore: keystore.jks
297+ keystorepass: android
298+ keypass: android
299+ keydname: "CN=RequestTracker Repo, OU=CI, O=GitHub"
300+ CONFIG
301+ chmod 600 fdroid-workspace/config.yml
302+ mkdir -p fdroid-workspace/repo/icons
303+ # Copy logo as repo icon
304+ if [ -f docs/fdroid/icon.png ]; then
305+ cp docs/fdroid/icon.png fdroid-workspace/repo/icons/icon.png
306+ else
307+ echo 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==' | base64 -d > fdroid-workspace/repo/icons/icon.png
308+ fi
309+ rm -f fdroid-workspace/repo/*.apk fdroid-workspace/repo/*.xml fdroid-workspace/repo/*.jar 2>/dev/null || true
310+ rm -f fdroid-workspace/repo/index.* 2>/dev/null || true
311+ APK=$(find . -name "*.apk" -type f | head -1)
312+ cp "$APK" fdroid-workspace/repo/
313+ cp fdroid/metadata/com.requesttracker.android.yml fdroid-workspace/metadata/
314+
315+ - name : Ensure repo icon exists
316+ run : |
317+ mkdir -p fdroid-workspace/repo/icons
318+ [ -f fdroid-workspace/repo/icons/icon.png ] || echo 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==' | base64 -d > fdroid-workspace/repo/icons/icon.png
319+
320+ - name : Generate F-Droid repo (fdroid update)
321+ run : |
322+ cd fdroid-workspace && fdroid update
323+
324+ - name : Verify F-Droid repo (logo, URL, hash, version)
325+ env :
326+ EXPECTED_VERSION : ${{ needs.version.outputs.semver }}
327+ EXPECTED_REPO_URL : " https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/repo"
328+ run : |
329+ set -e
330+ REPO=fdroid-workspace/repo
331+ ICON="$REPO/icons/icon.png"
332+ ERRORS=()
333+
334+ # 1) Logo: icon.png must exist
335+ if [ ! -f "$ICON" ]; then
336+ ERRORS+=("F-Droid logo check FAILED: icon file missing at $ICON")
337+ elif [ ! -s "$ICON" ]; then
338+ ERRORS+=("F-Droid logo check FAILED: repo/icons/icon.png is empty")
339+ fi
340+
341+ # 2) APK must exist
342+ APK=$(find "$REPO" -name "*.apk" -type f | head -1)
343+ if [ -z "$APK" ]; then
344+ ERRORS+=("F-Droid APK check FAILED: no APK found in $REPO")
345+ fi
346+ export APK
347+
348+ # 3) Repo URL in config must match expected
349+ if [ -f fdroid-workspace/config.yml ]; then
350+ CONFIG_URL=$(grep -E '^\s*repo_url:\s*' fdroid-workspace/config.yml | sed -E 's/.*repo_url:\s*["]?([^"]*)["]?.*/\1/' | tr -d '"' | xargs)
351+ if [ "$CONFIG_URL" != "$EXPECTED_REPO_URL" ]; then
352+ ERRORS+=("F-Droid URL check FAILED: config repo_url is '$CONFIG_URL' but expected '$EXPECTED_REPO_URL'")
353+ fi
354+ else
355+ ERRORS+=("F-Droid URL check FAILED: fdroid-workspace/config.yml not found")
356+ fi
357+
358+ # 4) Index must exist and reference APK with correct hash
359+ APKNAME=$(basename "$APK")
360+ COMPUTED=$(sha256sum "$APK" | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
361+ INDEX_HASH=""
362+ SOURCE=""
363+
364+ if [ -f "$REPO/index-v1.json" ]; then
365+ INDEX_HASH=$(jq -r --arg apk "$APKNAME" '
366+ .packages // {} |
367+ to_entries[] |
368+ .value[] |
369+ select(.apkName == $apk) |
370+ .hash // ""
371+ ' "$REPO/index-v1.json" | head -1 | sed 's/sha256://g' | tr -d "[:space:]" | tr "[:upper:]" "[:lower:]")
372+ SOURCE="index-v1.json"
373+ elif [ -f "$REPO/index.xml" ]; then
374+ INDEX_HASH=$(xmllint --xpath "string(//package[@apkName='$APKNAME']/@hash)" "$REPO/index.xml" 2>/dev/null | sed 's/sha256://g' | tr -d "[:space:]" | tr "[:upper:]" "[:lower:]")
375+ SOURCE="index.xml"
376+ fi
377+
378+ if [ -z "$INDEX_HASH" ]; then
379+ echo "APK $APKNAME not found in repo index" >&2
380+ exit 1
381+ fi
382+
383+ if [ "$INDEX_HASH" != "$COMPUTED" ]; then
384+ echo "Hash mismatch: $SOURCE has $INDEX_HASH, computed $COMPUTED" >&2
385+ exit 1
386+ fi
387+
388+ echo "$SOURCE hash matches."
389+
390+ if [ ${#ERRORS[@]} -gt 0 ]; then
391+ echo "F-Droid verification failed:"
392+ printf '%s\n' "${ERRORS[@]}"
393+ exit 1
394+ fi
395+
396+ - name : Assemble Pages artifact
267397 run : |
268- python .github/scripts/generate_fdroid_repo.py \
269- --version "${{ needs.version.outputs.semver }}" \
270- --version-code "${{ needs.version.outputs.version-code }}" \
271- --apk-url "${{ needs.release.outputs.apk-url }}" \
272- --apk-hash "${{ needs.build-android.outputs.apk-hash }}" \
273- --apk-size "${{ needs.build-android.outputs.apk-size }}" \
274- --repo-url "https://sharpninja.github.io/RequestTracker/repo" \
275- --output-dir docs/fdroid/repo
398+ mkdir -p pages-output/repo
399+ cp docs/fdroid/index.html pages-output/
400+ [ -f docs/fdroid/icon.png ] && cp docs/fdroid/icon.png pages-output/
401+ cp -r fdroid-workspace/repo/* pages-output/repo/
276402
277403 - uses : actions/configure-pages@v5
278404
279405 - uses : actions/upload-pages-artifact@v3
280406 with :
281- path : docs/fdroid
407+ path : pages-output
282408
283409 - id : deployment
284410 uses : actions/deploy-pages@v4
0 commit comments