Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 45 additions & 11 deletions packages/core/sentry.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,43 @@ tasks.register("cleanupTemporarySentryJsonConfiguration") {
plugins.withId('com.android.application') {
def androidComponents = extensions.getByName("androidComponents")

// Collect only variant metadata in onVariants - do NOT access tasks here.
// Calling tasks.matching { }.each { } inside onVariants forces task realization
// during AGP's variant configuration phase, which disrupts the Artifacts API
// transform chain used by other plugins (e.g. those calling
// variant.artifacts.use(...).toTransform(SingleArtifact.APK)). The result is
// that those plugins' APK output ends up in build/intermediates/ instead of
// build/outputs/, causing downstream tooling to fail to locate the final APK.
def releaseVariants = []
androidComponents.onVariants(androidComponents.selector().all()) { v ->
if (!v.name.toLowerCase().contains("debug")) {
def outputs = []
v.outputs.each { output ->
outputs << [
baseName: output.baseName,
versionCode: output.versionCode.getOrElse(0),
versionName: output.versionName.getOrElse(''),
appId: v.applicationId.get(),
]
}
releaseVariants << [name: v.name, outputs: outputs]
}
}

// All task-level operations must happen in afterEvaluate, not inside onVariants.
// By the time afterEvaluate runs, all plugins have registered their onVariants
// callbacks and the AGP Artifacts API transform chain is fully established.
project.afterEvaluate {
releaseVariants.each { variantData ->
// separately we then hook into the bundle task of react native to inject
// sourcemap generation parameters. In case for whatever reason no release
// was found for the asset folder we just bail.
def bundleTasks = tasks.findAll { task -> (task.name.startsWith("createBundle") || task.name.startsWith("bundle")) && task.name.endsWith("JsAndAssets") && !task.name.contains("Debug") && task.enabled }
bundleTasks.each { bundleTask ->
tasks.matching { task ->
(task.name.startsWith("createBundle") || task.name.startsWith("bundle")) &&
task.name.endsWith("JsAndAssets") &&
!task.name.contains("Debug") &&
task.enabled
}.each { bundleTask ->
def shouldCleanUp
def sourcemapOutput
def bundleOutput
Expand All @@ -94,7 +124,7 @@ plugins.withId('com.android.application') {
// .findAll{!['class', 'active'].contains(it.key)}
// .join('\n')

def currentVariants = extractCurrentVariants(bundleTask, v)
def currentVariants = extractCurrentVariants(bundleTask, variantData)
if (currentVariants == null) return

def previousCliTask = null
Expand Down Expand Up @@ -497,8 +527,12 @@ def forceSourceMapOutputFromBundleTask(bundleTask) {
return [shouldCleanUp, bundleOutput, sourcemapOutput, packagerSourcemapOutput, bundleCommand]
}

/** compose array with one item - current build flavor name */
static extractCurrentVariants(bundleTask, variant) {
/** compose array with one item - current build flavor name.
* variantData is a pre-collected plain map of the form:
* [name: String, outputs: [[baseName, versionCode, versionName, appId], ...]]
* collected during the onVariants callback to avoid accessing tasks there.
*/
static extractCurrentVariants(bundleTask, variantData) {
// examples: bundleLocalReleaseJsAndAssets, createBundleYellowDebugJsAndAssets
def pattern = Pattern.compile("(?:create)?(?:B|b)undle([A-Z][A-Za-z0-9_]+)JsAndAssets")

Expand All @@ -511,14 +545,14 @@ static extractCurrentVariants(bundleTask, variant) {
}

def currentVariants = null
if (variant.name.equalsIgnoreCase(currentRelease)) {
if (variantData.name.equalsIgnoreCase(currentRelease)) {
currentVariants = [:]
def variantName = variant.name
variant.outputs.each { output ->
def defaultVersionCode = output.versionCode.getOrElse(0)
def variantName = variantData.name
variantData.outputs.each { output ->
def defaultVersionCode = output.versionCode
def versionCode = System.getenv('SENTRY_DIST') ?: defaultVersionCode
def appId = variant.applicationId.get()
def versionName = output.versionName.getOrElse('') // may be empty if not set
def appId = output.appId
def versionName = output.versionName // may be empty if not set
def defaultReleaseName = "${appId}@${versionName}+${versionCode}"
def releaseName = System.getenv('SENTRY_RELEASE') ?: defaultReleaseName

Expand Down