diff --git a/.github/workflows/benchmark-help-config.yml b/.github/workflows/benchmark-help-config.yml new file mode 100644 index 000000000..4a2af2853 --- /dev/null +++ b/.github/workflows/benchmark-help-config.yml @@ -0,0 +1,69 @@ +name: Benchmark help task configuration + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + benchmark-help-config: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout Repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + # Full history so gradle-profiler's git-checkout can reach both the + # base and head commits of the PR. + fetch-depth: 0 + + - name: Set up Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: 'temurin' + java-version: '17' + + - name: Install Gradle Profiler and benchmark the help task + env: + BASE_REF: ${{ github.event.pull_request.base.sha }} + HEAD_REF: ${{ github.event.pull_request.head.sha }} + run: | + curl -s "https://get.sdkman.io" | bash + source "$HOME/.sdkman/bin/sdkman-init.sh" + sdk install gradleprofiler 0.24.0 + gradle-profiler --benchmark \ + --scenario-file scripts/benchmark/help-config-cache.scenarios \ + --output-dir out/help-config + + - name: Upload results + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: help-config-benchmark + path: out/help-config/ + + - name: Build PR comment + run: python3 scripts/benchmark/help-config-comment.py out/help-config/benchmark.csv comment.md + + - name: Post comparison comment + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const fs = require('fs'); + const marker = ''; + const body = fs.readFileSync('comment.md', 'utf8'); + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const comments = await github.paginate(github.rest.issues.listComments, { + owner, repo, issue_number, + }); + const existing = comments.find((c) => c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body }); + } else { + await github.rest.issues.createComment({ owner, repo, issue_number, body }); + } 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 eb1b8ca06..f13811ea7 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 @@ -54,7 +54,6 @@ fun ApplicationAndroidComponentsExtension.configure( project: Project, extension: SentryPluginExtension, buildEvents: BuildEventListenerRegistryInternal, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ) { @@ -77,13 +76,13 @@ fun ApplicationAndroidComponentsExtension.configure( } if (extension.snapshots.enabled.get()) { - variant.configureSnapshotsTasks(project, extension, cliExecutable, sentryOrg, sentryProject) + variant.configureSnapshotsTasks(project, extension, sentryOrg, sentryProject) } if (isVariantAllowed(extension, variant.name, variant.flavorName, variant.buildType)) { val paths = OutputPaths(project, variant.name) val sentryTelemetryProvider = - variant.configureTelemetry(project, extension, cliExecutable, sentryOrg, buildEvents) + variant.configureTelemetry(project, extension, sentryOrg, buildEvents) variant.configureDependenciesTask(project, extension, sentryTelemetryProvider) @@ -106,7 +105,6 @@ fun ApplicationAndroidComponentsExtension.configure( sentryTelemetryProvider, paths, sourceFiles, - cliExecutable, sentryOrg, sentryProject, ) @@ -118,7 +116,6 @@ fun ApplicationAndroidComponentsExtension.configure( extension, sentryTelemetryProvider, paths, - cliExecutable, sentryOrg, sentryProject, ) @@ -139,7 +136,6 @@ fun ApplicationAndroidComponentsExtension.configure( project, extension, sentryTelemetryProvider, - cliExecutable, sentryOrg, sentryProject, ) @@ -257,7 +253,6 @@ fun ApplicationAndroidComponentsExtension.configure( project, extension, sentryTelemetryProvider, - cliExecutable, sentryOrg, sentryProject, ) @@ -269,7 +264,6 @@ fun ApplicationAndroidComponentsExtension.configure( private fun Variant.configureTelemetry( project: Project, extension: SentryPluginExtension, - cliExecutable: Provider, sentryOrg: String?, buildEvents: BuildEventListenerRegistryInternal, ): Provider { @@ -277,14 +271,7 @@ private fun Variant.configureTelemetry( val sentryTelemetryProvider = SentryTelemetryService.register(project) project.gradle.taskGraph.whenReady { sentryTelemetryProvider.get().start { - SentryTelemetryService.createParameters( - project, - variant, - extension, - cliExecutable, - sentryOrg, - "Android", - ) + SentryTelemetryService.createParameters(project, variant, extension, sentryOrg, "Android") } buildEvents.onOperationCompletion(sentryTelemetryProvider) } @@ -297,7 +284,6 @@ private fun Variant.configureSourceBundleTasks( sentryTelemetryProvider: Provider, paths: OutputPaths, sourceFiles: Provider>?, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ): SourceContext.SourceContextTasks? { @@ -313,7 +299,6 @@ private fun Variant.configureSourceBundleTasks( variant, paths, sourceFiles, - cliExecutable, sentryOrg, sentryProject, taskSuffix, @@ -354,7 +339,6 @@ private fun ApplicationVariant.configureProguardMappingsTasks( extension: SentryPluginExtension, sentryTelemetryProvider: Provider, paths: OutputPaths, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ): TaskProvider? { @@ -386,7 +370,6 @@ private fun ApplicationVariant.configureProguardMappingsTasks( extension, sentryTelemetryProvider, debug = extension.debug, - cliExecutable = cliExecutable, generateUuidTask = generateUuidTask, sentryProperties = sentryProps, mappingFiles = mappings, @@ -460,7 +443,6 @@ private fun ApplicationVariant.configureDistributionPropertiesTask( private fun ApplicationVariant.configureSnapshotsTasks( project: Project, extension: SentryPluginExtension, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ) { @@ -478,7 +460,6 @@ private fun ApplicationVariant.configureSnapshotsTasks( project = project, extension = extension, sentryTelemetryProvider = null, - cliExecutable = cliExecutable, sentryOrgOverride = sentryOrg, sentryProjectOverride = sentryProject, applicationId = applicationId, @@ -557,7 +538,6 @@ fun Variant.configureUploadAppTasks( project: Project, extension: SentryPluginExtension, sentryTelemetryProvider: Provider, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ): Pair, TaskProvider> { @@ -570,7 +550,6 @@ fun Variant.configureUploadAppTasks( extension, sentryTelemetryProvider, debug = extension.debug, - cliExecutable = cliExecutable, appBundle = variant.bundle, apk = variant.apk, sentryOrg = sentryOrg?.let { project.provider { it } } ?: extension.org, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryCliProvider.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryCliProvider.kt index bd7a44d7c..44e96fc21 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryCliProvider.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryCliProvider.kt @@ -24,8 +24,6 @@ import org.gradle.api.tasks.Input internal object SentryCliProvider { - @field:Volatile private var memoizedCliPath: String? = null - /** * Return the correct sentry-cli executable path to use for the given project. This will look for * a sentry-cli executable in a local node_modules in case it was put there by sentry-react-native @@ -34,40 +32,26 @@ internal object SentryCliProvider { * without actually extracting it. */ @JvmStatic - @Synchronized fun getSentryCliPath( projectDir: DirectoryProperty, projectBuildDir: DirectoryProperty, rootDir: DirectoryProperty, ): String { - val cliPath = memoizedCliPath - if (!cliPath.isNullOrEmpty() && File(cliPath).exists()) { - logger.info { "Using memoized cli path: $cliPath" } - return cliPath - } - // If a path is provided explicitly use that first. logger.info { "Searching cli from sentry.properties file..." } searchCliInPropertiesFile(projectDir, rootDir)?.let { logger.info { "cli Found: $it" } - memoizedCliPath = it return@getSentryCliPath it } ?: logger.info { "sentry-cli not found in sentry.properties file" } - // next up try a packaged version of sentry-cli val cliResLocation = getCliLocationInResources() if (!cliResLocation.isNullOrBlank()) { logger.info { "cli present in resources: $cliResLocation" } - // just provide the target extraction path - // actual extraction will be done prior to task execution - val extractedResourcePath = - getCliResourcesExtractionPath(projectBuildDir).get().asFile.absolutePath - memoizedCliPath = extractedResourcePath - return extractedResourcePath + return getCliResourcesExtractionPath(projectBuildDir).get().asFile.absolutePath } logger.error { "Falling back to invoking `sentry-cli` from shell" } - return "sentry-cli".also { memoizedCliPath = it } + return "sentry-cli" } private fun getCliLocationInResources(): String? { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt index 14afdcdbc..6cfc94b4a 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt @@ -45,8 +45,6 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi project.pluginManager.withPlugin("com.android.application") { val androidComponentsExt = project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java) - val cliExecutable = project.cliExecutableProvider() - val extraProperties = project.extensions.getByName("ext") as ExtraPropertiesExtension val sentryOrgParameter = @@ -59,7 +57,6 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi project, extension, buildEvents, - cliExecutable, sentryOrgParameter, sentryProjectParameter, ) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/BundleSourcesTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/BundleSourcesTask.kt index 9a405c7ea..9a897d17c 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/BundleSourcesTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/BundleSourcesTask.kt @@ -77,7 +77,6 @@ abstract class BundleSourcesTask : SentryCliExecTask() { collectSourcesTask: TaskProvider, output: Provider, debug: Property, - cliExecutable: Provider, sentryOrg: Provider, sentryProject: Provider, sentryAuthToken: Property, @@ -95,7 +94,6 @@ abstract class BundleSourcesTask : SentryCliExecTask() { task.sentryAuthToken.set(sentryAuthToken) task.sentryUrl.set(sentryUrl) task.sourceDir.set(collectSourcesTask.flatMap { it.output }) - task.cliExecutable.set(cliExecutable) SentryPropertiesFileProvider.getPropertiesFilePath(project, variant)?.let { task.sentryProperties.set(File(it)) } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/SourceContext.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/SourceContext.kt index f1835b278..6ccc04b02 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/SourceContext.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/SourceContext.kt @@ -17,7 +17,6 @@ class SourceContext { variant: SentryVariant, paths: OutputPaths, sourceFiles: Provider>?, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, taskSuffix: String, @@ -54,7 +53,6 @@ class SourceContext { collectSourcesTask, output = paths.bundleDir, extension.debug, - cliExecutable, sentryOrg?.let { project.provider { it } } ?: extension.org, sentryProject?.let { project.provider { it } } ?: extension.projectName, extension.authToken, @@ -71,7 +69,6 @@ class SourceContext { variant, bundleSourcesTask, extension.debug, - cliExecutable, extension.autoUploadSourceContext, sentryOrg?.let { project.provider { it } } ?: extension.org, sentryProject?.let { project.provider { it } } ?: extension.projectName, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/UploadSourceBundleTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/UploadSourceBundleTask.kt index a807b029c..4fbcffdd0 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/UploadSourceBundleTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/sourcecontext/UploadSourceBundleTask.kt @@ -68,7 +68,6 @@ abstract class UploadSourceBundleTask : SentryCliExecTask() { variant: SentryVariant, bundleSourcesTask: TaskProvider, debug: Property, - cliExecutable: Provider, autoUploadSourceContext: Property, sentryOrg: Provider, sentryProject: Provider, @@ -87,7 +86,6 @@ abstract class UploadSourceBundleTask : SentryCliExecTask() { task.sentryAuthToken.set(sentryAuthToken) task.sentryUrl.set(sentryUrl) task.sourceBundleDir.set(bundleSourcesTask.flatMap { it.output }) - task.cliExecutable.set(cliExecutable) task.autoUploadSourceContext.set(autoUploadSourceContext) SentryPropertiesFileProvider.getPropertiesFilePath(project, variant)?.let { task.sentryProperties.set(File(it)) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTask.kt index 215029e4b..ff75e1ffb 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTask.kt @@ -22,8 +22,6 @@ abstract class SentryCliExecTask : Exec() { @get:Input @get:Optional abstract val debug: Property - @get:Input abstract val cliExecutable: Property - @get:InputFile @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) @@ -39,7 +37,9 @@ abstract class SentryCliExecTask : Exec() { @get:Internal abstract val sentryTelemetryService: Property - private val buildDirectory: DirectoryProperty = project.layout.buildDirectory + @get:Input abstract val cliExecutable: Property + + @get:Internal abstract val buildDirectory: DirectoryProperty override fun exec() { computeCommandLineArgs().let { @@ -92,8 +92,7 @@ abstract class SentryCliExecTask : Exec() { args.add(1, "/c") } - val cliPath = SentryCliProvider.maybeExtractFromResources(buildDirectory, cliExecutable.get()) - args.add(cliPath) + args.add(SentryCliProvider.maybeExtractFromResources(buildDirectory, cliExecutable.get())) args.addAll(preArgs()) getArguments(args) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTask.kt index b4bb1f22b..6ddd90f45 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTask.kt @@ -101,7 +101,6 @@ abstract class SentryUploadAppArtifactTask @Inject constructor(objectFactory: Ob debug: Property, appBundle: Provider, apk: Provider, - cliExecutable: Provider, sentryProperties: String?, sentryOrg: Provider, sentryProject: Provider, @@ -118,7 +117,7 @@ abstract class SentryUploadAppArtifactTask @Inject constructor(objectFactory: Ob ) { task -> task.workingDir(project.rootDir) task.debug.set(debug) - task.cliExecutable.set(cliExecutable) + task.sentryProperties.set(sentryProperties?.let { file -> project.file(file) }) task.bundle.set(appBundle) task.sentryOrganization.set(sentryOrg) @@ -148,7 +147,7 @@ abstract class SentryUploadAppArtifactTask @Inject constructor(objectFactory: Ob ) { task -> task.workingDir(project.rootDir) task.debug.set(debug) - task.cliExecutable.set(cliExecutable) + task.sentryProperties.set(sentryProperties?.let { file -> project.file(file) }) task.apk.set(apk) task.sentryOrganization.set(sentryOrg) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTask.kt index 77746e773..503776f24 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTask.kt @@ -31,8 +31,6 @@ abstract class SentryUploadNativeSymbolsTask : SentryCliExecTask() { @get:Internal abstract val variantName: Property - private val buildDir: Provider = project.layout.buildDirectory.asFile - override fun getArguments(args: MutableList) { args.add("debug-files") args.add("upload") @@ -44,7 +42,8 @@ abstract class SentryUploadNativeSymbolsTask : SentryCliExecTask() { // eg absoluteProjectFolderPath/build/intermediates/merged_native_libs/{variantName} // where {variantName} could be debug/release... args.add( - File(buildDir.get(), "intermediates/merged_native_libs/${variantName.get()}").absolutePath + File(buildDirectory.get().asFile, "intermediates/merged_native_libs/${variantName.get()}") + .absolutePath ) // Only include sources if includeNativeSources is enabled, as this is opt-in feature @@ -60,7 +59,6 @@ abstract class SentryUploadNativeSymbolsTask : SentryCliExecTask() { sentryTelemetryProvider: Provider, variantName: String, debug: Property, - cliExecutable: Provider, sentryProperties: String?, sentryOrg: Provider, sentryProject: Provider, @@ -78,7 +76,6 @@ abstract class SentryUploadNativeSymbolsTask : SentryCliExecTask() { task.workingDir(project.rootDir) task.debug.set(debug) task.autoUploadNativeSymbol.set(autoUploadNativeSymbols) - task.cliExecutable.set(cliExecutable) task.sentryProperties.set(sentryProperties?.let { file -> project.file(file) }) task.includeNativeSources.set(includeNativeSources) task.variantName.set(variantName) @@ -99,7 +96,6 @@ fun SentryVariant.configureNativeSymbolsTask( project: Project, extension: SentryPluginExtension, sentryTelemetryProvider: Provider, - cliExecutable: Provider, sentryOrg: String?, sentryProject: String?, ) { @@ -113,7 +109,6 @@ fun SentryVariant.configureNativeSymbolsTask( sentryTelemetryProvider = sentryTelemetryProvider, variantName = name, debug = extension.debug, - cliExecutable = cliExecutable, sentryProperties = sentryProps, autoUploadNativeSymbols = extension.autoUploadNativeSymbols, includeNativeSources = extension.includeNativeSources, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingsTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingsTask.kt index 31ef2b85b..eb1c88f24 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingsTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingsTask.kt @@ -89,7 +89,6 @@ abstract class SentryUploadProguardMappingsTask : SentryCliExecTask() { extension: SentryPluginExtension, sentryTelemetryProvider: Provider?, debug: Property, - cliExecutable: Provider, sentryProperties: String?, generateUuidTask: Provider, mappingFiles: Provider, @@ -108,7 +107,6 @@ abstract class SentryUploadProguardMappingsTask : SentryCliExecTask() { task.dependsOn(generateUuidTask) task.workingDir(project.rootDir) task.debug.set(debug) - task.cliExecutable.set(cliExecutable) task.sentryProperties.set(sentryProperties?.let { file -> project.file(file) }) task.uuidFile.set(generateUuidTask.flatMap { it.outputFile }) task.mappingsFiles = mappingFiles diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTask.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTask.kt index 3f5c95532..65724afef 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTask.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTask.kt @@ -75,7 +75,6 @@ abstract class SentryUploadSnapshotsTask : SentryCliExecTask() { project: Project, extension: SentryPluginExtension, sentryTelemetryProvider: Provider?, - cliExecutable: Provider, sentryOrgOverride: String?, sentryProjectOverride: String?, applicationId: Provider, @@ -88,7 +87,6 @@ abstract class SentryUploadSnapshotsTask : SentryCliExecTask() { ) { task -> task.workingDir(project.rootDir) task.debug.set(extension.debug) - task.cliExecutable.set(cliExecutable) task.sentryProperties.set(sentryProperties?.let { project.file(it) }) task.sentryOrganization.set( sentryOrgOverride?.let { project.provider { it } } ?: extension.org diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt index d58f976ed..bef59f221 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt @@ -18,32 +18,24 @@ import io.sentry.android.gradle.SentryPlugin import io.sentry.android.gradle.SentryPlugin.Companion.logger import io.sentry.android.gradle.SentryPropertiesFileProvider import io.sentry.android.gradle.extensions.SentryPluginExtension -import io.sentry.android.gradle.telemetry.SentryCliInfoValueSource.InfoParams -import io.sentry.android.gradle.telemetry.SentryCliVersionValueSource.VersionParams import io.sentry.android.gradle.util.AgpVersions import io.sentry.android.gradle.util.SentryCliException import io.sentry.android.gradle.util.error import io.sentry.android.gradle.util.getBuildServiceName import io.sentry.android.gradle.util.info -import io.sentry.android.gradle.util.setSentryPipelineEnv import io.sentry.exception.ExceptionMechanismException import io.sentry.gradle.common.SentryVariant import io.sentry.protocol.Mechanism import io.sentry.protocol.User -import java.io.ByteArrayOutputStream -import java.nio.charset.Charset -import javax.inject.Inject +import java.util.concurrent.TimeUnit +import kotlin.concurrent.thread import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.file.DirectoryProperty import org.gradle.api.internal.tasks.execution.ExecuteTaskBuildOperationDetails -import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import org.gradle.api.provider.ValueSource -import org.gradle.api.provider.ValueSourceParameters import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters.None -import org.gradle.api.tasks.Input import org.gradle.execution.RunRootBuildWorkBuildOperationType import org.gradle.internal.operations.BuildOperationDescriptor import org.gradle.internal.operations.BuildOperationListener @@ -51,7 +43,6 @@ import org.gradle.internal.operations.OperationFinishEvent import org.gradle.internal.operations.OperationIdentifier import org.gradle.internal.operations.OperationProgressEvent import org.gradle.internal.operations.OperationStartEvent -import org.gradle.process.ExecOperations import org.gradle.util.GradleVersion abstract class SentryTelemetryService : BuildService, BuildOperationListener, AutoCloseable { @@ -60,6 +51,7 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen private var transaction: ITransaction? = null private var didAddChildSpans: Boolean = false private var started: Boolean = false + private var pendingOrgLookupParams: SentryTelemetryServiceParams? = null @Synchronized fun start(paramsCallback: () -> SentryTelemetryServiceParams) { @@ -108,16 +100,11 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen hub.configureScope { scope -> scope.user = - User().also { user -> - startParameters.defaultSentryOrganization?.let { org -> - if (org != "-") { - user.id = org - } - } - startParameters.sentryOrganization?.let { user.id = it } - } + User().also { user -> startParameters.sentryOrganization?.let { user.id = it } } } + pendingOrgLookupParams = startParameters + started = true } } catch (t: Throwable) { @@ -125,7 +112,12 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen } } - override fun started(descriptor: BuildOperationDescriptor, event: OperationStartEvent) {} + override fun started(descriptor: BuildOperationDescriptor, event: OperationStartEvent) { + pendingOrgLookupParams?.let { params -> + pendingOrgLookupParams = null + fetchDefaultOrgInBackground(params) + } + } override fun progress(identifier: OperationIdentifier, event: OperationProgressEvent) {} @@ -227,6 +219,54 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen } } + private fun fetchDefaultOrgInBackground(params: SentryTelemetryServiceParams) { + val buildDir = params.cliBuildDir ?: return + val projectDir = params.cliProjectDir ?: return + val rootDir = params.cliRootDir ?: return + + thread(isDaemon = true, name = "sentry-cli-info") { + try { + val cliPath = SentryCliProvider.getSentryCliPath(projectDir, buildDir, rootDir) + val resolvedCli = SentryCliProvider.maybeExtractFromResources(buildDir, cliPath) + + val args = mutableListOf(resolvedCli) + params.cliUrl?.let { url -> + args.add("--url") + args.add(url) + } + args.add("--log-level=error") + args.add("info") + + val processBuilder = ProcessBuilder(args).redirectErrorStream(true) + params.cliPropertiesFilePath?.let { processBuilder.environment()["SENTRY_PROPERTIES"] = it } + params.cliAuthToken?.let { processBuilder.environment()["SENTRY_AUTH_TOKEN"] = it } + processBuilder.environment()["SENTRY_PIPELINE"] = + "sentry-gradle-plugin/${BuildConfig.Version}" + + val process = processBuilder.start() + val output = process.inputStream.bufferedReader().readText() + if (!process.waitFor(CLI_INFO_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { + process.destroyForcibly() + return@thread + } + + if (process.exitValue() == 0) { + ORG_REGEX.find(output)?.groupValues?.getOrNull(1)?.let { org -> + if (org != "-") { + hub.configureScope { scope -> + if (scope.user?.id == null) { + scope.user = User().also { it.id = org } + } + } + } + } + } + } catch (t: Throwable) { + SentryPlugin.logger.info { "Failed to fetch default org from sentry-cli: ${t.message}" } + } + } + } + override fun close() { if (transaction?.isFinished == false) { endRun() @@ -238,32 +278,21 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen val SENTRY_SAAS_DSN: String = "https://000e5dea9770b4537055f8a6d28c021e@o1.ingest.sentry.io/4506241308295168" val MECHANISM_TYPE: String = "GradleTelemetry" - private val orgRegex = Regex("""(?m)Default Organization: (.*)$""") - private val versionRegex = Regex("""(?m)sentry-cli (.*)$""") + private val ORG_REGEX = Regex("""(?m)Default Organization: (.*)$""") + private const val CLI_INFO_TIMEOUT_SECONDS = 5L fun createParameters( project: Project, variant: SentryVariant?, extension: SentryPluginExtension, - cliExecutable: Provider, sentryOrg: String?, buildType: String, ): SentryTelemetryServiceParams { val tags = extraTagsFromExtension(project, extension) val org = sentryOrg ?: extension.org.orNull - val isTelemetryEnabled = extension.telemetry.get() - - // if telemetry is disabled we don't even need to exec sentry-cli as telemetry service - // will be no-op - if (isTelemetryEnabled) { - paramsWithExecAvailable(project, cliExecutable, extension, variant, org, buildType, tags) - ?.let { - return it - } - } - // fallback: sentry-cli is not available or e.g. auth token is not configured + return SentryTelemetryServiceParams( - isTelemetryEnabled, + extension.telemetry.get(), extension.telemetryDsn.get(), org, buildType, @@ -271,73 +300,13 @@ abstract class SentryTelemetryService : BuildService, BuildOperationListen extension.debug.get(), saas = extension.url.orNull == null, cliVersion = BuildConfig.CliVersion, - ) - } - - private fun paramsWithExecAvailable( - project: Project, - cliExecutable: Provider, - extension: SentryPluginExtension, - variant: SentryVariant?, - sentryOrg: String?, - buildType: String, - tags: Map, - ): SentryTelemetryServiceParams? { - var cliVersion: String? = BuildConfig.CliVersion - var defaultSentryOrganization: String? = null - val infoOutput = - project.providers - .of(SentryCliInfoValueSource::class.java) { cliVS -> - cliVS.parameters.buildDirectory.set(project.layout.buildDirectory) - cliVS.parameters.cliExecutable.set(cliExecutable) - cliVS.parameters.authToken.set(extension.authToken) - cliVS.parameters.url.set(extension.url) - variant?.let { v -> - cliVS.parameters.propertiesFilePath.set( - SentryPropertiesFileProvider.getPropertiesFilePath(project, v) - ) - } - } - .get() - - if (infoOutput.isEmpty()) { - return null - } - val isSaas = infoOutput.contains("(?m)Sentry Server: .*sentry.io$".toRegex()) - - orgRegex.find(infoOutput)?.let { matchResult -> - val groupValues = matchResult.groupValues - if (groupValues.size > 1) { - defaultSentryOrganization = groupValues[1] - } - } - - val versionOutput = - project.providers - .of(SentryCliVersionValueSource::class.java) { cliVS -> - cliVS.parameters.buildDirectory.set(project.layout.buildDirectory) - cliVS.parameters.cliExecutable.set(cliExecutable) - cliVS.parameters.url.set(extension.url) - } - .get() - - versionRegex.find(versionOutput)?.let { matchResult -> - val groupValues = matchResult.groupValues - if (groupValues.size > 1) { - cliVersion = groupValues[1] - } - } - - return SentryTelemetryServiceParams( - extension.telemetry.get(), - extension.telemetryDsn.get(), - sentryOrg, - buildType, - tags, - extension.debug.get(), - defaultSentryOrganization, - isSaas, - cliVersion = cliVersion, + cliProjectDir = project.objects.directoryProperty().apply { set(project.projectDir) }, + cliBuildDir = project.layout.buildDirectory, + cliRootDir = project.objects.directoryProperty().apply { set(project.rootDir) }, + cliAuthToken = extension.authToken.orNull, + cliUrl = extension.url.orNull, + cliPropertiesFilePath = + variant?.let { SentryPropertiesFileProvider.getPropertiesFilePath(project, it) }, ) } @@ -419,104 +388,6 @@ class SentryMinimalException(message: String) : RuntimeException(message) { } } -abstract class SentryCliInfoValueSource : ValueSource { - interface InfoParams : ValueSourceParameters { - @get:Input val buildDirectory: DirectoryProperty - - @get:Input val cliExecutable: Property - - @get:Input val propertiesFilePath: Property - - @get:Input val url: Property - - @get:Input val authToken: Property - } - - @get:Inject abstract val execOperations: ExecOperations - - override fun obtain(): String? { - val stdOutput = ByteArrayOutputStream() - val errOutput = ByteArrayOutputStream() - - val execResult = - execOperations.exec { - it.isIgnoreExitValue = true - SentryCliProvider.maybeExtractFromResources( - parameters.buildDirectory, - parameters.cliExecutable.get(), - ) - - val args = mutableListOf(parameters.cliExecutable.get()) - - parameters.url.orNull?.let { url -> - args.add("--url") - args.add(url) - } - - args.add("--log-level=error") - args.add("info") - - parameters.propertiesFilePath.orNull?.let { path -> - it.environment("SENTRY_PROPERTIES", path) - } - - parameters.authToken.orNull?.let { authToken -> - it.environment("SENTRY_AUTH_TOKEN", authToken) - } - - it.setSentryPipelineEnv() - - it.commandLine(args) - it.standardOutput = stdOutput - it.errorOutput = errOutput - } - - if (execResult.exitValue == 0) { - return String(stdOutput.toByteArray(), Charset.defaultCharset()) - } else { - logger.info { - "Failed to execute sentry-cli info. Error Output: " + - String(errOutput.toByteArray(), Charset.defaultCharset()) - } - return "" - } - } -} - -abstract class SentryCliVersionValueSource : ValueSource { - interface VersionParams : ValueSourceParameters { - @get:Input val buildDirectory: DirectoryProperty - - @get:Input val cliExecutable: Property - - @get:Input val url: Property - } - - @get:Inject abstract val execOperations: ExecOperations - - override fun obtain(): String { - val output = ByteArrayOutputStream() - execOperations.exec { - it.isIgnoreExitValue = true - SentryCliProvider.maybeExtractFromResources( - parameters.buildDirectory, - parameters.cliExecutable.get(), - ) - - val args = mutableListOf(parameters.cliExecutable.get()) - - args.add("--log-level=error") - args.add("--version") - - it.setSentryPipelineEnv() - - it.commandLine(args) - it.standardOutput = output - } - return String(output.toByteArray(), Charset.defaultCharset()) - } -} - data class SentryTelemetryServiceParams( val sendTelemetry: Boolean, val dsn: String, @@ -524,7 +395,12 @@ data class SentryTelemetryServiceParams( val buildType: String, val extraTags: Map, val isDebug: Boolean, - val defaultSentryOrganization: String? = null, val saas: Boolean? = null, val cliVersion: String? = null, + val cliProjectDir: DirectoryProperty? = null, + val cliBuildDir: DirectoryProperty? = null, + val cliRootDir: DirectoryProperty? = null, + val cliAuthToken: String? = null, + val cliUrl: String? = null, + val cliPropertiesFilePath: String? = null, ) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryCliExec.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryCliExec.kt index 55a25fecd..6ec141789 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryCliExec.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryCliExec.kt @@ -1,10 +1,11 @@ package io.sentry.android.gradle.util import io.sentry.BuildConfig +import io.sentry.android.gradle.cliExecutableProvider +import io.sentry.android.gradle.tasks.SentryCliExecTask import io.sentry.android.gradle.util.CliFailureReason.OUTDATED import java.io.ByteArrayOutputStream import org.gradle.api.GradleException -import org.gradle.api.tasks.Exec import org.gradle.process.ExecSpec fun ExecSpec.setSentryPipelineEnv() { @@ -15,7 +16,10 @@ fun ExecSpec.setSentryPipelineEnv() { * An ext function for tasks that wrap sentry-cli, which provides common error handling. Must be * called at configuration phase (=when registering a task). */ -fun Exec.asSentryCliExec() { +fun SentryCliExecTask.asSentryCliExec() { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + isIgnoreExitValue = true // this is a workaround, otherwise doFirst is not needed // https://github.com/gradle/gradle/issues/16535 diff --git a/plugin-build/src/main/kotlin/io/sentry/jvm/gradle/SentryJvmPlugin.kt b/plugin-build/src/main/kotlin/io/sentry/jvm/gradle/SentryJvmPlugin.kt index d16e9b9b0..e86a9e54c 100644 --- a/plugin-build/src/main/kotlin/io/sentry/jvm/gradle/SentryJvmPlugin.kt +++ b/plugin-build/src/main/kotlin/io/sentry/jvm/gradle/SentryJvmPlugin.kt @@ -3,7 +3,6 @@ package io.sentry.jvm.gradle import io.sentry.android.gradle.SentryPlugin import io.sentry.android.gradle.SentryTasksProvider import io.sentry.android.gradle.autoinstall.installDependencies -import io.sentry.android.gradle.cliExecutableProvider import io.sentry.android.gradle.extensions.SentryPluginExtension import io.sentry.android.gradle.sourcecontext.OutputPaths import io.sentry.android.gradle.sourcecontext.SourceContext @@ -48,7 +47,6 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi val javaVariant = JavaVariant(project, javaExtension) val outputPaths = OutputPaths(project, "java") - val cliExecutable = project.cliExecutableProvider() val extraProperties = project.extensions.getByName("ext") as ExtraPropertiesExtension @@ -66,7 +64,6 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi project, javaVariant, extension, - cliExecutable, sentryOrgParameter, "JVM", ) @@ -90,7 +87,6 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi javaVariant, outputPaths, sourceFiles, - cliExecutable, sentryOrgParameter, sentryProjectParameter, "Java", diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/BundleSourcesTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/BundleSourcesTaskTest.kt index e865e88e1..785d441b6 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/BundleSourcesTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/BundleSourcesTaskTest.kt @@ -1,6 +1,7 @@ package io.sentry.android.gradle.tasks import com.google.common.truth.Truth.assertThat +import io.sentry.android.gradle.cliExecutableProvider import io.sentry.android.gradle.sourcecontext.BundleSourcesTask import io.sentry.android.gradle.sourcecontext.GenerateBundleIdTask.Companion.SENTRY_BUNDLE_ID_PROPERTY import java.io.File @@ -29,7 +30,7 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -37,7 +38,7 @@ class BundleSourcesTaskTest { val args = task.get().computeCommandLineArgs() - assertThat(args).contains("sentry-cli") + assertThat(args.first()).contains("sentry-cli") assertThat(args).contains("debug-files") assertThat(args).contains("bundle-jvm") assertThat(args).contains(sourceDir.absolutePath) @@ -57,7 +58,7 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -79,7 +80,6 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -101,7 +101,6 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -122,7 +121,6 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -142,7 +140,7 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -164,7 +162,7 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -224,7 +222,7 @@ class BundleSourcesTaskTest { val outDir = File(project.buildDir, "dummy/out") val task: TaskProvider = project.tasks.register("testBundleSources", BundleSourcesTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceDir.set(sourceDir) it.bundleIdFile.set(debugMetaPropertiesFile) it.output.set(outDir) @@ -244,6 +242,11 @@ class BundleSourcesTaskTest { } } + private fun SentryCliExecTask.configureCliPaths(project: Project) { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + } + private fun createDebugMetaProperties( project: Project, uuid: UUID = UUID.randomUUID(), diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTaskTest.kt index 404fd305a..b679b10cf 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryCliExecTaskTest.kt @@ -1,9 +1,9 @@ package io.sentry.android.gradle.tasks import io.sentry.android.gradle.SentryCliProvider +import io.sentry.android.gradle.cliExecutableProvider import java.io.File import kotlin.test.assertEquals -import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue import org.gradle.api.Project @@ -18,40 +18,18 @@ class SentryCliExecTaskTest { @get:Rule val tempDir = TemporaryFolder() @Test - fun `cli-executable is set correctly`() { + fun `cli path is resolved and extracted from resources`() { val project = createProject() - - val task: TaskProvider = - project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") - } - - val args = task.get().computeCommandLineArgs() - - assertTrue("sentry-cli" in args) - assertFalse("--org" in args) - assertFalse("--project" in args) - assertFalse("--log-level=debug" in args) - } - - @Test - fun `cli-executable is extracted from resources if required`() { - val project = createProject() - val cliPath = SentryCliProvider.getCliResourcesExtractionPath(project.layout.buildDirectory).get().asFile assertTrue(!cliPath.exists()) val task: TaskProvider = - project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set(cliPath.absolutePath) - } + project.tasks.register("testTask", TestTask::class.java) { it.configureCliPaths(project) } - // when the args are computed (usually during task execution) val args = task.get().computeCommandLineArgs() - // then the CLI should be extracted and set assertTrue(cliPath.exists()) assertEquals(cliPath.absolutePath, File(args[0]).absolutePath) } @@ -62,7 +40,7 @@ class SentryCliExecTaskTest { val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.debug.set(true) } @@ -77,7 +55,6 @@ class SentryCliExecTaskTest { val propertiesFile = project.file("dummy/folder/sentry.properties") val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sentryProperties.set(propertiesFile) } @@ -93,10 +70,7 @@ class SentryCliExecTaskTest { fun `with sentryAuthToken env variable is set correctly`() { val project = createProject() val task: TaskProvider = - project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") - it.sentryAuthToken.set("") - } + project.tasks.register("testTask", TestTask::class.java) { it.sentryAuthToken.set("") } task.get().setSentryAuthTokenEnv() @@ -106,10 +80,7 @@ class SentryCliExecTaskTest { @Test fun `without sentryProperties file SENTRY_PROPERTIES is not set`() { val project = createProject() - val task: TaskProvider = - project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") - } + val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) task.get().setSentryPropertiesEnv() @@ -121,7 +92,7 @@ class SentryCliExecTaskTest { val project = createProject() val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sentryOrganization.set("dummy-org") } @@ -136,7 +107,7 @@ class SentryCliExecTaskTest { val project = createProject() val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sentryProject.set("dummy-proj") } @@ -151,7 +122,7 @@ class SentryCliExecTaskTest { val project = createProject() val task: TaskProvider = project.tasks.register("testTask", TestTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sentryUrl.set("https://some-host.sentry.io") } @@ -168,6 +139,11 @@ class SentryCliExecTaskTest { } } + private fun SentryCliExecTask.configureCliPaths(project: Project) { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + } + abstract class TestTask : SentryCliExecTask() { override fun getArguments(args: MutableList) { // no-op diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTaskTest.kt index 7572c6a9e..e3d4d916d 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadAppArtifactTaskTest.kt @@ -4,6 +4,7 @@ import com.google.common.truth.FailureMetadata import com.google.common.truth.Subject import com.google.common.truth.Truth.assertAbout import com.google.common.truth.Truth.assertThat +import io.sentry.android.gradle.cliExecutableProvider import kotlin.test.assertEquals import kotlin.test.assertFailsWith import org.gradle.api.Project @@ -30,13 +31,13 @@ class SentryUploadAppArtifactTaskTest { val apkFile = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkFile) } val args = task.get().computeCommandLineArgs() - assertThat(args).contains("sentry-cli") + assertThat(args.first()).contains("sentry-cli") assertThat(args).contains("build") assertThat(args).contains("upload") assertThatStrings(args).containsEndingWith(dummyApkName) @@ -49,13 +50,13 @@ class SentryUploadAppArtifactTaskTest { val aabFile = project.aabFileProvider(dummyAabName) val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.bundle.set(aabFile) } val args = task.get().computeCommandLineArgs() - assertThat(args).contains("sentry-cli") + assertThat(args.first()).contains("sentry-cli") assertThat(args).contains("build") assertThat(args).contains("upload") assertThatStrings(args).containsEndingWith(dummyAabName) @@ -68,7 +69,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadProguardMapping", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.debug.set(true) } @@ -126,8 +127,8 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadProguardMapping", SentryUploadAppArtifactTask::class.java) { + it.configureCliPaths(project) it.sentryUrl.set("https://some-host.sentry.io") - it.cliExecutable.set("sentry-cli") it.apk.set(apkDir) } @@ -145,7 +146,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadProguardMapping", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.sentryOrganization.set("dummy-org") } @@ -163,7 +164,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadProguardMapping", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.sentryProject.set("dummy-proj") } @@ -180,7 +181,7 @@ class SentryUploadAppArtifactTaskTest { val nonExistentBundle = project.layout.buildDirectory.file("nonexistent/bundle.aab") val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.bundle.set(nonExistentBundle) } @@ -195,7 +196,7 @@ class SentryUploadAppArtifactTaskTest { val nonExistentApkDir = project.layout.buildDirectory.dir("nonexistent/apk") val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(nonExistentApkDir) } @@ -212,7 +213,7 @@ class SentryUploadAppArtifactTaskTest { emptyApkDir.get().asFile.mkdirs() val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(emptyApkDir) } @@ -226,7 +227,7 @@ class SentryUploadAppArtifactTaskTest { val project = createProject() val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) } val exception = assertFailsWith { task.get().computeCommandLineArgs() } @@ -240,7 +241,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.vcsHeadSha.set("abc123def456") it.vcsBaseSha.set("def456abc123") @@ -276,7 +277,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.installGroups.set(setOf("internal", "beta", "alpha")) } @@ -295,7 +296,7 @@ class SentryUploadAppArtifactTaskTest { val apkDir = project.apkDirProvider(dummyApkName) val task: TaskProvider = project.tasks.register("testUploadAppArtifact", SentryUploadAppArtifactTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.apk.set(apkDir) it.installGroups.set(emptySet()) } @@ -313,6 +314,11 @@ class SentryUploadAppArtifactTaskTest { } } + private fun SentryCliExecTask.configureCliPaths(project: Project) { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + } + private fun Project.apkDirProvider(path: String): Provider { val apkFileProvider = project.layout.buildDirectory.dir(path) apkFileProvider.get().asFile.parentFile.mkdirs() diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTaskTest.kt index b5ef6de5a..e62729f87 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadNativeSymbolsTaskTest.kt @@ -1,5 +1,6 @@ package io.sentry.android.gradle.tasks +import io.sentry.android.gradle.cliExecutableProvider import java.io.File import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -16,7 +17,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.includeNativeSources.set(false) it.variantName.set("debug") it.autoUploadNativeSymbol.set(true) @@ -24,7 +24,7 @@ class SentryUploadNativeSymbolsTaskTest { val args = task.computeCommandLineArgs() - assertTrue("sentry-cli" in args) + assertTrue(args.any { it.contains("sentry-cli") }) assertTrue("debug-files" in args) assertTrue("upload" in args) val path = File(project.buildDir, "intermediates/merged_native_libs/debug").absolutePath @@ -38,7 +38,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.includeNativeSources.set(false) it.variantName.set("debug") it.autoUploadNativeSymbol.set(false) @@ -54,7 +53,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.includeNativeSources.set(false) it.variantName.set("debug") it.autoUploadNativeSymbol.set(false) @@ -71,7 +69,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.includeNativeSources.set(true) it.variantName.set("debug") it.autoUploadNativeSymbol.set(true) @@ -108,7 +105,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.sentryOrganization.set("dummy-org") it.includeNativeSources.set(true) it.variantName.set("debug") @@ -126,7 +122,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.sentryProject.set("dummy-proj") it.includeNativeSources.set(true) it.variantName.set("debug") @@ -144,7 +139,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.sentryUrl.set("https://some-host.sentry.io") it.includeNativeSources.set(true) it.variantName.set("debug") @@ -162,7 +156,6 @@ class SentryUploadNativeSymbolsTaskTest { val project = createProject() val task = createTestTask(project) { - it.cliExecutable.set("sentry-cli") it.sentryUrl.set("https://some-host.sentry.io") it.includeNativeSources.set(true) it.variantName.set("debug") @@ -186,6 +179,10 @@ class SentryUploadNativeSymbolsTaskTest { block: (SentryUploadNativeSymbolsTask) -> Unit = {}, ): SentryUploadNativeSymbolsTask = project.tasks - .register("testUploadNativeSymbols", SentryUploadNativeSymbolsTask::class.java) { block(it) } + .register("testUploadNativeSymbols", SentryUploadNativeSymbolsTask::class.java) { + it.cliExecutable.set(project.cliExecutableProvider()) + it.buildDirectory.set(project.layout.buildDirectory) + block(it) + } .get() } diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingTaskTest.kt index 2c22b99a6..bff11c8c9 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadProguardMappingTaskTest.kt @@ -1,5 +1,6 @@ package io.sentry.android.gradle.tasks +import io.sentry.android.gradle.cliExecutableProvider import java.io.File import java.util.UUID import kotlin.test.assertEquals @@ -33,7 +34,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(true) @@ -41,7 +42,7 @@ class SentryUploadProguardMappingTaskTest { val args = task.get().computeCommandLineArgs() - assertTrue("sentry-cli" in args) + assertTrue(args.any { it.contains("sentry-cli") }) assertTrue("upload-proguard" in args) assertTrue("--uuid" in args) assertTrue(randomUuid.toString() in args) @@ -61,7 +62,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(true) @@ -69,7 +70,7 @@ class SentryUploadProguardMappingTaskTest { val args = task.get().computeCommandLineArgs() - assertTrue("sentry-cli" in args) + assertTrue(args.any { it.contains("sentry-cli") }) assertTrue("upload-proguard" in args) assertTrue("--uuid" in args) assertTrue(randomUuid.toString() in args) @@ -101,7 +102,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFiles it.autoUploadProguardMapping.set(true) @@ -123,7 +124,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(false) @@ -145,7 +146,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(false) @@ -217,8 +218,8 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { + it.configureCliPaths(project) it.sentryUrl.set("https://some-host.sentry.io") - it.cliExecutable.set("sentry-cli") it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(false) @@ -241,7 +242,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(false) @@ -265,7 +266,7 @@ class SentryUploadProguardMappingTaskTest { "testUploadProguardMapping", SentryUploadProguardMappingsTask::class.java, ) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.uuidFile.set(uuidFileProvider) it.mappingsFiles = mappingFile it.autoUploadProguardMapping.set(false) @@ -323,6 +324,11 @@ class SentryUploadProguardMappingTaskTest { } } + private fun SentryCliExecTask.configureCliPaths(project: Project) { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + } + private fun createFakeUuid( project: Project, uuid: UUID = UUID.randomUUID(), diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTaskTest.kt index ca2303dbc..0af083031 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/SentryUploadSnapshotsTaskTest.kt @@ -1,6 +1,7 @@ package io.sentry.android.gradle.tasks import com.google.common.truth.Truth.assertThat +import io.sentry.android.gradle.cliExecutableProvider import java.io.File import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -15,14 +16,13 @@ class SentryUploadSnapshotsTaskTest { @Test fun `cli-executable is set correctly`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) } val args = task.computeCommandLineArgs() - assertTrue("sentry-cli" in args) + assertTrue(args.any { it.contains("sentry-cli") }) assertTrue("build" in args) assertTrue("snapshots" in args) assertTrue("--app-id" in args) @@ -34,7 +34,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `--log-level=debug is set correctly`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) it.debug.set(true) @@ -68,7 +67,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `with sentryOrganization adds --org`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.sentryOrganization.set("dummy-org") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) @@ -83,7 +81,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `with sentryProject adds --project`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.sentryProject.set("dummy-proj") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) @@ -98,7 +95,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `with sentryUrl adds --url`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.sentryUrl.set("https://some-host.sentry.io") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) @@ -113,7 +109,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `the --url parameter is placed as the first argument`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.sentryUrl.set("https://some-host.sentry.io") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) @@ -127,7 +122,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `all vcs parameters are passed to CLI correctly`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) it.vcsHeadSha.set("abc123def456") @@ -159,7 +153,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `diffThreshold is passed to CLI when non-zero`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) it.diffThreshold.set(0.05) @@ -173,7 +166,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `diffThreshold is omitted when zero`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) it.diffThreshold.set(0.0) @@ -187,7 +179,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `diffThreshold is omitted when not set`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) } @@ -200,7 +191,6 @@ class SentryUploadSnapshotsTaskTest { @Test fun `vcs parameters are omitted when not set`() { val task = createTestTask { - it.cliExecutable.set("sentry-cli") it.appId.set("com.example") it.snapshotsPath.set(File("/path/to/snapshots")) } @@ -229,6 +219,10 @@ class SentryUploadSnapshotsTaskTest { block: (SentryUploadSnapshotsTask) -> Unit = {}, ): SentryUploadSnapshotsTask = project.tasks - .register("testUploadSnapshots", SentryUploadSnapshotsTask::class.java) { block(it) } + .register("testUploadSnapshots", SentryUploadSnapshotsTask::class.java) { + it.cliExecutable.set(project.cliExecutableProvider()) + it.buildDirectory.set(project.layout.buildDirectory) + block(it) + } .get() } diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/UploadSourceBundleTaskTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/UploadSourceBundleTaskTest.kt index 9f7457d8d..c0267b1d7 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/UploadSourceBundleTaskTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/tasks/UploadSourceBundleTaskTest.kt @@ -1,5 +1,6 @@ package io.sentry.android.gradle.tasks +import io.sentry.android.gradle.cliExecutableProvider import io.sentry.android.gradle.sourcecontext.UploadSourceBundleTask import java.io.File import kotlin.test.assertEquals @@ -24,14 +25,14 @@ class UploadSourceBundleTaskTest { val sourceBundleDir = File(project.buildDir, "dummy/folder") val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) } val args = task.get().computeCommandLineArgs() - assertTrue("sentry-cli" in args) + assertTrue(args.any { it.contains("sentry-cli") }) assertTrue("debug-files" in args) assertTrue("upload" in args) assertTrue("--type=jvm" in args) @@ -50,7 +51,7 @@ class UploadSourceBundleTaskTest { val sourceBundleDir = File(project.buildDir, "dummy/folder") val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(false) } @@ -67,7 +68,7 @@ class UploadSourceBundleTaskTest { val sourceBundleDir = File(project.buildDir, "dummy/folder") val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.debug.set(true) @@ -86,7 +87,6 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.sentryProperties.set(propertiesFile) @@ -107,7 +107,6 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.sentryAuthToken.set("") @@ -125,7 +124,7 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.sentryUrl.set("https://some-host.sentry.io") @@ -144,7 +143,6 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) } @@ -161,7 +159,7 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.sentryOrganization.set("dummy-org") @@ -180,7 +178,7 @@ class UploadSourceBundleTaskTest { val task: TaskProvider = project.tasks.register("testUploadSourceBundle", UploadSourceBundleTask::class.java) { - it.cliExecutable.set("sentry-cli") + it.configureCliPaths(project) it.sourceBundleDir.set(sourceBundleDir) it.autoUploadSourceContext.set(true) it.sentryProject.set("dummy-proj") @@ -198,4 +196,9 @@ class UploadSourceBundleTaskTest { return this } } + + private fun SentryCliExecTask.configureCliPaths(project: Project) { + cliExecutable.set(project.cliExecutableProvider()) + buildDirectory.set(project.layout.buildDirectory) + } } diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryServiceTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryServiceTest.kt index e0c462921..fae886683 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryServiceTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryServiceTest.kt @@ -1,7 +1,9 @@ package io.sentry.android.gradle.telemetry -import io.sentry.android.gradle.SentryCliProvider +import io.sentry.BuildConfig +import io.sentry.android.gradle.extensions.SentryPluginExtension import kotlin.test.assertEquals +import kotlin.test.assertTrue import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.Test @@ -11,24 +13,34 @@ class SentryTelemetryServiceTest { @get:Rule val testProjectDir = TemporaryFolder() - @Suppress("UnstableApiUsage") @Test - fun `SentryCliInfoValueSource returns empty string when no auth token is present`() { + fun `createParameters uses BuildConfig CliVersion`() { val project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + val extension = project.extensions.create("sentry", SentryPluginExtension::class.java) - val cliPath = - SentryCliProvider.getCliResourcesExtractionPath(project.layout.buildDirectory).get().asFile + val params = SentryTelemetryService.createParameters(project, null, extension, null, "test") - val infoOutput = - project.providers - .of(SentryCliInfoValueSource::class.java) { cliVS -> - cliVS.parameters.buildDirectory.set(project.layout.buildDirectory) - cliVS.parameters.cliExecutable.set(cliPath.absolutePath) - // sets an empty/invalid auth token - cliVS.parameters.authToken.set("") - } - .get() + assertEquals(BuildConfig.CliVersion, params.cliVersion) + } + + @Test + fun `createParameters detects SaaS when no URL is set`() { + val project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + val extension = project.extensions.create("sentry", SentryPluginExtension::class.java) + + val params = SentryTelemetryService.createParameters(project, null, extension, null, "test") + + assertTrue(params.saas == true) + } + + @Test + fun `createParameters detects self-hosted when URL is set`() { + val project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + val extension = project.extensions.create("sentry", SentryPluginExtension::class.java) + extension.url.set("https://sentry.example.com") + + val params = SentryTelemetryService.createParameters(project, null, extension, null, "test") - assertEquals("", infoOutput) + assertTrue(params.saas == false) } } diff --git a/scripts/benchmark/help-config-cache.scenarios b/scripts/benchmark/help-config-cache.scenarios new file mode 100644 index 000000000..391fbb7e8 --- /dev/null +++ b/scripts/benchmark/help-config-cache.scenarios @@ -0,0 +1,35 @@ +# Benchmarks the configuration-phase performance of this project's `help` task +# with the configuration cache disabled, comparing the PR base commit against +# the PR head commit in a single gradle-profiler run via the git-checkout +# mutator. +# +# BASE_REF and HEAD_REF are supplied as environment variables by the CI +# workflow; HOCON falls back to environment variables for ${...} lookups. +# +# `help` configures the whole build while executing essentially nothing, so it +# is a clean configuration-time signal. --no-configuration-cache forces a full +# configuration on every build. + +help_base { + title = "help base" + tasks = ["help"] + gradle-args = ["--no-configuration-cache"] + warm-ups = 2 + iterations = 5 + git-checkout { + build = ${BASE_REF} + cleanup = ${HEAD_REF} + } +} + +help_pr { + title = "help PR" + tasks = ["help"] + gradle-args = ["--no-configuration-cache"] + warm-ups = 2 + iterations = 5 + git-checkout { + build = ${HEAD_REF} + cleanup = ${HEAD_REF} + } +} diff --git a/scripts/benchmark/help-config-comment.py b/scripts/benchmark/help-config-comment.py new file mode 100644 index 000000000..d7b2ac8a7 --- /dev/null +++ b/scripts/benchmark/help-config-comment.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +"""Render a gradle-profiler benchmark.csv into a Markdown comparison table. + +Usage: help-config-comment.py + +The CSV has one column per scenario. gradle-profiler does not write summary +rows to the CSV (those live in the HTML report), so we read the `scenario` +header row for the titles and average the `measured build #N` rows ourselves to +get the mean total build time in milliseconds. +""" +import csv +import sys + +MARKER = "" + + +def main(csv_path: str, out_path: str) -> None: + header = None + measured = [] + with open(csv_path, newline="") as f: + for row in csv.reader(f): + if not row: + continue + if row[0] == "scenario": + header = row + elif row[0].startswith("measured build"): + measured.append(row) + + if header is None or not measured: + body = f"{MARKER}\n### `help` configuration benchmark\n\nCould not parse benchmark results." + with open(out_path, "w") as f: + f.write(body) + return + + titles = header[1:] + means = [] + for col in range(1, 1 + len(titles)): + values = [float(r[col]) for r in measured] + means.append(sum(values) / len(values)) + by_title = dict(zip(titles, means)) + + base = by_title.get("help base") + pr = by_title.get("help PR") + + lines = [ + MARKER, + "### `help` configuration benchmark (configuration cache disabled)", + "", + "Mean of 5 builds after 2 warm-ups.", + "", + "| Scenario | Mean build time |", + "| --- | --- |", + f"| Base (`help base`) | {base:.0f} ms |", + f"| PR (`help PR`) | {pr:.0f} ms |", + ] + + delta = pr - base + pct = (delta / base) * 100 if base else 0 + sign = "🔺" if delta > 0 else "✅" + lines.append(f"| **Difference** | {sign} {delta:+.0f} ms ({pct:+.1f}%) |") + + with open(out_path, "w") as f: + f.write("\n".join(lines) + "\n") + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2])