1- name : Build Android APK & Publish F-Droid Repo
1+ name : Build & Release
22
33on :
44 push :
@@ -15,67 +15,63 @@ concurrency:
1515 cancel-in-progress : false
1616
1717jobs :
18- build-and-release :
18+ # ── Shared version detection ──────────────────────────────────────────────
19+ version :
1920 runs-on : ubuntu-latest
2021 outputs :
2122 semver : ${{ steps.gitversion.outputs.semVer }}
23+ major : ${{ steps.gitversion.outputs.major }}
24+ minor : ${{ steps.gitversion.outputs.minor }}
25+ patch : ${{ steps.gitversion.outputs.patch }}
26+ commits : ${{ steps.gitversion.outputs.commitsSinceVersionSource }}
2227 version-code : ${{ steps.version-code.outputs.code }}
23- apk-url : ${{ steps.upload-release.outputs.apk-url }}
24- apk-hash : ${{ steps.apk-hash.outputs.sha256 }}
25- apk-size : ${{ steps.apk-hash.outputs.size }}
2628 steps :
27- - name : Checkout
28- uses : actions/checkout@v4
29- with :
30- fetch-depth : 0 # Full history for GitVersion
31-
32- - name : Setup .NET
33- uses : actions/setup-dotnet@v4
29+ - uses : actions/checkout@v4
3430 with :
35- dotnet-version : ' 9.0.x'
36-
37- - name : Install Android workload
38- run : dotnet workload install android
31+ fetch-depth : 0
3932
40- - name : Install GitVersion
41- uses : gittools/actions/gitversion/setup@v3.2.1
33+ - uses : gittools/actions/gitversion/setup@v3.2.1
4234 with :
4335 versionSpec : ' 6.x'
4436
45- - name : Determine version
46- id : gitversion
37+ - id : gitversion
4738 uses : gittools/actions/gitversion/execute@v3.2.1
4839 with :
4940 useConfigFile : false
5041
51- - name : Display version
52- run : |
53- echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"
54- echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}"
55- echo "Major: ${{ steps.gitversion.outputs.major }}"
56- echo "Minor: ${{ steps.gitversion.outputs.minor }}"
57- echo "Patch: ${{ steps.gitversion.outputs.patch }}"
58- echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
59-
60- - name : Calculate version code
42+ - name : Calculate Android version code
6143 id : version-code
6244 run : |
63- MAJOR=${{ steps.gitversion.outputs.major }}
64- MINOR=${{ steps.gitversion.outputs.minor }}
65- PATCH=${{ steps.gitversion.outputs.patch }}
66- COMMITS=${{ steps.gitversion.outputs.commitsSinceVersionSource }}
67- # version code = major*10000 + minor*1000 + patch*100 + commits
68- CODE=$(( MAJOR * 10000 + MINOR * 1000 + PATCH * 100 + COMMITS ))
45+ CODE=$(( ${{ steps.gitversion.outputs.major }} * 10000 + ${{ steps.gitversion.outputs.minor }} * 1000 + ${{ steps.gitversion.outputs.patch }} * 100 + ${{ steps.gitversion.outputs.commitsSinceVersionSource }} ))
6946 if [ "$CODE" -lt 1 ]; then CODE=1; fi
7047 echo "code=$CODE" >> "$GITHUB_OUTPUT"
71- echo "Version code: $CODE"
48+
49+ - run : echo "SemVer=${{ steps.gitversion.outputs.semVer }} VersionCode=${{ steps.version-code.outputs.code }}"
50+
51+ # ── Android APK ───────────────────────────────────────────────────────────
52+ build-android :
53+ needs : version
54+ runs-on : ubuntu-latest
55+ outputs :
56+ apk-hash : ${{ steps.apk-hash.outputs.sha256 }}
57+ apk-size : ${{ steps.apk-hash.outputs.size }}
58+ steps :
59+ - uses : actions/checkout@v4
60+ with :
61+ fetch-depth : 0
62+ submodules : true
63+
64+ - uses : actions/setup-dotnet@v4
65+ with :
66+ dotnet-version : ' 9.0.x'
67+
68+ - run : dotnet workload install android
7269
7370 - name : Decode keystore
7471 if : env.KEYSTORE_BASE64 != ''
7572 env :
7673 KEYSTORE_BASE64 : ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
77- run : |
78- echo "$KEYSTORE_BASE64" | base64 -d > ${{ github.workspace }}/release.keystore
74+ run : echo "$KEYSTORE_BASE64" | base64 -d > ${{ github.workspace }}/release.keystore
7975
8076 - name : Build Android APK
8177 run : |
@@ -84,119 +80,185 @@ jobs:
8480 SIGNING_ARGS="/p:AndroidSigningKeyStore=${{ github.workspace }}/release.keystore /p:AndroidSigningKeyAlias=${{ secrets.ANDROID_KEY_ALIAS }} /p:AndroidSigningStorePass=${{ secrets.ANDROID_KEYSTORE_PASSWORD }} /p:AndroidSigningKeyPass=${{ secrets.ANDROID_KEY_PASSWORD }}"
8581 fi
8682 dotnet publish src/RequestTracker.Android/RequestTracker.Android.csproj \
87- -c Release \
88- -f net9.0-android \
89- /p:ApplicationVersion=${{ steps.version-code.outputs.code }} \
90- /p:ApplicationDisplayVersion=${{ steps.gitversion.outputs.semVer }} \
83+ -c Release -f net9.0-android \
84+ /p:ApplicationVersion=${{ needs.version.outputs.version-code }} \
85+ /p:ApplicationDisplayVersion=${{ needs.version.outputs.semver }} \
9186 $SIGNING_ARGS
9287
9388 - name : Find and rename APK
9489 id : find-apk
9590 run : |
96- echo "=== All output files ==="
97- find src/RequestTracker.Android/bin/Release -type f -name "*.apk" -o -name "*.aab" | sort
98- echo "=== Searching for APK ==="
99- # Search for signed APK first, then any APK
10091 APK=$(find src/RequestTracker.Android/bin/Release -name "*-Signed.apk" | head -1)
92+ [ -z "$APK" ] && APK=$(find src/RequestTracker.Android/bin/Release -name "*.apk" | head -1)
10193 if [ -z "$APK" ]; then
102- APK=$(find src/RequestTracker.Android/bin/Release -name "*.apk" | head -1)
103- fi
104- if [ -z "$APK" ]; then
105- echo "ERROR: No APK found! Full file listing:"
106- find src/RequestTracker.Android/bin/Release -type f
107- exit 1
94+ echo "ERROR: No APK found!"; find src/RequestTracker.Android/bin/Release -type f; exit 1
10895 fi
109- DEST="src/RequestTracker.Android/bin/Release/RequestTracker-${{ steps.gitversion.outputs.semVer }}.apk"
96+ DEST="artifacts/RequestTracker-${{ needs.version.outputs.semver }}.apk"
97+ mkdir -p artifacts
11098 cp "$APK" "$DEST"
11199 echo "apk-path=$DEST" >> "$GITHUB_OUTPUT"
112- echo "Found APK: $APK -> $DEST"
113100
114- - name : Compute APK hash and size
101+ - name : Compute APK hash
115102 id : apk-hash
116103 run : |
117- APK="${{ steps.find-apk.outputs.apk-path }}"
118- SHA256=$(sha256sum "$APK" | awk '{print $1}')
119- SIZE=$(stat -c%s "$APK")
104+ SHA256=$(sha256sum "${{ steps.find-apk.outputs.apk-path }}" | awk '{print $1}')
105+ SIZE=$(stat -c%s "${{ steps.find-apk.outputs.apk-path }}")
120106 echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
121107 echo "size=$SIZE" >> "$GITHUB_OUTPUT"
122- echo "APK SHA-256: $SHA256"
123- echo "APK size: $SIZE bytes"
108+
109+ - uses : actions/upload-artifact@v4
110+ with :
111+ name : android-apk
112+ path : artifacts/*.apk
113+
114+ # ── Windows MSIX ──────────────────────────────────────────────────────────
115+ build-windows :
116+ needs : version
117+ runs-on : windows-latest
118+ steps :
119+ - uses : actions/checkout@v4
120+ with :
121+ fetch-depth : 0
122+ submodules : true
123+
124+ - uses : actions/setup-dotnet@v4
125+ with :
126+ dotnet-version : ' 9.0.x'
127+
128+ - name : Build MSIX package
129+ shell : pwsh
130+ run : |
131+ Import-Module ./scripts/MsixTools/MsixTools.psd1 -Force
132+ New-MsixPackage `
133+ -WorkspaceRoot . `
134+ -ConfigPath msix.yml `
135+ -Version "${{ needs.version.outputs.semver }}" `
136+ -ExcludeService `
137+ -DevCert `
138+ -Force
139+
140+ - name : Rename MSIX
141+ shell : pwsh
142+ run : |
143+ $msix = Get-ChildItem artifacts -Filter '*.msix' | Select-Object -First 1
144+ $dest = "artifacts/RequestTracker-${{ needs.version.outputs.semver }}-win-x64.msix"
145+ if ($msix.FullName -ne (Resolve-Path $dest -ErrorAction SilentlyContinue)) {
146+ Move-Item $msix.FullName $dest -Force
147+ }
148+ Write-Host "MSIX: $dest"
149+
150+ - uses : actions/upload-artifact@v4
151+ with :
152+ name : windows-msix
153+ path : artifacts/*.msix
154+
155+ # ── Linux DEB ─────────────────────────────────────────────────────────────
156+ build-linux :
157+ needs : version
158+ runs-on : ubuntu-latest
159+ steps :
160+ - uses : actions/checkout@v4
161+ with :
162+ fetch-depth : 0
163+ submodules : true
164+
165+ - uses : actions/setup-dotnet@v4
166+ with :
167+ dotnet-version : ' 9.0.x'
168+
169+ - name : Build DEB package
170+ run : |
171+ chmod +x scripts/build-deb.sh
172+ scripts/build-deb.sh --version "${{ needs.version.outputs.semver }}"
173+
174+ - uses : actions/upload-artifact@v4
175+ with :
176+ name : linux-deb
177+ path : artifacts/*.deb
178+
179+ # ── GitHub Release ────────────────────────────────────────────────────────
180+ release :
181+ needs : [version, build-android, build-windows, build-linux]
182+ runs-on : ubuntu-latest
183+ outputs :
184+ apk-url : ${{ steps.urls.outputs.apk-url }}
185+ steps :
186+ - uses : actions/download-artifact@v4
187+ with :
188+ path : release-assets
189+ merge-multiple : true
190+
191+ - name : List release assets
192+ run : ls -lh release-assets/
124193
125194 - name : Create GitHub Release
126- id : create-release
127195 uses : softprops/action-gh-release@v2
128196 with :
129- tag_name : v${{ steps.gitversion .outputs.semVer }}
130- name : RequestTracker v${{ steps.gitversion .outputs.semVer }}
197+ tag_name : v${{ needs.version .outputs.semver }}
198+ name : RequestTracker v${{ needs.version .outputs.semver }}
131199 body : |
132- ## RequestTracker v${{ steps.gitversion.outputs.semVer }}
200+ ## RequestTracker v${{ needs.version.outputs.semver }}
201+
202+ ### Downloads
203+ | Platform | File |
204+ |----------|------|
205+ | 🤖 Android | `RequestTracker-${{ needs.version.outputs.semver }}.apk` |
206+ | 🪟 Windows | `RequestTracker-${{ needs.version.outputs.semver }}-win-x64.msix` |
207+ | 🐧 Linux | `requesttracker_${{ needs.version.outputs.semver }}_amd64.deb` |
133208
134209 ### Android APK
135- - **Version**: ${{ steps.gitversion.outputs.semVer }}
136- - **Version Code**: ${{ steps.version-code.outputs.code }}
137- - **SHA-256**: `${{ steps.apk-hash.outputs.sha256 }}`
210+ - **Version Code**: ${{ needs.version.outputs.version-code }}
211+ - **SHA-256**: `${{ needs.build-android.outputs.apk-hash }}`
138212
139213 ### Install via F-Droid
140- Add this repo URL to your F-Droid client:
141214 ```
142215 https://sharpninja.github.io/RequestTracker/fdroid/repo
143216 ```
217+
218+ ### Install on Linux
219+ ```bash
220+ sudo dpkg -i requesttracker_${{ needs.version.outputs.semver }}_amd64.deb
221+ ```
144222 draft : false
145- prerelease : ${{ contains(steps.gitversion .outputs.semVer , '-') }}
146- files : ${{ steps.find-apk.outputs.apk-path }}
223+ prerelease : ${{ contains(needs.version .outputs.semver , '-') }}
224+ files : release-assets/*
147225
148- - name : Get APK release asset URL
149- id : upload-release
226+ - name : Compute release URLs
227+ id : urls
150228 run : |
151- # Get the direct download URL for the APK asset from the release
152- TAG="v${{ steps.gitversion.outputs.semVer }}"
153- APK_NAME="RequestTracker-${{ steps.gitversion.outputs.semVer }}.apk"
154- APK_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${APK_NAME}"
155- echo "apk-url=$APK_URL" >> "$GITHUB_OUTPUT"
156- echo "APK release URL: $APK_URL"
229+ TAG="v${{ needs.version.outputs.semver }}"
230+ echo "apk-url=https://github.com/${{ github.repository }}/releases/download/${TAG}/RequestTracker-${{ needs.version.outputs.semver }}.apk" >> "$GITHUB_OUTPUT"
157231
232+ # ── F-Droid repo deployment ───────────────────────────────────────────────
158233 deploy-fdroid :
159- needs : build-and- release
234+ needs : [version, build-android, release]
160235 runs-on : ubuntu-latest
161236 environment :
162237 name : github-pages
163238 url : ${{ steps.deployment.outputs.page_url }}
164239 steps :
165- - name : Checkout
166- uses : actions/checkout@v4
240+ - uses : actions/checkout@v4
167241
168- - name : Setup Python
169- uses : actions/setup-python@v5
242+ - uses : actions/setup-python@v5
170243 with :
171244 python-version : ' 3.12'
172245
173246 - name : Generate F-Droid repo metadata
174247 run : |
175248 python .github/scripts/generate_fdroid_repo.py \
176- --version "${{ needs.build-and-release .outputs.semver }}" \
177- --version-code "${{ needs.build-and-release .outputs.version-code }}" \
178- --apk-url "${{ needs.build-and- release.outputs.apk-url }}" \
179- --apk-hash "${{ needs.build-and-release .outputs.apk-hash }}" \
180- --apk-size "${{ needs.build-and-release .outputs.apk-size }}" \
249+ --version "${{ needs.version .outputs.semver }}" \
250+ --version-code "${{ needs.version .outputs.version-code }}" \
251+ --apk-url "${{ needs.release.outputs.apk-url }}" \
252+ --apk-hash "${{ needs.build-android .outputs.apk-hash }}" \
253+ --apk-size "${{ needs.build-android .outputs.apk-size }}" \
181254 --repo-url "https://sharpninja.github.io/RequestTracker/fdroid/repo" \
182255 --output-dir docs/fdroid/repo
183256
184- - name : Show generated metadata
185- run : |
186- echo "=== index-v1.json ==="
187- cat docs/fdroid/repo/index-v1.json
188- echo ""
189- echo "=== entry.json ==="
190- cat docs/fdroid/repo/entry.json
191-
192- - name : Setup Pages
193- uses : actions/configure-pages@v5
257+ - uses : actions/configure-pages@v5
194258
195- - name : Upload Pages artifact
196- uses : actions/upload-pages-artifact@v3
259+ - uses : actions/upload-pages-artifact@v3
197260 with :
198261 path : docs/fdroid
199262
200- - name : Deploy to GitHub Pages
201- id : deployment
263+ - id : deployment
202264 uses : actions/deploy-pages@v4
0 commit comments