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 5bc3bda96..c4bccd4b3 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 @@ -22,6 +22,7 @@ import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory import io.sentry.android.gradle.services.SentryModulesService import io.sentry.android.gradle.sourcecontext.OutputPaths import io.sentry.android.gradle.sourcecontext.SourceContext +import io.sentry.android.gradle.tasks.GenerateDistributionPropertiesTask import io.sentry.android.gradle.tasks.InjectSentryMetaPropertiesIntoAssetsTask import io.sentry.android.gradle.tasks.PropertiesFileOutputTask import io.sentry.android.gradle.tasks.SentryGenerateIntegrationListTask @@ -103,6 +104,15 @@ fun ApplicationAndroidComponentsExtension.configure( ) generateProguardUuidTask?.let { tasksGeneratingProperties.add(it) } + val generateDistributionPropertiesTask = + variant.configureDistributionPropertiesTask( + project, + extension, + sentryTelemetryProvider, + paths, + ) + generateDistributionPropertiesTask?.let { tasksGeneratingProperties.add(it) } + sentryVariant.configureNativeSymbolsTask( project, extension, @@ -372,6 +382,26 @@ private fun ApplicationVariant.configureProguardMappingsTasks( } } +private fun ApplicationVariant.configureDistributionPropertiesTask( + project: Project, + extension: SentryPluginExtension, + sentryTelemetryProvider: Provider, + paths: OutputPaths, +): TaskProvider? { + val variantName = name + if (extension.distribution.enabledVariants.get().contains(variantName)) { + return GenerateDistributionPropertiesTask.register( + project = project, + extension = extension, + sentryTelemetryProvider = sentryTelemetryProvider, + output = paths.distributionPropertiesDir, + taskSuffix = name.capitalized, + buildConfiguration = name, + ) + } + return null +} + /** * Configure the upload AAB and APK tasks and set them up as finalizers on the respective producer * tasks diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/OutputPaths.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/OutputPaths.kt index 31f46387f..83298cfcc 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/OutputPaths.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/OutputPaths.kt @@ -15,4 +15,5 @@ class OutputPaths(private val project: Project, variantName: String) { val bundleIdDir = dir("$variantDirectory/bundle-id") val sourceDir = dir("$variantDirectory/source-to-bundle") val bundleDir = dir("$variantDirectory/source-bundle") + val distributionPropertiesDir = dir("$variantDirectory/distribution-properties") } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTask.kt new file mode 100644 index 000000000..652a31ac1 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTask.kt @@ -0,0 +1,76 @@ +package io.sentry.android.gradle.tasks + +import io.sentry.android.gradle.extensions.SentryPluginExtension +import io.sentry.android.gradle.telemetry.SentryTelemetryService +import io.sentry.android.gradle.telemetry.withSentryTelemetry +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.TaskProvider + +@CacheableTask +abstract class GenerateDistributionPropertiesTask : PropertiesFileOutputTask() { + + init { + description = "Writes properties used to check for Build Distribution updates" + } + + @get:OutputFile + override val outputFile: Provider + get() = output.file(SENTRY_DISTRIBUTION_OUTPUT) + + @get:Input abstract val orgSlug: Property + + @get:Input abstract val projectSlug: Property + + @get:Input abstract val orgAuthToken: Property + + @get:Input abstract val buildConfiguration: Property + + @TaskAction + fun generateProperties() { + outputFile.get().asFile.writer().use { writer -> + orgSlug.orNull?.let { writer.appendLine("$ORG_SLUG_PROPERTY=$it") } + projectSlug.orNull?.let { writer.appendLine("$PROJECT_SLUG_PROPERTY=$it") } + orgAuthToken.orNull?.let { writer.appendLine("$DISTRIBUTION_AUTH_TOKEN_PROPERTY=$it") } + writer.appendLine("$BUILD_CONFIGURATION_PROPERTY=${buildConfiguration.get()}") + } + } + + companion object { + internal const val SENTRY_DISTRIBUTION_OUTPUT = "sentry-distribution.properties" + const val ORG_SLUG_PROPERTY = "io.sentry.distribution.org-slug" + const val PROJECT_SLUG_PROPERTY = "io.sentry.distribution.project-slug" + const val DISTRIBUTION_AUTH_TOKEN_PROPERTY = "io.sentry.distribution.auth-token" + const val BUILD_CONFIGURATION_PROPERTY = "io.sentry.distribution.build-configuration" + + fun register( + project: Project, + extension: SentryPluginExtension, + sentryTelemetryProvider: Provider? = null, + output: Provider, + taskSuffix: String, + buildConfiguration: String, + ): TaskProvider { + return project.tasks.register( + "generateSentryDistributionProperties$taskSuffix", + GenerateDistributionPropertiesTask::class.java, + ) { task -> + task.output.set(output) + task.withSentryTelemetry(extension, sentryTelemetryProvider) + // TODO we should check if the org and project are available in sentry.properties + task.orgSlug.set(extension.org) + task.projectSlug.set(extension.projectName) + // TODO we should have a separate authToken for Build Distribution + task.orgAuthToken.set(extension.authToken) + task.buildConfiguration.set(buildConfiguration) + } + } + } +} diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTaskTest.kt new file mode 100644 index 000000000..303409bbd --- /dev/null +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/GenerateDistributionPropertiesTaskTest.kt @@ -0,0 +1,58 @@ +package io.sentry.android.gradle.tasks + +import io.sentry.android.gradle.extensions.SentryPluginExtension +import io.sentry.android.gradle.tasks.GenerateDistributionPropertiesTask.Companion.BUILD_CONFIGURATION_PROPERTY +import io.sentry.android.gradle.tasks.GenerateDistributionPropertiesTask.Companion.DISTRIBUTION_AUTH_TOKEN_PROPERTY +import io.sentry.android.gradle.tasks.GenerateDistributionPropertiesTask.Companion.ORG_SLUG_PROPERTY +import io.sentry.android.gradle.tasks.GenerateDistributionPropertiesTask.Companion.PROJECT_SLUG_PROPERTY +import io.sentry.android.gradle.util.PropertiesUtil +import java.io.File +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.gradle.api.Project +import org.gradle.api.tasks.TaskProvider +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Test + +class GenerateDistributionPropertiesTaskTest { + + @Test + fun `generate distribution properties with all fields`() { + val project = createProject() + val extension = project.extensions.findByName("sentry") as SentryPluginExtension + extension.org.set("test-org") + extension.projectName.set("test-project") + extension.authToken.set("test-token") + + val task: TaskProvider = + GenerateDistributionPropertiesTask.register( + project, + extension, + null, + project.layout.buildDirectory.dir("dummy/folder/"), + "test", + "debug", + ) + + val outputDir = File(project.buildDir, "dummy/folder/") + outputDir.mkdirs() + + task.get().generateProperties() + + val expectedFile = File(project.buildDir, "dummy/folder/sentry-distribution.properties") + assertTrue(expectedFile.exists()) + + val props = PropertiesUtil.load(expectedFile) + assertEquals("test-org", props.getProperty(ORG_SLUG_PROPERTY)) + assertEquals("test-project", props.getProperty(PROJECT_SLUG_PROPERTY)) + assertEquals("test-token", props.getProperty(DISTRIBUTION_AUTH_TOKEN_PROPERTY)) + assertEquals("debug", props.getProperty(BUILD_CONFIGURATION_PROPERTY)) + } + + private fun createProject(): Project { + with(ProjectBuilder.builder().build()) { + plugins.apply("io.sentry.android.gradle") + return this + } + } +}