Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -372,6 +382,26 @@ private fun ApplicationVariant.configureProguardMappingsTasks(
}
}

private fun ApplicationVariant.configureDistributionPropertiesTask(
project: Project,
extension: SentryPluginExtension,
sentryTelemetryProvider: Provider<SentryTelemetryService>,
paths: OutputPaths,
): TaskProvider<GenerateDistributionPropertiesTask>? {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Original file line number Diff line number Diff line change
@@ -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<RegularFile>
get() = output.file(SENTRY_DISTRIBUTION_OUTPUT)

@get:Input abstract val orgSlug: Property<String>

@get:Input abstract val projectSlug: Property<String>

@get:Input abstract val orgAuthToken: Property<String>

@get:Input abstract val buildConfiguration: Property<String>

@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("$ORG_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 ORG_AUTH_TOKEN_PROPERTY = "io.sentry.distribution.org-auth-token"
const val BUILD_CONFIGURATION_PROPERTY = "io.sentry.distribution.build-configuration"

fun register(
project: Project,
extension: SentryPluginExtension,
sentryTelemetryProvider: Provider<SentryTelemetryService>? = null,
output: Provider<Directory>,
taskSuffix: String,
buildConfiguration: String,
): TaskProvider<GenerateDistributionPropertiesTask> {
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah, this is a good point! We also check ext for org and project names, but I'm not sure if anyone is really using extras to set that. Maybe we should get rid of it in the upcoming major altogether

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point. I have a ticket to follow up on this. I added a note about ext. https://linear.app/getsentry/issue/EME-398/support-environment-variables-and-sentryproperties-for

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's more of a security topic, but idk if it's fine to inject and expose the auth token at runtime, given that we recommend hiding it in an env variable even on CI, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. We will make these custom grained token in the future: See Hector’s comment here: #999 (comment)

task.buildConfiguration.set(buildConfiguration)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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.ORG_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> =
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(ORG_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
}
}
}
Loading