Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
304 changes: 275 additions & 29 deletions .github/workflows/build+test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,317 @@ concurrency:

jobs:
build:
runs-on: macos-15-intel
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set Up JDK
uses: actions/setup-java@v3
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '17'
cache: 'gradle'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

# Allow us to run the command
- name: Change wrapper permissions
run: chmod +x ./gradlew

# Run Build & Test the Project
- name: Build gradle project
run: ./gradlew build
# Assemble (no tests / no lint — those run in dedicated jobs)
- name: Assemble gradle project
run: ./gradlew assemble -x lint -x lintDebug -x lintVitalRelease

- name: Build test project
run: ./gradlew :app:assembleAndroidTest -DtestBuildType=debug -x lint -x lintDebug -x lintVitalRelease

- name: Run tests on Firebase Test Lab
uses: asadmansr/Firebase-Test-Lab-Action@v1.0
with:
arg-spec: '.github/firebase-tests.yml:android-pixel-7'
env:
SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}

unit-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Change wrapper permissions
run: chmod +x ./gradlew

- name: Run unit tests with coverage
run: ./gradlew :superwall:testDebugUnitTest -x lint -x lintDebug -x lintVitalRelease

- name: Upload unit test coverage data
uses: actions/upload-artifact@v4
if: always()
with:
name: unit-test-coverage
path: superwall/build/jacoco/

- name: Upload unit test reports
uses: actions/upload-artifact@v4
if: always()
with:
name: unit-test-reports
path: |
superwall/build/reports/tests/
superwall/build/test-results/

# Single-runner pre-job that populates the AVD snapshot cache before the matrix
# fans out, so the 5 shards don't race to create the same snapshot on a cold cache.
# On a warm cache this job is ~30s of overhead (checkout + cache restore + skip).
warm-emulator-cache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Run unit and instrumentation tests with coverage
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-api33-google_apis-x86_64-pixel_7_pro-v1

# Everything below only runs on a cold cache. On a warm cache the job ends here.
- name: Free disk space
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: jlumbroso/free-disk-space@v1.3.1
with:
android: false
tool-cache: true
dotnet: true
haskell: true
swap-storage: true
docker-images: false
large-packages: false

- name: Enable KVM
if: steps.avd-cache.outputs.cache-hit != 'true'
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Set up JDK 17
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: gradle/actions/setup-gradle@v3

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
target: google_apis
arch: x86_64
profile: pixel_7_pro
force-avd-creation: true
force-avd-creation: false
ram-size: 4096M
emulator-boot-timeout: 1800
disable-animations: true
disable-animations: false
emulator-options: >
-no-window
-gpu swiftshader_indirect
-no-boot-anim
-noaudio
-camera-back none
-camera-front none
script: echo "Generated AVD snapshot for caching."

instrumentation-tests:
runs-on: ubuntu-latest
needs: [warm-emulator-cache]
# Run even if warm-emulator-cache failed — the per-shard warm-up step below
# acts as a fallback. Don't run on workflow cancellation.
if: ${{ !cancelled() }}
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2, 3, 4]

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

# Reclaim ~10+ GB on the runner before the AVD cache restore + emulator boot.
# Ubuntu runners ship near-full and instrumentation jobs can hit "no space
# left on device" around the emulator boot or coverage write otherwise.
- name: Free disk space
uses: jlumbroso/free-disk-space@v1.3.1
with:
android: false # keep Android SDK / tools
tool-cache: true # rm -rf "$AGENT_TOOLSDIRECTORY"
dotnet: true # rm -rf /usr/share/dotnet
haskell: true # rm -rf /opt/ghc
swap-storage: true # rm -f /mnt/swapfile (4 GiB)
docker-images: false # slow (~16s), skip
large-packages: false # slow (includes google-cloud-sdk), skip

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Change wrapper permissions
run: chmod +x ./gradlew

# Cache the AVD across runs. Key is shared across all 5 shards because they
# all use the same api-level/target/arch/profile, so they all share one snapshot.
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-api33-google_apis-x86_64-pixel_7_pro-v1

# Cold-cache only: create the AVD and let the emulator save a snapshot on shutdown.
# Note the deliberate ABSENCE of -no-snapshot-save in emulator-options here, and
# disable-animations is left false so the snapshot is generic and reusable.
- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
target: google_apis
arch: x86_64
profile: pixel_7_pro
force-avd-creation: false
ram-size: 4096M
emulator-boot-timeout: 1800
disable-animations: false
emulator-options: >
-no-window
-gpu swiftshader_indirect
-no-boot-anim
-noaudio
-camera-back none
-camera-front none
script: echo "Generated AVD snapshot for caching."

- name: Run instrumentation tests with coverage (shard ${{ matrix.shard }}/5)
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
target: google_apis
arch: x86_64
profile: pixel_7_pro
force-avd-creation: false
ram-size: 4096M
emulator-boot-timeout: 1800
disable-animations: true
emulator-options: >
-no-snapshot-save
script: ./gradlew :superwall:jacocoFullReport
-no-window
-gpu swiftshader_indirect
-no-boot-anim
-noaudio
-camera-back none
-camera-front none
script: >
./gradlew :superwall:connectedDebugAndroidTest
-Pandroid.testInstrumentationRunnerArguments.numShards=5
-Pandroid.testInstrumentationRunnerArguments.shardIndex=${{ matrix.shard }}
-x lint -x lintDebug -x lintVitalRelease

- name: Build test project
run: ./gradlew :app:assembleAndroidTest -DtestBuildType=debug
- name: Upload instrumentation test coverage data
uses: actions/upload-artifact@v4
if: always()
with:
name: instrumentation-test-coverage-shard-${{ matrix.shard }}
path: superwall/build/outputs/code_coverage/

- name: Upload test reports
- name: Upload instrumentation test reports
uses: actions/upload-artifact@v4
if: always()
with:
name: test-reports
name: instrumentation-test-reports-shard-${{ matrix.shard }}
path: |
**/build/reports/tests/
**/build/test-results/
**/build/reports/androidTests/connected/
**/build/outputs/code_coverage/
superwall/build/reports/androidTests/connected/
superwall/build/outputs/androidTest-results/

coverage-report:
runs-on: ubuntu-latest
needs: [unit-tests, instrumentation-tests]
# Run as long as unit-tests succeeded, even if some/all instrumentation
# shards failed — a partial report is better than no report or badge update.
if: ${{ !cancelled() && needs.unit-tests.result == 'success' }}

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Change wrapper permissions
run: chmod +x ./gradlew

- name: Download unit test coverage data
uses: actions/download-artifact@v4
with:
name: unit-test-coverage
path: superwall/build/jacoco/

- name: Download instrumentation test coverage data (all shards)
uses: actions/download-artifact@v4
with:
pattern: instrumentation-test-coverage-shard-*
path: superwall/build/outputs/code_coverage/

- name: Generate combined coverage report
run: ./gradlew :superwall:compileDebugSources :superwall:jacocoTestReport -x testDebugUnitTest -x lint -x lintDebug -x lintVitalRelease

- name: Upload coverage report
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -107,10 +360,3 @@ jobs:
git commit -m "Update coverage badge [skip ci]"
git push origin HEAD:${{ github.head_ref }}
fi

- name: Run tests on Firebase Test Lab
uses: asadmansr/Firebase-Test-Lab-Action@v1.0
with:
arg-spec: '.github/firebase-tests.yml:android-pixel-7'
env:
SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}
2 changes: 1 addition & 1 deletion .github/workflows/on-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ jobs:
with:
token: ${{ secrets.MAIN_REPO_PAT }}
repository: superwall/paywall-next
event-type: android-release
event-type: android-release
Loading