Versions #123
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Android APK | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [ main ] | |
| paths: | |
| - 'Valour/Client.Maui/**' | |
| - 'Valour/Client/**' | |
| jobs: | |
| check-version: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version_changed: ${{ steps.check.outputs.changed }} | |
| version: ${{ steps.check.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Check if release already exists | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| CURRENT=$(grep -oP '(?<=<ApplicationDisplayVersion>)[^<]+' Valour/Client.Maui/Valour.Client.Maui.csproj) | |
| echo "version=$CURRENT" >> $GITHUB_OUTPUT | |
| if gh release view "v$CURRENT" > /dev/null 2>&1; then | |
| echo "Release v$CURRENT already exists, skipping build" | |
| echo "changed=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "No release for v$CURRENT, will build" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| fi | |
| build-android: | |
| needs: check-version | |
| if: needs.check-version.outputs.version_changed == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: 10.0.x | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| - name: Install MAUI workload | |
| run: dotnet workload install maui-android | |
| - name: Materialize Android signing keystore | |
| id: signing-keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| run: | | |
| if [ -z "$ANDROID_KEYSTORE_BASE64" ]; then | |
| echo "Missing required secret: ANDROID_KEYSTORE_BASE64" | |
| exit 1 | |
| fi | |
| KEYSTORE_PATH="$RUNNER_TEMP/valour-release.keystore" | |
| echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$KEYSTORE_PATH" | |
| echo "keystore_path=$KEYSTORE_PATH" >> $GITHUB_OUTPUT | |
| - name: Validate Android signing secrets | |
| env: | |
| ANDROID_SIGNING_STORE_PASSWORD: ${{ secrets.ANDROID_SIGNING_STORE_PASSWORD }} | |
| ANDROID_SIGNING_KEY_ALIAS: ${{ secrets.ANDROID_SIGNING_KEY_ALIAS }} | |
| ANDROID_SIGNING_KEY_PASSWORD: ${{ secrets.ANDROID_SIGNING_KEY_PASSWORD }} | |
| run: | | |
| if [ -z "$ANDROID_SIGNING_STORE_PASSWORD" ]; then | |
| echo "Missing required secret: ANDROID_SIGNING_STORE_PASSWORD" | |
| exit 1 | |
| fi | |
| if [ -z "$ANDROID_SIGNING_KEY_ALIAS" ]; then | |
| echo "Missing required secret: ANDROID_SIGNING_KEY_ALIAS" | |
| exit 1 | |
| fi | |
| if [ -z "$ANDROID_SIGNING_KEY_PASSWORD" ]; then | |
| echo "Missing required secret: ANDROID_SIGNING_KEY_PASSWORD" | |
| exit 1 | |
| fi | |
| - name: Validate keystore and alias | |
| env: | |
| ANDROID_SIGNING_STORE_PASSWORD: ${{ secrets.ANDROID_SIGNING_STORE_PASSWORD }} | |
| ANDROID_SIGNING_KEY_ALIAS: ${{ secrets.ANDROID_SIGNING_KEY_ALIAS }} | |
| run: | | |
| keytool -list \ | |
| -keystore "${{ steps.signing-keystore.outputs.keystore_path }}" \ | |
| -storepass "$ANDROID_SIGNING_STORE_PASSWORD" > /dev/null | |
| if ! keytool -list \ | |
| -keystore "${{ steps.signing-keystore.outputs.keystore_path }}" \ | |
| -storepass "$ANDROID_SIGNING_STORE_PASSWORD" \ | |
| -alias "$ANDROID_SIGNING_KEY_ALIAS" > /dev/null; then | |
| echo "Alias '$ANDROID_SIGNING_KEY_ALIAS' was not found in the keystore." | |
| echo "Configured aliases are:" | |
| keytool -list \ | |
| -keystore "${{ steps.signing-keystore.outputs.keystore_path }}" \ | |
| -storepass "$ANDROID_SIGNING_STORE_PASSWORD" | |
| exit 1 | |
| fi | |
| - name: Get short SHA | |
| id: short-sha | |
| run: echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT | |
| - name: Replace asset version hashes | |
| uses: mingjun97/file-regex-replace@v1 | |
| with: | |
| regex: '\$\(SHORTHASH\)' | |
| replacement: '${{ steps.short-sha.outputs.short_sha }}' | |
| flags: "g" | |
| include: '\.(js|cs|razor|cshtml|html)$' | |
| exclude: '.^' | |
| encoding: 'utf8' | |
| path: '.' | |
| - name: Restore dependencies | |
| run: | | |
| dotnet restore Valour/BuildTools/CssBundler/CssBundler.csproj | |
| dotnet restore Valour/Client.Maui/Valour.Client.Maui.csproj -p:AndroidSdkDirectory="${{ env.ANDROID_HOME }}" | |
| - name: Build Client (generates CSS bundle) | |
| run: dotnet build Valour/Client/Valour.Client.csproj -c Release | |
| - name: Build APK | |
| env: | |
| ANDROID_SIGNING_STORE_PASSWORD: ${{ secrets.ANDROID_SIGNING_STORE_PASSWORD }} | |
| ANDROID_SIGNING_KEY_ALIAS: ${{ secrets.ANDROID_SIGNING_KEY_ALIAS }} | |
| ANDROID_SIGNING_KEY_PASSWORD: ${{ secrets.ANDROID_SIGNING_KEY_PASSWORD }} | |
| run: > | |
| dotnet publish Valour/Client.Maui/Valour.Client.Maui.csproj | |
| -f net10.0-android | |
| -c Release | |
| -o ./artifacts | |
| -p:AndroidKeyStore=true | |
| -p:AndroidSigningKeyStore="${{ steps.signing-keystore.outputs.keystore_path }}" | |
| -p:AndroidSigningStorePass="$ANDROID_SIGNING_STORE_PASSWORD" | |
| -p:AndroidSigningKeyAlias="$ANDROID_SIGNING_KEY_ALIAS" | |
| -p:AndroidSigningKeyPass="$ANDROID_SIGNING_KEY_PASSWORD" | |
| -p:AndroidPackageFormat=apk | |
| -p:AndroidUseApkSigner=true | |
| -p:AndroidApkSignerAdditionalArguments=--verbose | |
| -p:AndroidSdkDirectory="${{ env.ANDROID_HOME }}" | |
| - name: Find Signed APK | |
| id: find-apk | |
| run: | | |
| echo "APK candidates found in ./artifacts:" | |
| find ./artifacts -name '*.apk' | sort || true | |
| APKSIGNER=$(find "${ANDROID_HOME}/build-tools" -type f -name apksigner | sort -V | tail -1) | |
| if [ -z "$APKSIGNER" ]; then | |
| echo "Could not find apksigner in ${ANDROID_HOME}/build-tools" | |
| exit 1 | |
| fi | |
| APK_PATH="" | |
| while IFS= read -r CANDIDATE; do | |
| if "$APKSIGNER" verify "$CANDIDATE" > /dev/null 2>&1; then | |
| APK_PATH="$CANDIDATE" | |
| break | |
| fi | |
| done < <(find ./artifacts -name '*.apk' | sort) | |
| if [ -z "$APK_PATH" ]; then | |
| echo "No signed APK was found. Refusing to create a release from unsigned artifacts." | |
| exit 1 | |
| fi | |
| echo "Signed APK selected: $APK_PATH" | |
| "$APKSIGNER" verify --print-certs "$APK_PATH" | |
| echo "apk_path=$APK_PATH" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.check-version.outputs.version }} | |
| name: Valour v${{ needs.check-version.outputs.version }} | |
| files: ${{ steps.find-apk.outputs.apk_path }} | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |