Skip to content

Commit b3704c8

Browse files
authored
Add gh workflow for testing release builds against AGP matrix (#2439)
1 parent 5fd37fa commit b3704c8

File tree

17 files changed

+242
-20
lines changed

17 files changed

+242
-20
lines changed

.github/workflows/agp-matrix.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: AGP Matrix Sample Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- release/**
8+
pull_request:
9+
10+
jobs:
11+
cancel-previous-workflow:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Cancel Previous Runs
15+
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # [email protected]
16+
with:
17+
access_token: ${{ github.token }}
18+
19+
agp-matrix-sample-release:
20+
runs-on: ubuntu-latest
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
agp: ['7.3.0','7.4.0-rc01','8.0.0-alpha09']
25+
26+
name: AGP Matrix Sample Release - AGP ${{ matrix.agp }}
27+
env:
28+
VERSION_AGP: ${{ matrix.agp }}
29+
30+
steps:
31+
- name: Checkout Repo
32+
uses: actions/checkout@v2
33+
34+
- name: Setup Java Version
35+
uses: actions/setup-java@v2
36+
with:
37+
distribution: 'temurin'
38+
java-version: '17'
39+
40+
- name: Build the Release variant
41+
uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef # pin@v2
42+
with:
43+
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
44+
arguments: sentry-android-integration-tests:sentry-test-agp:assembleRelease

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Fixes
1010

1111
- Use minSdk compatible `Objects` class ([#2436](https://github.com/getsentry/sentry-java/pull/2436))
12+
- Prevent R8 from warning on missing classes, as we check for their presence at runtime ([#2439](https://github.com/getsentry/sentry-java/pull/2439))
1213

1314
### Features
1415

buildSrc/src/main/java/Config.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import java.math.BigDecimal
22

33
object Config {
4+
val AGP = System.getenv("VERSION_AGP") ?: "7.3.0"
45
val kotlinVersion = "1.6.10"
56
val kotlinStdLib = "stdlib-jdk8"
67

@@ -11,7 +12,7 @@ object Config {
1112
val composeVersion = "1.1.1"
1213

1314
object BuildPlugins {
14-
val androidGradle = "com.android.tools.build:gradle:7.3.0"
15+
val androidGradle = "com.android.tools.build:gradle:$AGP"
1516
val kotlinGradlePlugin = "gradle-plugin"
1617
val buildConfig = "com.github.gmazzo.buildconfig"
1718
val buildConfigVersion = "3.0.3"
@@ -130,6 +131,7 @@ object Config {
130131
val composeNavigation = "androidx.navigation:navigation-compose:$navigationVersion"
131132
val composeActivity = "androidx.activity:activity-compose:1.4.0"
132133
val composeFoundation = "androidx.compose.foundation:foundation:$composeVersion"
134+
val composeUi = "androidx.compose.ui:ui:$composeVersion"
133135
val composeFoundationLayout = "androidx.compose.foundation:foundation-layout:$composeVersion"
134136
val composeMaterial = "androidx.compose.material3:material3:1.0.0-alpha13"
135137

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ org.gradle.parallel=true
66
# AndroidX required by AGP >= 3.6.x
77
android.useAndroidX=true
88

9+
# Required by AGP >= 8.0.x
10+
android.defaults.buildfeatures.buildconfig=true
11+
912
# Release information
1013
versionName=6.10.0
1114

sentry-android-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ dependencies {
108108
testImplementation(projects.sentryTestSupport)
109109
testImplementation(projects.sentryAndroidFragment)
110110
testImplementation(projects.sentryAndroidTimber)
111+
testImplementation(projects.sentryComposeHelper)
112+
testImplementation(projects.sentryAndroidNdk)
111113
testRuntimeOnly(Config.Libs.timber)
112114
testRuntimeOnly(Config.Libs.fragment)
113115
}

sentry-android-core/proguard-rules.pro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
# don't warn jetbrains annotations
2222
-dontwarn org.jetbrains.annotations.**
23-
# don't warn about missing classes (mainly for Guardsquare's proguard).
24-
# We are checking for their presence at runtime
23+
# don't warn about missing classes, as we are checking for their presence at runtime
2524
-dontwarn io.sentry.android.timber.SentryTimberIntegration
2625
-dontwarn io.sentry.android.fragment.FragmentLifecycleIntegration
26+
-dontwarn io.sentry.compose.gestures.ComposeGestureTargetLocator
2727

2828
# To ensure that stack traces is unambiguous
2929
# https://developer.android.com/studio/build/shrink-code#decode-stack-trace

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
@SuppressWarnings("Convert2MethodRef") // older AGP versions do not support method references
4242
final class AndroidOptionsInitializer {
4343

44+
static final String SENTRY_COMPOSE_INTEGRATION_CLASS_NAME =
45+
"io.sentry.compose.gestures.ComposeGestureTargetLocator";
46+
47+
static final String COMPOSE_CLASS_NAME = "androidx.compose.ui.node.Owner";
48+
4449
/** private ctor */
4550
private AndroidOptionsInitializer() {}
4651

@@ -143,15 +148,15 @@ static void initializeIntegrationsAndProcessors(
143148
if (options.getGestureTargetLocators().isEmpty()) {
144149
final List<GestureTargetLocator> gestureTargetLocators = new ArrayList<>(2);
145150
gestureTargetLocators.add(new AndroidViewGestureTargetLocator(isAndroidXScrollViewAvailable));
146-
try {
151+
152+
final boolean isComposeUpstreamAvailable =
153+
loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options);
154+
final boolean isComposeAvailable =
155+
(isComposeUpstreamAvailable
156+
&& loadClass.isClassAvailable(SENTRY_COMPOSE_INTEGRATION_CLASS_NAME, options));
157+
158+
if (isComposeAvailable) {
147159
gestureTargetLocators.add(new ComposeGestureTargetLocator());
148-
} catch (NoClassDefFoundError error) {
149-
options
150-
.getLogger()
151-
.log(
152-
SentryLevel.DEBUG,
153-
"ComposeGestureTargetLocator not available, consider adding the `sentry-compose` library.",
154-
error);
155160
}
156161
options.setGestureTargetLocators(gestureTargetLocators);
157162
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<uses-sdk
5+
tools:overrideLibrary="
6+
io.sentry.compose,
7+
io.sentry.android.ndk,
8+
androidx.navigation.compose,
9+
androidx.activity.compose,
10+
androidx.compose.animation,
11+
androidx.lifecycle.viewmodel.compose,
12+
androidx.compose.foundation.layout,
13+
androidx.compose.animation.core,
14+
androidx.compose.ui,
15+
androidx.compose.ui.text,
16+
androidx.compose.runtime.saveable,
17+
androidx.compose.ui.graphics,
18+
androidx.compose.ui.unit,
19+
androidx.compose.ui.geometry,
20+
androidx.compose.ui.util"/>
21+
</manifest>

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ import io.sentry.ILogger
88
import io.sentry.MainEventProcessor
99
import io.sentry.SentryOptions
1010
import io.sentry.android.core.cache.AndroidEnvelopeCache
11+
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator
1112
import io.sentry.android.core.internal.modules.AssetsModulesLoader
1213
import io.sentry.android.core.internal.util.AndroidMainThreadChecker
1314
import io.sentry.android.fragment.FragmentLifecycleIntegration
1415
import io.sentry.android.timber.SentryTimberIntegration
16+
import io.sentry.compose.gestures.ComposeGestureTargetLocator
1517
import org.junit.runner.RunWith
1618
import org.mockito.kotlin.any
19+
import org.mockito.kotlin.eq
1720
import org.mockito.kotlin.mock
1821
import org.mockito.kotlin.whenever
1922
import java.io.File
@@ -66,7 +69,7 @@ class AndroidOptionsInitializerTest {
6669

6770
fun initSutWithClassLoader(
6871
minApi: Int = 16,
69-
classToLoad: Class<*>? = null,
72+
classesToLoad: List<String> = emptyList(),
7073
isFragmentAvailable: Boolean = false,
7174
isTimberAvailable: Boolean = false
7275
) {
@@ -89,7 +92,7 @@ class AndroidOptionsInitializerTest {
8992
sentryOptions,
9093
context,
9194
buildInfo,
92-
createClassMock(classToLoad),
95+
createClassMock(classesToLoad),
9396
isFragmentAvailable,
9497
isTimberAvailable
9598
)
@@ -101,10 +104,14 @@ class AndroidOptionsInitializerTest {
101104
return buildInfo
102105
}
103106

104-
private fun createClassMock(clazz: Class<*>?): LoadClass {
107+
private fun createClassMock(classes: List<String>): LoadClass {
105108
val loadClassMock = mock<LoadClass>()
106-
whenever(loadClassMock.loadClass(any(), any())).thenReturn(clazz)
107-
whenever(loadClassMock.isClassAvailable(any(), any<ILogger>())).thenReturn(clazz != null)
109+
classes.forEach {
110+
whenever(loadClassMock.loadClass(eq(it), any()))
111+
.thenReturn(Class.forName(it, false, this::class.java.classLoader))
112+
whenever(loadClassMock.isClassAvailable(eq(it), any<SentryOptions>()))
113+
.thenReturn(true)
114+
}
108115
return loadClassMock
109116
}
110117
}
@@ -267,23 +274,23 @@ class AndroidOptionsInitializerTest {
267274

268275
@Test
269276
fun `NdkIntegration will load SentryNdk class and add to the integration list`() {
270-
fixture.initSutWithClassLoader(classToLoad = SentryNdk::class.java)
277+
fixture.initSutWithClassLoader(classesToLoad = listOfNotNull(NdkIntegration.SENTRY_NDK_CLASS_NAME))
271278

272279
val actual = fixture.sentryOptions.integrations.firstOrNull { it is NdkIntegration }
273280
assertNotNull((actual as NdkIntegration).sentryNdkClass)
274281
}
275282

276283
@Test
277284
fun `NdkIntegration won't be enabled because API is lower than 16`() {
278-
fixture.initSutWithClassLoader(minApi = 14, classToLoad = SentryNdk::class.java)
285+
fixture.initSutWithClassLoader(minApi = 14, classesToLoad = listOfNotNull(NdkIntegration.SENTRY_NDK_CLASS_NAME))
279286

280287
val actual = fixture.sentryOptions.integrations.firstOrNull { it is NdkIntegration }
281288
assertNull((actual as NdkIntegration).sentryNdkClass)
282289
}
283290

284291
@Test
285292
fun `NdkIntegration won't be enabled, if class not found`() {
286-
fixture.initSutWithClassLoader(classToLoad = null)
293+
fixture.initSutWithClassLoader(classesToLoad = emptyList())
287294

288295
val actual = fixture.sentryOptions.integrations.firstOrNull { it is NdkIntegration }
289296
assertNull((actual as NdkIntegration).sentryNdkClass)
@@ -455,4 +462,26 @@ class AndroidOptionsInitializerTest {
455462

456463
assertTrue { fixture.sentryOptions.mainThreadChecker is AndroidMainThreadChecker }
457464
}
465+
466+
@Test
467+
fun `does not install ComposeGestureTargetLocator, if sentry-compose is not available`() {
468+
fixture.initSutWithClassLoader()
469+
470+
assertTrue { fixture.sentryOptions.gestureTargetLocators.size == 1 }
471+
assertTrue { fixture.sentryOptions.gestureTargetLocators[0] is AndroidViewGestureTargetLocator }
472+
}
473+
474+
@Test
475+
fun `installs ComposeGestureTargetLocator, if sentry-compose is available`() {
476+
fixture.initSutWithClassLoader(
477+
classesToLoad = listOf(
478+
AndroidOptionsInitializer.COMPOSE_CLASS_NAME,
479+
AndroidOptionsInitializer.SENTRY_COMPOSE_INTEGRATION_CLASS_NAME
480+
)
481+
)
482+
483+
assertTrue { fixture.sentryOptions.gestureTargetLocators.size == 2 }
484+
assertTrue { fixture.sentryOptions.gestureTargetLocators[0] is AndroidViewGestureTargetLocator }
485+
assertTrue { fixture.sentryOptions.gestureTargetLocators[1] is ComposeGestureTargetLocator }
486+
}
458487
}

sentry-android-integration-tests/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
* [App metrics test specification (yaml)](./metrics-test.yml)
66
* [Espresso-based benchmarks](./sentry-uitest-android-benchmark) - run within SauceLabs (see /.sauce/*.yml)
77
* [Espresso-based UI tests](./sentry-uitest-android) - run within SauceLabs (see /.sauce/*.yml)
8+
* [Sample app for testing against AGP compatibility matrix](./sentry-test-agp)

0 commit comments

Comments
 (0)