From e98f2c0c3ec657d5debbfb9a7adc1cb49e2ef27c Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Tue, 29 Jan 2019 16:11:52 +0100 Subject: [PATCH] Sentry gradle script refactoring, compatibility with Gradle 5.0 recovered (#532) * Sentry gradle script refactoring, compatibility with Gradle 5.0 recovered * Merged/rebase with latest version of master --- sentry.gradle | 291 ++++++++++++++++++++++++++++---------------------- 1 file changed, 162 insertions(+), 129 deletions(-) diff --git a/sentry.gradle b/sentry.gradle index bc874ef637..8c07582b0b 100644 --- a/sentry.gradle +++ b/sentry.gradle @@ -6,54 +6,20 @@ import java.util.regex.Pattern def config = project.hasProperty("sentryCli") ? project.sentryCli : []; gradle.projectsEvaluated { - def releases = [:]; - android.applicationVariants.each { variant -> - def releaseName = "${variant.getApplicationId()}-${variant.getVersionName()}"; - variant.outputs.each { output -> - def versionCode = output.getVersionCode(); - def variantName = variant.getName(); - def outputName = output.getName(); - if (releases[variantName] == null) { - releases[variantName] = [:]; - } - releases[variantName][outputName] = [outputName, releaseName, versionCode]; - } - } + def releases = extractReleasesInfo() + // 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("bundle") && task.name.endsWith("JsAndAssets") - } + def bundleTasks = tasks.findAll { task -> task.name.startsWith("bundle") && task.name.endsWith("JsAndAssets") } bundleTasks.each { bundleTask -> - def props = bundleTask.getProperties(); - def cmd = props.get("commandLine") as List; - def cmdArgs = props.get("args") as List; - def bundleOutput = null; - def sourcemapOutput = null; - def reactRoot = props.get("workingDir"); - def shouldCleanUp = false; - - cmdArgs.eachWithIndex{ String arg, int i -> - if (arg == "--bundle-output") { - bundleOutput = cmdArgs[i + 1]; - } else if (arg == "--sourcemap-output") { - sourcemapOutput = cmdArgs[i + 1]; - } - } - - if (sourcemapOutput == null) { - sourcemapOutput = bundleOutput + ".map"; - cmd.push("--sourcemap-output"); - cmd.push(sourcemapOutput); - cmdArgs.push("--sourcemap-output"); - cmdArgs.push(sourcemapOutput); + def shouldCleanUp + def sourcemapOutput + def bundleOutput + def props = bundleTask.getProperties() + def reactRoot = props.get("workingDir") - shouldCleanUp = true - } - - bundleTask.setProperty("commandLine", cmd); - bundleTask.setProperty("args", cmdArgs); + (shouldCleanUp, bundleOutput, sourcemapOutput) = forceSourceMapOutputFromBundleTask(bundleTask) if (config.flavorAware) { println "**********************************" @@ -68,121 +34,188 @@ gradle.projectsEvaluated { // .findAll{!['class', 'active'].contains(it.key)} // .join('\n') - def currentRelease = ""; - def pattern = Pattern.compile("bundle([A-Z][A-Za-z0-9]+)JsAndAssets") - Matcher matcher = pattern.matcher(bundleTask.name) - if (matcher.find()) { - def match = matcher.group(1); - currentRelease = match.substring(0, 1).toLowerCase() + match.substring(1); - } + def currentVariants = extractCurrentVariants(bundleTask, releases) + if (currentVariants == null) return - def currentVariants = null; - releases.each { key, release -> - if (key.equalsIgnoreCase(currentRelease)) { - currentVariants = release; - } - } - - if (currentVariants == null) return; - - def variant = null; - def releaseName = null; - def versionCodes = new ArrayList(currentVariants.size()); + def variant = null + def releaseName = null + def versionCodes = new ArrayList(currentVariants.size()) currentVariants.each { key, currentVariant -> - variant = currentVariant[0]; - releaseName = currentVariant[1]; - versionCodes.push(currentVariant[2]); + variant = currentVariant[0] + releaseName = currentVariant[1] + versionCodes.push(currentVariant[2]) } - def cliTask = tasks.create( - name: bundleTask.getName() + variant + "SentryUpload", - type: Exec) { + def nameCliTask = "${bundleTask.name}_SentryUpload" + def nameCleanup = "${bundleTask.name}_SentryUploadCleanUp" + + /** Upload source map file to the sentry server via CLI call. */ + def cliTask = tasks.create(name: nameCliTask, type: Exec) { description = "upload debug symbols to sentry" + group = 'sentry.io' - def propertiesFile = "$reactRoot/android/sentry.properties"; + workingDir reactRoot + + def propertiesFile = "$reactRoot/android/sentry.properties" if (config.flavorAware) { - propertiesFile = "$reactRoot/android/sentry-$variant"+".properties" - println "For $variant using: $propertiesFile" + propertiesFile = "$reactRoot/android/sentry-${variant}.properties" + project.logger.info("For $variant using: $propertiesFile") } else { environment("SENTRY_PROPERTIES", propertiesFile) } - Properties sentryProps = new Properties(); + + Properties sentryProps = new Properties() try { - sentryProps.load(new FileInputStream(propertiesFile)); + sentryProps.load(new FileInputStream(propertiesFile)) } catch (FileNotFoundException e) { - println "File not found: $propertiesFile" + project.logger.info("file not found '$propertiesFile' for '$variant'") } - def cliExecutable = sentryProps.get("cli.executable", "$reactRoot/node_modules/@sentry/cli/bin/sentry-cli"); + def cliExecutable = sentryProps.get("cli.executable", "$reactRoot/node_modules/@sentry/cli/bin/sentry-cli") - workingDir reactRoot - + // fix path separator for Windows if (Os.isFamily(Os.FAMILY_WINDOWS)) { - cliExecutable = cliExecutable.replaceAll("/","\\\\"); + cliExecutable = cliExecutable.replaceAll("/", "\\\\") } - def args = [ - cliExecutable - ]; - if (config.logLevel) { - args.push("--log-level"); - args.push(config.logLevel); - } + // + // based on: + // https://github.com/getsentry/sentry-cli/blob/master/src/commands/react_native_gradle.rs + // + def args = [cliExecutable] + + args.addAll( !config.logLevel ? [] : [ + "--log-level", config.logLevel // control verbosity of the output + ]) + args.addAll(!config.flavorAware ? [] : [ + "--url", sentryProps.get("defaults.url"), + "--auth-token", sentryProps.get("auth.token") + ]) + args.addAll(["react-native", "gradle", + "--bundle", bundleOutput, // The path to a bundle that should be uploaded. + "--sourcemap", sourcemapOutput, // The path to a sourcemap that should be uploaded. + "--release", releaseName // The name of the release to publish. + ]) + args.addAll(!config.flavorAware ? [] : [ + "--org", sentryProps.get("defaults.org"), + "--project", sentryProps.get("defaults.project") + ]) + + // The names of the distributions to publish. Can be supplied multiple times. + versionCodes.each { versionCode -> args.addAll(["--dist", versionCode]) } + + project.logger.info("Sentry-CLI arguments: ${args}") + + def osCompatibility = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'node'] : [] + commandLine(*osCompatibility, *args) - if (config.flavorAware) { - args.push("--url"); - args.push(sentryProps.get("defaults.url")); - args.push("--auth-token"); - args.push(sentryProps.get("auth.token")); - } + enabled true + } - args.push("react-native"); - args.push("gradle"); - args.push("--bundle"); - args.push(bundleOutput); - args.push("--sourcemap"); - args.push(sourcemapOutput); - args.push("--release"); - args.push(releaseName); + /** Delete sourcemap files */ + def cliCleanUpTask = tasks.create(name: nameCleanup, type: Delete) { + description = "clean up extra sourcemap" + group = 'sentry.io' - if (config.flavorAware) { - args.push("--org"); - args.push(sentryProps.get("defaults.org")); - args.push("--project"); - args.push(sentryProps.get("defaults.project")); - } + delete sourcemapOutput + } - versionCodes.each { versionCode -> - args.add("--dist"); - args.add(versionCode); - } + // dependsOn, mustRunAfter, shouldRunAfter, doFirst, doLast, finalizedBy + // bundleTask --> cliTask + bundleTask.finalizedBy cliTask - if (config.logLevel) { - println args - } - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine("cmd", "/c", "node", *args) - } else { - commandLine(*args) + // register clean task extension + cliCleanUpTask.onlyIf { shouldCleanUp } + project.tasks.clean.dependsOn cliCleanUpTask + } +} + +/** Compose lookup map of build variants - to - outputs. */ +def extractReleasesInfo() { + def releases = [:] + + android.applicationVariants.each { variant -> + def releaseName = "${variant.getApplicationId()}-${variant.getVersionName()}" + + variant.outputs.each { output -> + def versionCode = output.getVersionCode() + def variantName = variant.getName() + def outputName = output.getName() + if (releases[variantName] == null) { + releases[variantName] = [:] } - enabled true + releases[variantName][outputName] = [outputName, releaseName, versionCode] } + } - def cliCleanUpTask = tasks.create( - name: bundleTask.getName() + variant + "SentryUploadCleanUp", - type: Delete) { - description = "clean up extra sourcemap" + return releases +} - delete sourcemapOutput - }; +/** Extract from arguments collection bundle and sourcemap files output names. */ +static extractBundleTaskArguments(cmdArgs){ + def bundleOutput = null + def sourcemapOutput = null - bundleTask.doLast { - cliTask.execute(); - if (shouldCleanUp) { - cliCleanUpTask.execute(); - } + cmdArgs.eachWithIndex { String arg, int i -> + if (arg == "--bundle-output") { + bundleOutput = cmdArgs[i + 1] + } else if (arg == "--sourcemap-output") { + sourcemapOutput = cmdArgs[i + 1] } + } + + return [ bundleOutput, sourcemapOutput ] +} + +/** Force Bundle task to produce sourcemap files if they are not pre-configured by user yet. */ +def forceSourceMapOutputFromBundleTask(bundleTask){ + def props = bundleTask.getProperties() + def cmd = props.get("commandLine") as List + def cmdArgs = props.get("args") as List + def shouldCleanUp = false + def bundleOutput = null + def sourcemapOutput = null + + (bundleOutput, sourcemapOutput) = extractBundleTaskArguments(cmdArgs) + + if (sourcemapOutput == null) { + sourcemapOutput = bundleOutput + ".map" + + cmd.addAll(["--sourcemap-output", sourcemapOutput]) + cmdArgs.addAll(["--sourcemap-output", sourcemapOutput]) - cliTask.dependsOn(bundleTask) + shouldCleanUp = true + + bundleTask.setProperty("commandLine", cmd) + bundleTask.setProperty("args", cmdArgs) + + project.logger.info("forced sourcemap file output for `${bundleTask.name}` task") + } else { + project.logger.info("Info: used pre-configured source map files: ${sourcemapOutput}") } + + return [shouldCleanUp, bundleOutput, sourcemapOutput] +} + +/** compose array with one item - current build flavor name */ +static extractCurrentVariants(bundleTask, releases) { + // examples: bundleLocalReleaseJsAndAssets, bundleYellowDebugJsAndAssets + def pattern = Pattern.compile("bundle([A-Z][A-Za-z0-9_]+)JsAndAssets") + + def currentRelease = "" + + Matcher matcher = pattern.matcher(bundleTask.name) + if (matcher.find()) { + def match = matcher.group(1) + currentRelease = match.substring(0, 1).toLowerCase() + match.substring(1) + } + + def currentVariants = null + releases.each { key, release -> + if (key.equalsIgnoreCase(currentRelease)) { + currentVariants = release + } + } + + return currentVariants }