fix: ensure Android keystore is decoded for manual workflow triggers #20
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: CI - Build & Test | |
| on: | |
| push: | |
| branches: [ main, development ] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'LICENSE' | |
| - '.gitignore' | |
| pull_request: | |
| branches: [ main, development ] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'LICENSE' | |
| - '.gitignore' | |
| workflow_dispatch: | |
| # Cancel in-progress runs for same PR/branch | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| JAVA_VERSION: '21' | |
| JAVA_DISTRIBUTION: 'temurin' | |
| GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true | |
| jobs: | |
| # ================== Unit Tests ================== | |
| test-unit: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 # Shallow clone for speed | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
| - name: Run unit tests | |
| run: | | |
| ./gradlew \ | |
| :pocketbase-kt-sdk:jvmTest \ | |
| :composeApp:jvmTest \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| continue-on-error: false | |
| - name: Run shared unit tests (exclude integration) | |
| run: | | |
| ./gradlew :shared:jvmTest \ | |
| --tests 'love.bside.app.unit.*' \ | |
| --tests 'love.bside.app.data.serialization.*' \ | |
| --tests 'love.bside.app.domain.models.*' \ | |
| --tests 'love.bside.app.domain.validation.*' \ | |
| --parallel \ | |
| --build-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| continue-on-error: false | |
| - name: Upload test reports | |
| if: failure() # Only upload on failure to save storage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-reports-unit | |
| path: | | |
| **/build/reports/tests/ | |
| **/build/test-results/ | |
| retention-days: 3 # Reduced from 7 days | |
| # ================== Android Build ================== | |
| build-android: | |
| name: Build Android | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| needs: test-unit | |
| if: github.event_name == 'push' || github.event.pull_request.draft == false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
| - name: Build Android APK (Debug) | |
| run: | | |
| ./gradlew \ | |
| :composeApp:assembleDebug \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| - name: Upload Android APK | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-apk-debug | |
| path: composeApp/build/outputs/apk/debug/*.apk | |
| retention-days: 14 # Reduced from 30 days | |
| compression-level: 0 # APKs are already compressed | |
| - name: Generate APK checksums | |
| run: | | |
| cd composeApp/build/outputs/apk/debug | |
| sha256sum *.apk > checksums.txt | |
| cat checksums.txt | |
| - name: Upload checksums | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-checksums | |
| path: composeApp/build/outputs/apk/debug/checksums.txt | |
| retention-days: 14 | |
| # ================== iOS Build (macOS only) ================== | |
| build-ios: | |
| name: Build iOS | |
| runs-on: macos-14 # M1 runner (faster & cheaper than macos-latest) | |
| timeout-minutes: 30 | |
| needs: test-unit | |
| if: github.event_name == 'push' || github.event.pull_request.draft == false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
| - name: Build iOS Framework | |
| run: | | |
| ./gradlew \ | |
| :composeApp:linkDebugFrameworkIosSimulatorArm64 \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| - name: Upload iOS Framework | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-framework-debug | |
| path: composeApp/build/bin/iosSimulatorArm64/debugFramework/ | |
| retention-days: 14 | |
| # ================== Desktop Build ================== | |
| build-desktop: | |
| name: Build Desktop | |
| strategy: | |
| fail-fast: false # Continue other OS builds if one fails | |
| matrix: | |
| os: [ubuntu-latest, macos-14, windows-latest] | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| needs: test-unit | |
| # Only build desktop on main branch or explicit request | |
| if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
| - name: Build Desktop JAR | |
| run: | | |
| ./gradlew \ | |
| :composeApp:jvmJar \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| - name: Upload Desktop Distribution | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-${{ runner.os }} | |
| path: composeApp/build/compose/binaries/main/app/ | |
| retention-days: 14 | |
| compression-level: 6 # Good balance for binaries | |
| # ================== Web Build ================== | |
| build-web: | |
| name: Build Web | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| needs: test-unit | |
| if: github.event_name == 'push' || github.event.pull_request.draft == false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: ${{ github.ref != 'refs/heads/main' }} | |
| - name: Build Web | |
| run: | | |
| ./gradlew \ | |
| :composeApp:jsBrowserProductionWebpack \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --stacktrace | |
| - name: Upload Web Build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: web-production | |
| path: composeApp/build/dist/js/productionExecutable/ | |
| retention-days: 14 | |
| compression-level: 9 # Max compression for web assets | |
| # ================== Code Quality ================== | |
| code-quality: | |
| name: Code Quality | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| # Run in parallel with builds, don't wait for tests | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Setup JDK ${{ env.JAVA_VERSION }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: ${{ env.JAVA_VERSION }} | |
| distribution: ${{ env.JAVA_DISTRIBUTION }} | |
| cache: gradle | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v3 | |
| with: | |
| cache-read-only: true # Read-only for lint | |
| - name: Run Lint | |
| run: | | |
| ./gradlew \ | |
| :pocketbase-kt-sdk:lintDebug \ | |
| :shared:lintDebug \ | |
| --parallel \ | |
| --build-cache \ | |
| --configuration-cache \ | |
| --no-daemon \ | |
| --continue | |
| - name: Upload Lint Reports | |
| if: failure() # Only upload on failure | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lint-reports | |
| path: | | |
| **/build/reports/lint-results*.html | |
| retention-days: 3 | |
| # ================== Summary ================== | |
| ci-summary: | |
| name: CI Summary | |
| runs-on: ubuntu-latest | |
| needs: [test-unit, build-android, build-ios, build-desktop, build-web, code-quality] | |
| if: always() | |
| steps: | |
| - name: Check all jobs | |
| run: | | |
| echo "Unit Tests: ${{ needs.test-unit.result }}" | |
| echo "Android Build: ${{ needs.build-android.result }}" | |
| echo "iOS Build: ${{ needs.build-ios.result }}" | |
| echo "Desktop Build: ${{ needs.build-desktop.result }}" | |
| echo "Web Build: ${{ needs.build-web.result }}" | |
| echo "Code Quality: ${{ needs.code-quality.result }}" | |
| if [[ "${{ needs.test-unit.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.build-android.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.build-ios.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.build-desktop.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.build-web.result }}" == "failure" ]]; then | |
| echo "❌ CI pipeline failed" | |
| exit 1 | |
| else | |
| echo "✅ CI pipeline passed" | |
| fi |