diff --git a/CHANGELOG.md b/CHANGELOG.md index f98f1fe76..ebe6a1f11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## XX.XX.XX +* Added gradle configuration cache support to upload symbols plugin. + ## 26.1.2 * Added `CountlyInitProvider` ContentProvider to register activity lifecycle callbacks before `Application.onCreate()`. This ensures the SDK captures the current activity in single-activity frameworks (Flutter, React Native) and apps with deferred initialization. * Added `CountlyConfig.setInitialActivity(Activity)` as an explicit way for wrapper SDKs to provide the host activity during initialization. diff --git a/upload-plugin/src/main/groovy/ly/count/android/plugins/uploadSymbols.groovy b/upload-plugin/src/main/groovy/ly/count/android/plugins/uploadSymbols.groovy index 3e0cdb1b6..1c61b510e 100644 --- a/upload-plugin/src/main/groovy/ly/count/android/plugins/uploadSymbols.groovy +++ b/upload-plugin/src/main/groovy/ly/count/android/plugins/uploadSymbols.groovy @@ -4,7 +4,6 @@ import okhttp3.* import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.tasks.StopActionException -import org.gradle.api.tasks.StopExecutionException import static groovy.io.FileType.FILES @@ -20,29 +19,33 @@ class UploadSymbolsPluginExtension { class UploadSymbolsPlugin implements Plugin { void apply(Project project) { - OkHttpClient client = null - Request request = null def ext = project.extensions.create('countly', UploadSymbolsPluginExtension) project.tasks.register('uploadJavaSymbols') { group = "countly" description = "Upload Java minification mapping file mapping.txt to Countly server" - doFirst { - if (!ext.app_key) { - logger.error("Please specify your app key in countly block.") - throw new StopExecutionException("Please specify your app key in countly block.") - } - if (!ext.server) { - logger.error("Please specify your server in countly block.") - throw new StopExecutionException("Please specify your server in countly block.") - } - String buildVersion = project.android.defaultConfig.versionName - String url = ext.server; - String path = "i/crash_symbols/upload_symbol"; + + // Resolve project/extension values at configuration time to avoid + // capturing non-serializable Project reference in task actions + def buildVersion = project.android.defaultConfig.versionName + def appKey = ext.app_key + def serverUrl = ext.server + def noteJava = ext.noteJava + def mappingFilePath = "${project.buildDir}/${ext.mappingFile}" + + if (!appKey || !serverUrl) { + logger.warn("[Countly] uploadJavaSymbols: 'app_key' or 'server' is empty. " + + "Make sure the countly block is configured before this task is realized. " + + "Disabling task.") + enabled = false + } + + doLast { + String url = serverUrl + String path = "i/crash_symbols/upload_symbol" // Ensure there is exactly one "/" between the base URL and the path - url = url.endsWith("/") ? url + path : url + "/" + path; - def filePath = "$project.buildDir/$ext.mappingFile" - logger.debug("uploadJavaSymbols, Version name:[ {} ], Upload symbol url:[ {} ], Mapping file path:[ {} ]", buildVersion, url, filePath) - File file = new File(filePath) + url = url.endsWith("/") ? url + path : url + "/" + path + logger.debug("uploadJavaSymbols, Version name:[ {} ], Upload symbol url:[ {} ], Mapping file path:[ {} ]", buildVersion, url, mappingFilePath) + File file = new File(mappingFilePath) if (!file.exists()) { logger.error("Mapping file not found") throw new StopActionException("Mapping file not found") @@ -52,17 +55,11 @@ class UploadSymbolsPlugin implements Plugin { .addFormDataPart("symbols", file.getName(), RequestBody.create(MediaType.parse("text/plain"), file)) .addFormDataPart("platform", "android") - .addFormDataPart("app_key", ext.app_key) + .addFormDataPart("app_key", appKey) .addFormDataPart("build", buildVersion) - .addFormDataPart("note", ext.noteJava) + .addFormDataPart("note", noteJava) .build() - request = new Request.Builder().url(url).post(formBody).build() - } - doLast { - if (request == null) { - logger.error("Request not constructed") - throw new StopActionException("Something happened while constructing the request. Please try again.") - } + Request request = new Request.Builder().url(url).post(formBody).build() if (request.body() != null) { logger.debug("uploadJavaSymbols, Generated request: {}", request.body().toString()) @@ -70,7 +67,7 @@ class UploadSymbolsPlugin implements Plugin { logger.error("uploadJavaSymbols, Request body is null which should not be the case") } - client = new OkHttpClient() + OkHttpClient client = new OkHttpClient() Response response = client.newCall(request).execute() if (response.code() != 200) { @@ -88,28 +85,43 @@ class UploadSymbolsPlugin implements Plugin { project.tasks.register('uploadNativeSymbols') { group = "countly" description = "Upload breakpad symbols folder to Countly server" - doFirst { - String buildVersion = project.android.defaultConfig.versionName - String url = "${ext.server}/i/crash_symbols/upload_symbol" - String breakpadVersion = "$ext.dumpSymsPath/dump_syms --version".execute().getText().trim() + + // Resolve project/extension values at configuration time to avoid + // capturing non-serializable Project reference in task actions + def buildVersion = project.android.defaultConfig.versionName + def appKey = ext.app_key + def serverUrl = ext.server + def noteNative = ext.noteNative + def dumpSymsPath = ext.dumpSymsPath + def objectsDirPath = "${project.buildDir}/${ext.nativeObjectFilesDir}" + def countlyDirStr = "${project.buildDir}/intermediates/countly" + + if (!appKey || !serverUrl) { + logger.warn("[Countly] uploadNativeSymbols: 'app_key' or 'server' is empty. " + + "Make sure the countly block is configured before this task is realized. " + + "Disabling task.") + enabled = false + } + + doLast { + String url = "${serverUrl}/i/crash_symbols/upload_symbol" + String breakpadVersion = "$dumpSymsPath/dump_syms --version".execute().getText().trim() if (!(breakpadVersion =~ /^\d+\.\d+\+cly$/)) { breakpadVersion = "0.1+bpd" } - def objectsDir = new File("$project.buildDir/$ext.nativeObjectFilesDir") - def countlyDirStr = "$project.buildDir/intermediates/countly" - def countlyDir = new File("$countlyDirStr") + def objectsDir = new File(objectsDirPath) + def countlyDir = new File(countlyDirStr) logger.debug("uploadNativeSymbols, Version name:[ {} ], Upload symbol url:[ {} ], objectsDir:[ {} ], countlyDirStr:[ {} ], countlyDir:[ {} ], breakpadVersion:[ {} ]", buildVersion, url, objectsDir, countlyDirStr, countlyDir, breakpadVersion) countlyDir.deleteDir() countlyDir.mkdirs() - // println "objectsDir=$objectsDir" def filterObjectFiles = ~/.*\.so$/ def i = 0 def processFile = { i = i + 1 - def cmd = "$ext.dumpSymsPath/dump_syms $it" + def cmd = "$dumpSymsPath/dump_syms $it" println cmd def proc = cmd.execute() def outputStream = new StringBuffer() @@ -131,23 +143,23 @@ class UploadSymbolsPlugin implements Plugin { } objectsDir.traverse type: FILES, visit: processFile, nameFilter: filterObjectFiles def tarFileName = "$countlyDirStr/symbols.tar.gz" - project.ant.tar(destfile: tarFileName, basedir: "$countlyDirStr", includes: "symbols/**", compression: "gzip") + // Use standalone AntBuilder instead of project.ant for configuration cache compatibility + new groovy.ant.AntBuilder().tar(destfile: tarFileName, basedir: "$countlyDirStr", includes: "symbols/**", compression: "gzip") File file = new File(tarFileName) RequestBody formBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("symbols", file.getName(), RequestBody.create(MediaType.parse("text/plain"), file)) .addFormDataPart("platform", "android_native") - .addFormDataPart("app_key", ext.app_key) + .addFormDataPart("app_key", appKey) .addFormDataPart("build", buildVersion) - .addFormDataPart("note", ext.noteNative) + .addFormDataPart("note", noteNative) .addFormDataPart("sym_tool_ver", breakpadVersion) .build() - request = new Request.Builder().url(url).post(formBody).build() + Request request = new Request.Builder().url(url).post(formBody).build() logger.debug("uploadNativeSymbols, Generated request: {}", request.body().toString()) - } - doLast { - client = new OkHttpClient() + + OkHttpClient client = new OkHttpClient() Response response = client.newCall(request).execute() if (response.code() != 200) {