Build Nightly APK #31
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: Build Nightly APK | |
| on: | |
| schedule: | |
| # Runs at 02:17 America/Buenos_Aires. | |
| - cron: '17 5 * * *' | |
| workflow_dispatch: | |
| permissions: | |
| actions: read | |
| contents: read | |
| concurrency: | |
| group: nightly-apk-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| changes: | |
| if: github.actor != 'dependabot[bot]' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| current-sha: ${{ steps.nightly-changes.outputs.current-sha }} | |
| previous-sha: ${{ steps.nightly-changes.outputs.previous-sha }} | |
| should-build: ${{ steps.nightly-changes.outputs.should-build }} | |
| short-sha: ${{ steps.nightly-changes.outputs.short-sha }} | |
| steps: | |
| - name: Check for new main changes | |
| id: nightly-changes | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const workflow_id = 'nightly-apk.yml'; | |
| const currentSha = context.sha; | |
| const shortSha = currentSha.slice(0, 7); | |
| if (context.eventName === 'workflow_dispatch') { | |
| core.setOutput('current-sha', currentSha); | |
| core.setOutput('previous-sha', ''); | |
| core.setOutput('short-sha', shortSha); | |
| core.setOutput('should-build', 'true'); | |
| await core.summary | |
| .addHeading('Nightly APK') | |
| .addRaw(`Manual run requested for ${currentSha}. Building APKs.`) | |
| .write(); | |
| return; | |
| } | |
| const runs = await github.paginate(github.rest.actions.listWorkflowRuns, { | |
| owner, | |
| repo, | |
| workflow_id, | |
| branch: 'main', | |
| status: 'success', | |
| per_page: 20, | |
| }); | |
| const previousRun = runs.find((run) => run.id !== context.runId); | |
| const previousSha = previousRun?.head_sha ?? ''; | |
| const shouldBuild = previousSha !== currentSha; | |
| core.setOutput('current-sha', currentSha); | |
| core.setOutput('previous-sha', previousSha); | |
| core.setOutput('short-sha', shortSha); | |
| core.setOutput('should-build', shouldBuild ? 'true' : 'false'); | |
| const summary = core.summary.addHeading('Nightly APK'); | |
| if (shouldBuild) { | |
| summary.addRaw( | |
| previousSha | |
| ? `main moved from ${previousSha} to ${currentSha}. Building APKs.` | |
| : `No previous successful nightly was found. Building APKs for ${currentSha}.` | |
| ); | |
| } else { | |
| summary.addRaw(`main is still at ${currentSha}. Skipping APK build.`); | |
| } | |
| await summary.write(); | |
| build: | |
| needs: changes | |
| if: needs.changes.outputs.should-build == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up JDK 21 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: temurin | |
| java-version: '21' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v6 | |
| # The keystore password must never be hardcoded here: this file is public and the | |
| # cached .jks is restorable by fork-PR workflow runs, so a literal password hands | |
| # out the CI signing identity. Use the CI_KEYSTORE_PASSWORD repo secret for a | |
| # stable cached keystore; without the secret, fall back to an uncached throwaway | |
| # keystore with a random one-off password (signature varies per run). | |
| - name: Resolve CI keystore password | |
| env: | |
| CI_KEYSTORE_PASSWORD: ${{ secrets.CI_KEYSTORE_PASSWORD }} | |
| run: | | |
| if [ -n "$CI_KEYSTORE_PASSWORD" ]; then | |
| echo "KEYSTORE_PASSWORD=$CI_KEYSTORE_PASSWORD" >> "$GITHUB_ENV" | |
| echo "CI_KEYSTORE_SECRET_SET=true" >> "$GITHUB_ENV" | |
| else | |
| echo "KEYSTORE_PASSWORD=$(openssl rand -hex 24)" >> "$GITHUB_ENV" | |
| echo "CI_KEYSTORE_SECRET_SET=false" >> "$GITHUB_ENV" | |
| fi | |
| - name: Cache nightly keystore | |
| id: cache-keystore | |
| if: env.CI_KEYSTORE_SECRET_SET == 'true' | |
| uses: actions/cache@v5 | |
| with: | |
| path: pixelplayeross-nightly-ci.jks | |
| key: ${{ runner.os }}-nightly-keystore-pixelplayeross | |
| - name: Generate nightly keystore if not cached | |
| if: steps.cache-keystore.outputs.cache-hit != 'true' | |
| run: | | |
| keytool -genkey -v -keystore pixelplayeross-nightly-ci.jks -alias pixelplayeross-nightly-key -keyalg RSA -keysize 4096 -validity 10000 \ | |
| -storepass "$KEYSTORE_PASSWORD" -keypass "$KEYSTORE_PASSWORD" \ | |
| -dname "CN=PixelPlayerOSS Nightly, OU=Dev, O=PixelPlayerOSS, L=World, S=World, C=US" | |
| - name: Create keystore.properties | |
| run: | | |
| echo "storeFile=pixelplayeross-nightly-ci.jks" > keystore.properties | |
| echo "storePassword=$KEYSTORE_PASSWORD" >> keystore.properties | |
| echo "keyAlias=pixelplayeross-nightly-key" >> keystore.properties | |
| echo "keyPassword=$KEYSTORE_PASSWORD" >> keystore.properties | |
| - name: Build Phone nightly release APKs | |
| run: ./gradlew :app:assembleRelease -Ppixelplayer.enableAbiSplits=true | |
| - name: Verify Phone nightly split APKs | |
| run: | | |
| BUILD_TOOLS_VERSION="$(ls "$ANDROID_HOME/build-tools" | sort -V | tail -n 1)" | |
| for apk in \ | |
| app/build/outputs/apk/release/app-arm64-v8a-release.apk \ | |
| app/build/outputs/apk/release/app-armeabi-v7a-release.apk | |
| do | |
| "$ANDROID_HOME/build-tools/$BUILD_TOOLS_VERSION/aapt2" dump badging "$apk" >/dev/null | |
| "$ANDROID_HOME/build-tools/$BUILD_TOOLS_VERSION/apksigner" verify --verbose "$apk" | |
| done | |
| - name: Upload Phone nightly split APK artifacts | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: PixelPlayerOSS-phone-nightly-${{ needs.changes.outputs.short-sha }} | |
| path: | | |
| app/build/outputs/apk/release/app-arm64-v8a-release.apk | |
| app/build/outputs/apk/release/app-armeabi-v7a-release.apk | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 14 |