diff --git a/.github/badges/branches.svg b/.github/badges/branches.svg index 363f11af..c1f4c6f7 100644 --- a/.github/badges/branches.svg +++ b/.github/badges/branches.svg @@ -1 +1 @@ -branches39% \ No newline at end of file +branches28.7% \ No newline at end of file diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg index ea74503b..6fafb180 100644 --- a/.github/badges/jacoco.svg +++ b/.github/badges/jacoco.svg @@ -1 +1 @@ -coverage54.4% \ No newline at end of file +coverage37.6% \ No newline at end of file diff --git a/.github/workflows/build+test.yml b/.github/workflows/build+test.yml index 81a1dc20..7c8c8db8 100644 --- a/.github/workflows/build+test.yml +++ b/.github/workflows/build+test.yml @@ -18,41 +18,228 @@ 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 @@ -60,22 +247,88 @@ jobs: -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 @@ -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 }} diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 80a19bc3..8e2e371a 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -13,4 +13,4 @@ jobs: with: token: ${{ secrets.MAIN_REPO_PAT }} repository: superwall/paywall-next - event-type: android-release + event-type: android-release \ No newline at end of file diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 7bec972d..999a6cc6 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -5,8 +5,8 @@ on: branches: [ develop ] jobs: - test: - runs-on: macos-15-intel + unit-tests: + runs-on: ubuntu-latest steps: - name: Checkout code @@ -24,30 +24,177 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 - - name: Cache Gradle packages + - 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: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: AVD cache uses: actions/cache@v4 + id: avd-cache with: path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + ~/.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: 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." + + 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: + - name: Checkout code + 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 - - name: Run unit and instrumentation tests with coverage + # 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: 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 @@ -55,19 +202,89 @@ jobs: -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: 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: + - name: Checkout code + 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 diff --git a/gradle.properties b/gradle.properties index f2ca36db..74e3dc58 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,8 @@ android.enableR8.debugMode=true android.enableR8.fullMode=true android.debug.obsoleteApi=true mavenCentralPublishing=true -signAllPublications=true \ No newline at end of file +signAllPublications=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=true +org.gradle.workers.max=4 diff --git a/gradle/jacoco-combined.gradle b/gradle/jacoco-combined.gradle index 8f28556d..37be5679 100644 --- a/gradle/jacoco-combined.gradle +++ b/gradle/jacoco-combined.gradle @@ -135,7 +135,13 @@ project.afterEvaluate { // Create combined report task that includes BOTH unit tests and instrumentation tests tasks.register('jacocoTestReport', JacocoReport) { - dependsOn 'testDebugUnitTest' + // compileDebugKotlin / compileDebugJavaWithJavac are listed explicitly so + // the JacocoReport task declares a producer dependency on the class + // directories it reads via fileTree(...). Without this, Gradle 8 strict + // task validation fails when this task runs without testDebugUnitTest in + // the same graph (e.g. the CI coverage-report job, which downloads the + // .exec from an artifact and excludes testDebugUnitTest). + dependsOn 'testDebugUnitTest', 'compileDebugKotlin', 'compileDebugJavaWithJavac' // Note: Instrumentation tests must be run separately before generating the combined report // Run: ./gradlew :superwall:connectedDebugAndroidTest diff --git a/superwall-compose/build.gradle.kts b/superwall-compose/build.gradle.kts index b5abb471..c0f55be9 100644 --- a/superwall-compose/build.gradle.kts +++ b/superwall-compose/build.gradle.kts @@ -1,5 +1,4 @@ import groovy.json.JsonBuilder -import java.io.ByteArrayOutputStream import java.text.SimpleDateFormat import java.util.Date @@ -23,14 +22,20 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - val gitSha = - project - .exec { - commandLine("git", "rev-parse", "--short", "HEAD") - standardOutput = ByteArrayOutputStream() - }.toString() - .trim() - buildConfigField("String", "GIT_SHA", "\"${gitSha}\"") + // Configuration-cache safe: use GITHUB_SHA from CI when set, otherwise + // fall back to `git rev-parse` via providers.exec (tracked Provider API). + // Final fallback prevents a crash if .git is missing. + val gitSha: String = runCatching { + providers + .environmentVariable("GITHUB_SHA") + .map { it.take(7) } + .orElse( + providers.exec { + commandLine("git", "rev-parse", "--short", "HEAD") + }.standardOutput.asText.map { it.trim() }, + ).get() + }.getOrDefault("unknown") + buildConfigField("String", "GIT_SHA", "\"$gitSha\"") val currentTime = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()) buildConfigField("String", "BUILD_TIME", "\"${currentTime}\"") diff --git a/superwall/build.gradle.kts b/superwall/build.gradle.kts index 267012b6..58b9e38a 100644 --- a/superwall/build.gradle.kts +++ b/superwall/build.gradle.kts @@ -1,6 +1,5 @@ import groovy.json.JsonBuilder -import java.io.ByteArrayOutputStream import java.text.SimpleDateFormat import java.util.Date @@ -46,14 +45,20 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true - val gitSha = - project - .exec { - commandLine("git", "rev-parse", "--short", "HEAD") - standardOutput = ByteArrayOutputStream() - }.toString() - .trim() - buildConfigField("String", "GIT_SHA", "\"${gitSha}\"") + // Configuration-cache safe: use GITHUB_SHA from CI when set, otherwise + // fall back to `git rev-parse` via providers.exec (tracked Provider API). + // Final fallback prevents a crash if .git is missing. + val gitSha: String = runCatching { + providers + .environmentVariable("GITHUB_SHA") + .map { it.take(7) } + .orElse( + providers.exec { + commandLine("git", "rev-parse", "--short", "HEAD") + }.standardOutput.asText.map { it.trim() }, + ).get() + }.getOrDefault("unknown") + buildConfigField("String", "GIT_SHA", "\"$gitSha\"") val currentTime = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()) buildConfigField("String", "BUILD_TIME", "\"${currentTime}\"")