diff --git a/.github/workflows/test-matrix-agp-gradle.yaml b/.github/workflows/test-matrix-agp-gradle.yaml index 530eb5eb8..b72598657 100644 --- a/.github/workflows/test-matrix-agp-gradle.yaml +++ b/.github/workflows/test-matrix-agp-gradle.yaml @@ -12,7 +12,7 @@ concurrency: jobs: publish-dry-run: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index abe22e397..20665fa11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixes - Kotlin Compiler Plugin: Fix API incompatibility with Kotlin 2.1.20 ([#857](https://github.com/getsentry/sentry-android-gradle-plugin/pull/857)) +- Make `SentryGenerateIntegrationListTask` configuration-cache compatible ([#866](https://github.com/getsentry/sentry-android-gradle-plugin/pull/866)) ### Internal diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt index cfe9ee3cd..daa83c706 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt @@ -29,7 +29,6 @@ import io.sentry.android.gradle.tasks.SentryUploadProguardMappingsTask import io.sentry.android.gradle.tasks.configureNativeSymbolsTask import io.sentry.android.gradle.tasks.dependencies.SentryExternalDependenciesReportTaskFactory import io.sentry.android.gradle.telemetry.SentryTelemetryService -import io.sentry.android.gradle.telemetry.withSentryTelemetry import io.sentry.android.gradle.transforms.MetaInfStripTransform import io.sentry.android.gradle.util.AgpVersions import io.sentry.android.gradle.util.AgpVersions.isAGP74 @@ -204,18 +203,13 @@ fun AndroidComponentsExtension<*, *, *>.configure( } val manifestUpdater = - project.tasks.register( - "${variant.name}SentryGenerateIntegrationListTask", - SentryGenerateIntegrationListTask::class.java, - ) { - it.integrations.set( - sentryModulesService.map { service -> - service.retrieveEnabledInstrumentationFeatures() - } - ) - it.usesService(sentryModulesService) - it.withSentryTelemetry(extension, sentryTelemetryProvider) - } + SentryGenerateIntegrationListTask.register( + project, + extension, + sentryTelemetryProvider, + sentryModulesService, + variant.name, + ) variant.artifacts .use(manifestUpdater) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt index e952800e5..29ba71bb3 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt @@ -28,7 +28,7 @@ abstract class SentryModulesService : @set:Synchronized var externalModules: Map = emptyMap() - fun retrieveEnabledInstrumentationFeatures(): Set { + fun retrieveEnabledInstrumentationFeatures(project: Project): Provider> { val features = parameters.features .get() @@ -52,7 +52,7 @@ abstract class SentryModulesService : features.add("DexGuard") } - return features + return project.provider { features } } private fun isInstrumentationEnabled(feature: InstrumentationFeature): Boolean { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryGenerateIntegrationListTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryGenerateIntegrationListTask.kt index 8fdb65210..730545865 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryGenerateIntegrationListTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryGenerateIntegrationListTask.kt @@ -1,11 +1,17 @@ package io.sentry.android.gradle.tasks import io.sentry.android.gradle.ManifestWriter +import io.sentry.android.gradle.extensions.SentryPluginExtension +import io.sentry.android.gradle.services.SentryModulesService +import io.sentry.android.gradle.telemetry.SentryTelemetryService +import io.sentry.android.gradle.telemetry.withSentryTelemetry import io.sentry.android.gradle.util.info import java.nio.file.Files import java.nio.file.StandardCopyOption import org.gradle.api.DefaultTask +import org.gradle.api.Project import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Provider import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input @@ -14,14 +20,11 @@ import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity.NONE import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.TaskProvider @CacheableTask abstract class SentryGenerateIntegrationListTask : DefaultTask() { - companion object { - const val ATTR_INTEGRATIONS = "io.sentry.gradle-plugin-integrations" - } - init { description = "Writes enabled integrations to AndroidManifest.xml" } @@ -58,4 +61,29 @@ abstract class SentryGenerateIntegrationListTask : DefaultTask() { ) } } + + companion object { + const val ATTR_INTEGRATIONS = "io.sentry.gradle-plugin-integrations" + + fun register( + project: Project, + extension: SentryPluginExtension, + sentryTelemetryProvider: Provider?, + sentryModulesService: Provider, + variantName: String, + ): TaskProvider { + return project.tasks.register( + "${variantName}SentryGenerateIntegrationListTask", + SentryGenerateIntegrationListTask::class.java, + ) { + it.integrations.set( + sentryModulesService.flatMap { service -> + service.retrieveEnabledInstrumentationFeatures(project) + } + ) + it.usesService(sentryModulesService) + it.withSentryTelemetry(extension, sentryTelemetryProvider) + } + } + } } diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/integration/SentryPluginConfigurationCacheTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/integration/SentryPluginConfigurationCacheTest.kt index 6064eabcb..a3618997d 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/integration/SentryPluginConfigurationCacheTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/integration/SentryPluginConfigurationCacheTest.kt @@ -6,12 +6,15 @@ import io.sentry.android.gradle.util.AgpVersions import io.sentry.android.gradle.util.GradleVersions import io.sentry.android.gradle.util.SemVer import io.sentry.android.gradle.verifyDependenciesReportAndroid +import io.sentry.android.gradle.verifyIntegrationList import java.io.File import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue +import org.gradle.testkit.runner.TaskOutcome import org.gradle.util.GradleVersion import org.hamcrest.CoreMatchers.`is` +import org.jetbrains.kotlin.gradle.report.TaskExecutionState.UP_TO_DATE import org.junit.Assume.assumeThat import org.junit.Test @@ -306,4 +309,61 @@ class SentryPluginConfigurationCacheTest : val outputWithConfigCache = runner.build().output assertTrue { "Configuration cache entry reused." in outputWithConfigCache } } + + @Test + fun `generate integration list task respects configuration cache`() { + assumeThat( + "SentryGenerateIntegrationListTask only supports " + + "configuration cache from Gradle 7.5 onwards", + GradleVersions.CURRENT >= GradleVersions.VERSION_7_5, + `is`(true), + ) + appBuildFile.writeText( + // language=Groovy + """ + plugins { + id "com.android.application" + id "io.sentry.android.gradle" + } + + android { + namespace 'com.example' + } + + sentry { + includeNativeSources = false + uploadNativeSymbols = false + includeProguardMapping = false + autoUploadProguardMapping = false + tracingInstrumentation.features = [] + telemetry = false + } + """ + .trimIndent() + ) + runner.appendArguments(":app:assembleDebug").appendArguments("--configuration-cache") + + val firstBuild = runner.build().output + assertTrue { "Configuration cache entry stored." in firstBuild } + + val integrationsFirst = verifyIntegrationList(testProjectDir.root, "debug", signed = false) + assertEquals( + listOf("AppStartInstrumentation", "LogcatInstrumentation"), + integrationsFirst.sorted(), + ) + + // second build should reuse config cache and tasks should be up-to-date as nothing changed + val secondBuild = runner.build() + assertEquals( + TaskOutcome.UP_TO_DATE, + secondBuild.task(":app:debugSentryGenerateIntegrationListTask")?.outcome, + ) + assertTrue { "Configuration cache entry reused." in secondBuild.output } + + val integrationsSecond = verifyIntegrationList(testProjectDir.root, "debug", signed = false) + assertEquals( + listOf("AppStartInstrumentation", "LogcatInstrumentation"), + integrationsSecond.sorted(), + ) + } }