Skip to content

Commit 4b4a78d

Browse files
sharpninjaCopilot
andcommitted
Switch to fdroidserver for F-Droid repo generation
Replace custom Python script with the official fdroidserver tool (fdroid update), matching the approach used in remote-agent. Adds proper fdroid metadata YAML, keystore generation, repo verification, and cached keystore across CI runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0957bb4 commit 4b4a78d

6 files changed

Lines changed: 158 additions & 183 deletions

File tree

.github/scripts/generate_fdroid_repo.py

Lines changed: 0 additions & 151 deletions
This file was deleted.

.github/workflows/build-android.yml

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

docs/fdroid/repo/entry.json

Lines changed: 0 additions & 10 deletions
This file was deleted.
-3.49 KB
Binary file not shown.

docs/fdroid/repo/index-v1.json

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# F-Droid metadata for RequestTracker (binary repo – no Builds).
2+
# See https://f-droid.org/docs/Build_Metadata_Reference
3+
4+
Categories:
5+
- Development
6+
- System
7+
8+
License: MIT
9+
10+
Summary: Browse and analyze Copilot session logs
11+
12+
Description: |
13+
RequestTracker is an Avalonia-based Android app for browsing, searching,
14+
and analyzing Copilot request/session logs. Supports phone (portrait
15+
NavigationView) and tablet (desktop-like) layouts.
16+
17+
WebSite: https://github.com/sharpninja/RequestTracker
18+
19+
SourceCode: https://github.com/sharpninja/RequestTracker
20+
21+
IssueTracker: https://github.com/sharpninja/RequestTracker/issues

0 commit comments

Comments
 (0)