Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gh workflow for testing release builds against AGP matrix #2439

Merged
merged 9 commits into from
Dec 28, 2022
Merged
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
44 changes: 44 additions & 0 deletions .github/workflows/agp-matrix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: AGP Matrix Sample Release

on:
push:
branches:
- main
- release/**
pull_request:

jobs:
cancel-previous-workflow:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # pin@0.11.0
with:
access_token: ${{ github.token }}

agp-matrix-sample-release:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
agp: ['7.3.0','7.4.0-rc01','8.0.0-alpha09']

name: AGP Matrix Sample Release - AGP ${{ matrix.agp }}
env:
VERSION_AGP: ${{ matrix.agp }}

steps:
- name: Checkout Repo
uses: actions/checkout@v2

- name: Setup Java Version
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '17'

- name: Build the Release variant
uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef # pin@v2
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
arguments: sentry-android-integration-tests:sentry-test-agp:assembleRelease
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Fixes

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

### Features

Expand Down
4 changes: 3 additions & 1 deletion buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import java.math.BigDecimal

object Config {
val AGP = System.getenv("VERSION_AGP") ?: "7.3.0"
val kotlinVersion = "1.6.10"
val kotlinStdLib = "stdlib-jdk8"

Expand All @@ -11,7 +12,7 @@ object Config {
val composeVersion = "1.1.1"

object BuildPlugins {
val androidGradle = "com.android.tools.build:gradle:7.3.0"
val androidGradle = "com.android.tools.build:gradle:$AGP"
val kotlinGradlePlugin = "gradle-plugin"
val buildConfig = "com.github.gmazzo.buildconfig"
val buildConfigVersion = "3.0.3"
Expand Down Expand Up @@ -130,6 +131,7 @@ object Config {
val composeNavigation = "androidx.navigation:navigation-compose:$navigationVersion"
val composeActivity = "androidx.activity:activity-compose:1.4.0"
val composeFoundation = "androidx.compose.foundation:foundation:$composeVersion"
val composeUi = "androidx.compose.ui:ui:$composeVersion"
val composeFoundationLayout = "androidx.compose.foundation:foundation-layout:$composeVersion"
val composeMaterial = "androidx.compose.material3:material3:1.0.0-alpha13"

Expand Down
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ org.gradle.parallel=true
# AndroidX required by AGP >= 3.6.x
android.useAndroidX=true

# Required by AGP >= 8.0.x
android.defaults.buildfeatures.buildconfig=true

# Release information
versionName=6.10.0

Expand Down
2 changes: 2 additions & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ dependencies {
testImplementation(projects.sentryTestSupport)
testImplementation(projects.sentryAndroidFragment)
testImplementation(projects.sentryAndroidTimber)
testImplementation(projects.sentryComposeHelper)
testImplementation(projects.sentryAndroidNdk)
testRuntimeOnly(Config.Libs.timber)
testRuntimeOnly(Config.Libs.fragment)
}
4 changes: 2 additions & 2 deletions sentry-android-core/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

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

# To ensure that stack traces is unambiguous
# https://developer.android.com/studio/build/shrink-code#decode-stack-trace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
@SuppressWarnings("Convert2MethodRef") // older AGP versions do not support method references
final class AndroidOptionsInitializer {

static final String SENTRY_COMPOSE_INTEGRATION_CLASS_NAME =
"io.sentry.compose.gestures.ComposeGestureTargetLocator";

static final String COMPOSE_CLASS_NAME = "androidx.compose.ui.node.Owner";

/** private ctor */
private AndroidOptionsInitializer() {}

Expand Down Expand Up @@ -143,15 +148,15 @@ static void initializeIntegrationsAndProcessors(
if (options.getGestureTargetLocators().isEmpty()) {
final List<GestureTargetLocator> gestureTargetLocators = new ArrayList<>(2);
gestureTargetLocators.add(new AndroidViewGestureTargetLocator(isAndroidXScrollViewAvailable));
try {

final boolean isComposeUpstreamAvailable =
loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options);
final boolean isComposeAvailable =
(isComposeUpstreamAvailable
&& loadClass.isClassAvailable(SENTRY_COMPOSE_INTEGRATION_CLASS_NAME, options));

if (isComposeAvailable) {
gestureTargetLocators.add(new ComposeGestureTargetLocator());
} catch (NoClassDefFoundError error) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"ComposeGestureTargetLocator not available, consider adding the `sentry-compose` library.",
error);
}
options.setGestureTargetLocators(gestureTargetLocators);
}
Expand Down
21 changes: 21 additions & 0 deletions sentry-android-core/src/test/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android">

<uses-sdk
tools:overrideLibrary="
io.sentry.compose,
io.sentry.android.ndk,
androidx.navigation.compose,
androidx.activity.compose,
androidx.compose.animation,
androidx.lifecycle.viewmodel.compose,
androidx.compose.foundation.layout,
androidx.compose.animation.core,
androidx.compose.ui,
androidx.compose.ui.text,
androidx.compose.runtime.saveable,
androidx.compose.ui.graphics,
androidx.compose.ui.unit,
androidx.compose.ui.geometry,
androidx.compose.ui.util"/>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import io.sentry.ILogger
import io.sentry.MainEventProcessor
import io.sentry.SentryOptions
import io.sentry.android.core.cache.AndroidEnvelopeCache
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator
import io.sentry.android.core.internal.modules.AssetsModulesLoader
import io.sentry.android.core.internal.util.AndroidMainThreadChecker
import io.sentry.android.fragment.FragmentLifecycleIntegration
import io.sentry.android.timber.SentryTimberIntegration
import io.sentry.compose.gestures.ComposeGestureTargetLocator
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.File
Expand Down Expand Up @@ -66,7 +69,7 @@ class AndroidOptionsInitializerTest {

fun initSutWithClassLoader(
minApi: Int = 16,
classToLoad: Class<*>? = null,
classesToLoad: List<String> = emptyList(),
isFragmentAvailable: Boolean = false,
isTimberAvailable: Boolean = false
) {
Expand All @@ -89,7 +92,7 @@ class AndroidOptionsInitializerTest {
sentryOptions,
context,
buildInfo,
createClassMock(classToLoad),
createClassMock(classesToLoad),
isFragmentAvailable,
isTimberAvailable
)
Expand All @@ -101,10 +104,14 @@ class AndroidOptionsInitializerTest {
return buildInfo
}

private fun createClassMock(clazz: Class<*>?): LoadClass {
private fun createClassMock(classes: List<String>): LoadClass {
val loadClassMock = mock<LoadClass>()
whenever(loadClassMock.loadClass(any(), any())).thenReturn(clazz)
whenever(loadClassMock.isClassAvailable(any(), any<ILogger>())).thenReturn(clazz != null)
classes.forEach {
whenever(loadClassMock.loadClass(eq(it), any()))
.thenReturn(Class.forName(it, false, this::class.java.classLoader))
whenever(loadClassMock.isClassAvailable(eq(it), any<SentryOptions>()))
.thenReturn(true)
}
return loadClassMock
}
}
Expand Down Expand Up @@ -267,23 +274,23 @@ class AndroidOptionsInitializerTest {

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

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

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

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

@Test
fun `NdkIntegration won't be enabled, if class not found`() {
fixture.initSutWithClassLoader(classToLoad = null)
fixture.initSutWithClassLoader(classesToLoad = emptyList())

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

assertTrue { fixture.sentryOptions.mainThreadChecker is AndroidMainThreadChecker }
}

@Test
fun `does not install ComposeGestureTargetLocator, if sentry-compose is not available`() {
fixture.initSutWithClassLoader()

assertTrue { fixture.sentryOptions.gestureTargetLocators.size == 1 }
assertTrue { fixture.sentryOptions.gestureTargetLocators[0] is AndroidViewGestureTargetLocator }
}

@Test
fun `installs ComposeGestureTargetLocator, if sentry-compose is available`() {
fixture.initSutWithClassLoader(
classesToLoad = listOf(
AndroidOptionsInitializer.COMPOSE_CLASS_NAME,
AndroidOptionsInitializer.SENTRY_COMPOSE_INTEGRATION_CLASS_NAME
)
)

assertTrue { fixture.sentryOptions.gestureTargetLocators.size == 2 }
assertTrue { fixture.sentryOptions.gestureTargetLocators[0] is AndroidViewGestureTargetLocator }
assertTrue { fixture.sentryOptions.gestureTargetLocators[1] is ComposeGestureTargetLocator }
}
}
1 change: 1 addition & 0 deletions sentry-android-integration-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
* [App metrics test specification (yaml)](./metrics-test.yml)
* [Espresso-based benchmarks](./sentry-uitest-android-benchmark) - run within SauceLabs (see /.sauce/*.yml)
* [Espresso-based UI tests](./sentry-uitest-android) - run within SauceLabs (see /.sauce/*.yml)
* [Sample app for testing against AGP compatibility matrix](./sentry-test-agp)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
plugins {
id("com.android.application")
}

android {
compileSdk = Config.Android.compileSdkVersion
namespace = "io.sentry.test.agp"

defaultConfig {
applicationId = "io.sentry.test.agp"
minSdk = Config.Android.minSdkVersionOkHttp
targetSdk = Config.Android.targetSdkVersion
versionCode = 1
versionName = "1.0"
}

buildTypes {
getByName("release") {
isMinifyEnabled = true
signingConfig = signingConfigs.getByName("debug") // to be able to run release mode
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt")
)
ndk {
abiFilters.clear()
abiFilters.add("arm64-v8a")
}
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding = true
}
signingConfigs {
getByName("debug") {
storeFile = rootProject.file("debug.keystore")
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}

variantFilter {
if (Config.Android.shouldSkipDebugVariant(buildType.name)) {
ignore = true
}
}
}
dependencies {
// just a mix of different dependencies to test how our logic for checking classes at runtime
// works with r8
implementation(projects.sentryAndroid)
implementation(projects.sentryAndroidOkhttp)
implementation(projects.sentryAndroidFragment)
implementation(projects.sentryAndroidTimber)

implementation(Config.Libs.fragment)
implementation(Config.Libs.timber)

implementation(Config.Libs.retrofit2)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity android:name=".MainActivity"/>
<meta-data android:name="io.sentry.dsn" android:value="https://1053864c67cc410aa1ffc9701bd6f93d@o447951.ingest.sentry.io/5428559" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.sentry.test.agp;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
helloWorld();
}

public void helloWorld() {
System.out.println("¯\\_(ツ)_/¯");
}
}
Loading