From 85a812064b136557f3dc45a989af1f362cc6301e Mon Sep 17 00:00:00 2001 From: LepilkinaElena Date: Tue, 29 Oct 2019 18:46:14 +0300 Subject: [PATCH] Move to Artifactory usage (#3513) --- HACKING.md | 8 +-- .../org/jetbrains/kotlin/BuildRegister.kt | 12 ++-- .../kotlin/org/jetbrains/kotlin/MPPTools.kt | 15 +++-- .../jetbrains/kotlin/RegressionsReporter.kt | 14 ++--- performance/KotlinVsSwift/build.gradle | 4 +- performance/build.gradle | 16 +++-- performance/gradle.properties | 5 +- .../src/main/kotlin/main.kt | 18 +++--- .../src/main/kotlin/routes/route.kt | 63 ++++++++++--------- .../ui/src/main/kotlin/main.kt | 4 +- 10 files changed, 81 insertions(+), 78 deletions(-) diff --git a/HACKING.md b/HACKING.md index 6174ff8b405..033089f0335 100644 --- a/HACKING.md +++ b/HACKING.md @@ -153,15 +153,15 @@ and then a final native binary is produced from this klibrary using the -Xinclud Output can be redirected to file with flag `--output/-o`. To get detailed information about supported options, please use `--help/-h`. - Analyzer tool can compare both local files and files placed on Bintray/TeamCity. + Analyzer tool can compare both local files and files placed on Artifactory/TeamCity. - File description stored on Bintray + File description stored on Artifactory - bintray::: + artifactory::: Example - bintray:1.2-dev-7942:Windows10:nativeReport.json + artifactory:1.2-dev-7942:Windows10:nativeReport.json File description stored on TeamCity diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/BuildRegister.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/BuildRegister.kt index 7b60e5d3970..bddc5dd7ab5 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/BuildRegister.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/BuildRegister.kt @@ -89,11 +89,10 @@ open class BuildRegister : DefaultTask() { val buildProperties = Properties() buildProperties.load(FileInputStream(teamcityConfig)) val buildId = buildProperties.getProperty("teamcity.build.id") - val bintrayUser = buildProperties.getProperty("bintray.user") - val bintrayApiKey = buildProperties.getProperty("bintray.apikey") val teamCityUser = buildProperties.getProperty("teamcity.auth.userId") val teamCityPassword = buildProperties.getProperty("teamcity.auth.password") val buildNumber = buildProperties.getProperty("build.number") + val apiKey = buildProperties.getProperty("artifactory.apikey") // Get branch. val currentBuild = getBuild("id:$buildId", teamCityUser, teamCityPassword) @@ -104,8 +103,8 @@ open class BuildRegister : DefaultTask() { // Get summary information. val output = arrayOf("$analyzer", "summary", "--exec-samples", "all", "--compile", "samples", "--compile-samples", "HelloWorld,Videoplayer", "--codesize-samples", "all", - "--exec-normalize", "bintray:goldenResults.csv", - "--codesize-normalize", "bintray:goldenResults.csv", "$currentBenchmarksReportFile") + "--exec-normalize", "artifactory:builds/goldenResults.csv", + "--codesize-normalize", "artifactory:builds/goldenResults.csv", "$currentBenchmarksReportFile") .runCommand() // Postprocess information. @@ -131,7 +130,7 @@ open class BuildRegister : DefaultTask() { val frameworkOutput = arrayOf("$analyzer", "summary", "--compile", "samples", "--compile-samples", "FrameworkBenchmarksAnalyzer", "--codesize-samples", "FrameworkBenchmarksAnalyzer", - "--codesize-normalize", "bintray:goldenResults.csv", "$currentBenchmarksReportFile") + "--codesize-normalize", "artifactory:builds/goldenResults.csv", "$currentBenchmarksReportFile") .runCommand() val buildInfoPartsFramework = frameworkOutput.split(',') @@ -154,8 +153,7 @@ open class BuildRegister : DefaultTask() { append("{\"buildId\":\"$buildId\",") append("\"teamCityUser\":\"$teamCityUser\",") append("\"teamCityPassword\":\"$teamCityPassword\",") - append("\"bintrayUser\": \"$bintrayUser\", ") - append("\"bintrayPassword\":\"$bintrayApiKey\", ") + append("\"artifactoryApiKey\":\"$apiKey\",") append("\"target\": \"$target\",") append("\"buildType\": \"$buildType\",") append("\"failuresNumber\": $failures,") diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt index 131c160967c..6c4c992bf0d 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/MPPTools.kt @@ -141,13 +141,14 @@ fun getCompileOnlyBenchmarksOpts(project: Project, defaultCompilerOpts: List> = emptyList()) { val uploadingFile = File(fileName) val connection = URL(url).openConnection() as HttpURLConnection connection.doOutput = true @@ -158,7 +159,9 @@ fun sendUploadRequest(url: String, fileName: String, username: String? = null, p val auth = Base64.getEncoder().encode((username + ":" + password).toByteArray()).toString(Charsets.UTF_8) connection.addRequestProperty("Authorization", "Basic $auth") } - + extraHeaders.forEach { + connection.addRequestProperty(it.first, it.second) + } try { connection.connect() BufferedOutputStream(connection.outputStream).use { output -> diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/RegressionsReporter.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/RegressionsReporter.kt index f9370894194..5159a9b8e47 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/RegressionsReporter.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/RegressionsReporter.kt @@ -125,8 +125,8 @@ open class RegressionsReporter : DefaultTask() { } } - // File name on bintray is the same as current. - val bintrayFileName = currentBenchmarksReportFile.substringAfterLast("/") + // File name on Artifactory is the same as current. + val artifactoryFileName = currentBenchmarksReportFile.substringAfterLast("/") // Get compare to build. val compareToBuild = getBuild(previousBuildLocator(buildTypeId, defaultBranch), user, password) @@ -135,21 +135,21 @@ open class RegressionsReporter : DefaultTask() { val target = System.getProperty("os.name").replace("\\s".toRegex(), "") // Generate comparison report. - val output = arrayOf("$analyzer", "-r", "html", "$currentBenchmarksReportFile", "bintray:$compareToBuildNumber:$target:$bintrayFileName", "-o", "$htmlReport") + val output = arrayOf("$analyzer", "-r", "html", "$currentBenchmarksReportFile", "artifactory:$compareToBuildNumber:$target:$artifactoryFileName", "-o", "$htmlReport") .runCommand() if (output.contains("Uncaught exception")) { error("Error during comparasion of $currentBenchmarksReportFile and " + - "bintray:$compareToBuildNumber:$target:$bintrayFileName with $analyzer! " + + "artifactory:$compareToBuildNumber:$target:$artifactoryFileName with $analyzer! " + "Please check files existance and their correctness.") } - arrayOf("$analyzer", "-r", "statistics", "$currentBenchmarksReportFile", "bintray:$compareToBuildNumber:$target:$bintrayFileName", "-o", "$summaryFile") + arrayOf("$analyzer", "-r", "statistics", "$currentBenchmarksReportFile", "artifactory:$compareToBuildNumber:$target:$artifactoryFileName", "-o", "$summaryFile") .runCommand() val reportLink = "https://kotlin-native-perf-summary.labs.jb.gg/?target=$target&build=$buildNumber" val detailedReportLink = "https://kotlin-native-performance.labs.jb.gg/?" + - "report=bintray:$buildNumber:$target:$bintrayFileName&" + - "compareTo=bintray:$compareToBuildNumber:$target:$bintrayFileName" + "report=artifactory:$buildNumber:$target:$artifactoryFileName&" + + "compareTo=artifactory:$compareToBuildNumber:$target:$artifactoryFileName" val title = "\n*Performance report for target $target (build $buildNumber)* - $reportLink\n" + "*Detailed info - * $detailedReportLink" diff --git a/performance/KotlinVsSwift/build.gradle b/performance/KotlinVsSwift/build.gradle index 41fe9b3b865..e97a330eaf5 100644 --- a/performance/KotlinVsSwift/build.gradle +++ b/performance/KotlinVsSwift/build.gradle @@ -35,14 +35,14 @@ defaultTasks 'konanRun' task mergeNativeReports { doLast { mergeReports(nativeJson) - uploadBenchmarkResultToBintray(nativeJson) + uploadBenchmarkResultToArtifactory(nativeJson) } } task mergeJvmReports { doLast { mergeReports(jvmJson) - uploadBenchmarkResultToBintray(jvmJson) + uploadBenchmarkResultToArtifactory(jvmJson) } } diff --git a/performance/build.gradle b/performance/build.gradle index 0f6a5bb4eeb..31af64fcecc 100644 --- a/performance/build.gradle +++ b/performance/build.gradle @@ -64,18 +64,16 @@ task slackSummary(type: RegressionsSummaryReporter) { 'Windows': "${rootBuildDirectory}/targetsResults/Windows 10.txt".toString()] } -private def uploadBenchmarkResultToBintray(String fileName) { +private def uploadBenchmarkResultToArtifactory(String fileName) { def teamcityConfig = System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") if (teamcityConfig) { def buildProperties = new Properties() buildProperties.load(new FileInputStream(teamcityConfig)) - def user = buildProperties.getProperty("bintray.user") - def password = buildProperties.getProperty("bintray.apikey") + def password = buildProperties.getProperty("artifactory.apikey") def buildNumber = buildProperties.getProperty("build.number") def target = System.getProperty("os.name").replaceAll("\\s", "") - MPPTools.uploadFileToBintray("${bintrayUrl}", "${bintrayRepo}", - buildNumber, "${bintrayPackage}", "${target}/${buildNumber}/${fileName}", - "${buildDir.absolutePath}/${fileName}", user, password) + MPPTools.uploadFileToArtifactory("${artifactoryUrl}", "${artifactoryRepo}", + "${target}/${buildNumber}/${fileName}", "${buildDir.absolutePath}/${fileName}", password) } } @@ -126,7 +124,7 @@ task registerExternalBenchmarks { if (!merged.isEmpty()) { mkdir buildDir.absolutePath new File(buildDir, externalBenchmarksReport).write(merged) - uploadBenchmarkResultToBintray(externalBenchmarksReport) + uploadBenchmarkResultToArtifactory(externalBenchmarksReport) } } } @@ -164,14 +162,14 @@ def mergeReports(String fileName) { task mergeNativeReports { doLast { mergeReports(nativeJson) - uploadBenchmarkResultToBintray(nativeJson) + uploadBenchmarkResultToArtifactory(nativeJson) } } task mergeJvmReports { doLast { mergeReports(jvmJson) - uploadBenchmarkResultToBintray(jvmJson) + uploadBenchmarkResultToArtifactory(jvmJson) } } diff --git a/performance/gradle.properties b/performance/gradle.properties index 533ffe39cfb..8d084e0b320 100644 --- a/performance/gradle.properties +++ b/performance/gradle.properties @@ -12,8 +12,7 @@ jvmJson = jvmReport.json analyzerTool = benchmarksAnalyzer analyzerToolDirectory = tools/benchmarksAnalyzer/build/bin outputReport = ../report/report.html -bintrayUrl = https://api.bintray.com/content/lepilkinaelena -bintrayRepo = KotlinNativePerformance -bintrayPackage = jsonReports +artifactoryUrl = https://repo.labs.intellij.net +artifactoryRepo = kotlin-native-benchmarks externalReports = coroutinesReport.txt externalBenchmarksReport = externalReport.json diff --git a/tools/benchmarksAnalyzer/src/main/kotlin/main.kt b/tools/benchmarksAnalyzer/src/main/kotlin/main.kt index 94017efefc5..66b765a6dc7 100644 --- a/tools/benchmarksAnalyzer/src/main/kotlin/main.kt +++ b/tools/benchmarksAnalyzer/src/main/kotlin/main.kt @@ -31,27 +31,27 @@ abstract class Connector { abstract fun getFileContent(fileLocation: String, user: String? = null): String } -object BintrayConnector : Connector() { - override val connectorPrefix = "bintray:" - val bintrayUrl = "https://dl.bintray.com/content/lepilkinaelena/KotlinNativePerformance" +object ArtifactoryConnector : Connector() { + override val connectorPrefix = "artifactory:" + val artifactoryUrl = "https://repo.labs.intellij.net/kotlin-native-benchmarks" override fun getFileContent(fileLocation: String, user: String?): String { val fileParametersSize = 3 val fileDescription = fileLocation.substringAfter(connectorPrefix) val fileParameters = fileDescription.split(':', limit = fileParametersSize) - // Right link to bintray file. + // Right link to Artifactory file. if (fileParameters.size == 1) { - val accessFileUrl = "$bintrayUrl/${fileParameters[0]}" + val accessFileUrl = "$artifactoryUrl/${fileParameters[0]}" return sendGetRequest(accessFileUrl, followLocation = true) } // Used builds description format. if (fileParameters.size != fileParametersSize) { - error("To get file from bintray, please, specify, build number from TeamCity and target" + - " in format bintray:build_number:target:filename") + error("To get file from Artifactory, please, specify, build number from TeamCity and target" + + " in format artifactory:build_number:target:filename") } val (buildNumber, target, fileName) = fileParameters - val accessFileUrl = "$bintrayUrl/$target/$buildNumber/$fileName" + val accessFileUrl = "$artifactoryUrl/$target/$buildNumber/$fileName" return sendGetRequest(accessFileUrl, followLocation = true) } } @@ -78,7 +78,7 @@ object TeamCityConnector: Connector() { fun getFileContent(fileName: String, user: String? = null): String { return when { - BintrayConnector.isCompatible(fileName) -> BintrayConnector.getFileContent(fileName, user) + ArtifactoryConnector.isCompatible(fileName) -> ArtifactoryConnector.getFileContent(fileName, user) TeamCityConnector.isCompatible(fileName) -> TeamCityConnector.getFileContent(fileName, user) else -> readFile(fileName) } diff --git a/tools/performance-server/src/main/kotlin/routes/route.kt b/tools/performance-server/src/main/kotlin/routes/route.kt index 442b4dcd39e..938d80d327f 100644 --- a/tools/performance-server/src/main/kotlin/routes/route.kt +++ b/tools/performance-server/src/main/kotlin/routes/route.kt @@ -21,16 +21,17 @@ import org.jetbrains.report.json.* import org.jetbrains.build.Build const val teamCityUrl = "https://buildserver.labs.intellij.net/app/rest" -const val downloadBintrayUrl = "https://dl.bintray.com/content/lepilkinaelena/KotlinNativePerformance" -const val uploadBintrayUrl = "https://api.bintray.com/content/lepilkinaelena/KotlinNativePerformance" +const val artifactoryUrl = "https://repo.labs.intellij.net/kotlin-native-benchmarks" const val buildsFileName = "buildsSummary.csv" const val goldenResultsFileName = "goldenResults.csv" -const val bintrayPackage = "builds" +const val artifactoryBuildsDirectory = "builds" const val buildsInfoPartsNumber = 11 operator fun Map?.get(key: K) = this?.get(key) -// Local cache for saving information about builds got from Bintray. +fun getArtifactoryHeader(artifactoryApiKey: String) = Pair("X-JFrog-Art-Api", artifactoryApiKey) + +// Local cache for saving information about builds got from Artifactory. object LocalCache { private val knownTargets = listOf("Linux", "MacOSX", "Windows10") private val buildsInfo = mutableMapOf>() @@ -43,7 +44,7 @@ object LocalCache { fun fill(onlyTarget: String? = null) { onlyTarget?.let { - val buildsDescription = getBuildsInfoFromBintray(onlyTarget).lines().drop(1) + val buildsDescription = getBuildsInfoFromArtifactory(onlyTarget).lines().drop(1) buildsInfo[onlyTarget] = mutableMapOf() buildsDescription.forEach { if (!it.isEmpty()) { @@ -65,19 +66,19 @@ object LocalCache { fun buildExists(target: String, buildNumber: String) = buildsInfo[target][buildNumber]?.let { true } ?: false - fun delete(target: String, builds: Iterable, bintrayUser: String, bintrayPassword: String): Boolean { - // Delete from bintray. - val buildsDescription = getBuildsInfoFromBintray(target).lines() + fun delete(target: String, builds: Iterable, apiKey: String): Boolean { + // Delete from Artifactory. + val buildsDescription = getBuildsInfoFromArtifactory(target).lines() val newBuildsDescription = buildsDescription.filter { val buildNumber = it.substringBefore(',') buildNumber !in builds } - if (newBuildsDescription.size < buildsDescription.size) { // Upload new version of file. - val uploadUrl = "$uploadBintrayUrl/$bintrayPackage/latest/$target/$buildsFileName?publish=1&override=1" - sendUploadRequest(uploadUrl, newBuildsDescription.joinToString("\n"), bintrayUser, bintrayPassword) + val uploadUrl = "$artifactoryUrl/$artifactoryBuildsDirectory/$target/$buildsFileName" + sendUploadRequest(uploadUrl, newBuildsDescription.joinToString("\n"), + extraHeaders = listOf(getArtifactoryHeader(apiKey))) // Reload values. clean(target) @@ -111,15 +112,14 @@ object LocalCache { } data class GoldenResult(val benchmarkName: String, val metric: String, val value: Double) -data class GoldenResultsInfo(val bintrayUser: String, val bintrayPassword: String, val goldenResults: Array) +data class GoldenResultsInfo(val apiKey: String, val goldenResults: Array) // Build information provided from request. data class BuildInfo(val buildNumber: String, val branch: String, val startTime: String, val finishTime: String) data class BuildRegister(val buildId: String, val teamCityUser: String, val teamCityPassword: String, - val bintrayUser: String, val bintrayPassword: String, - val target: String, val buildType: String, val failuresNumber: Int, + val artifactoryApiKey: String, val target: String, val buildType: String, val failuresNumber: Int, val executionTime: String, val compileTime: String, val codeSize: String, val bundleSize: String?) { companion object { @@ -127,8 +127,8 @@ data class BuildRegister(val buildId: String, val teamCityUser: String, val team val requestDetails = JSON.parse(json) // Parse method doesn't create real instance with all methods. So create it by hands. return BuildRegister(requestDetails.buildId, requestDetails.teamCityUser, requestDetails.teamCityPassword, - requestDetails.bintrayUser, requestDetails.bintrayPassword, requestDetails.target, - requestDetails.buildType, requestDetails.failuresNumber, requestDetails.executionTime, requestDetails.compileTime, + requestDetails.artifactoryApiKey, requestDetails.target, requestDetails.buildType, + requestDetails.failuresNumber, requestDetails.executionTime, requestDetails.compileTime, requestDetails.codeSize, requestDetails.bundleSize) } } @@ -189,8 +189,8 @@ class CommitsList(data: JsonElement): ConvertedFromJson { } } -fun getBuildsInfoFromBintray(target: String) = - sendGetRequest("$downloadBintrayUrl/$target/$buildsFileName") +fun getBuildsInfoFromArtifactory(target: String) = + sendGetRequest("$artifactoryUrl/$artifactoryBuildsDirectory/$target/$buildsFileName") fun checkBuildType(currentType: String, targetType: String): Boolean { val releasesBuildTypes = listOf("release", "eap", "rc1", "rc2") @@ -226,7 +226,7 @@ fun router() { val express = require("express") val router = express.Router() - // Register build on Bintray. + // Register build on Artifactory. router.post("/register", { request, response -> val maxCommitsNumber = 5 val register = BuildRegister.create(JSON.stringify(request.body)) @@ -251,8 +251,8 @@ fun router() { } } - // Get summary file from Bintray. - var buildsDescription = getBuildsInfoFromBintray(register.target) + // Get summary file from Artifactory. + var buildsDescription = getBuildsInfoFromArtifactory(register.target) // Add information about new build. //var buildsDescription = "build, start time, finish time, branch, commits, type, failuresNumber, execution time, compile time, code size, bundle size\n" buildsDescription += "${buildInfo.buildNumber}, ${buildInfo.startTime}, ${buildInfo.finishTime}, " + @@ -261,8 +261,8 @@ fun router() { "${register.bundleSize ?: "-"}\n" // Upload new version of file. - val uploadUrl = "$uploadBintrayUrl/$bintrayPackage/latest/${register.target}/${buildsFileName}?publish=1&override=1" - sendUploadRequest(uploadUrl, buildsDescription, register.bintrayUser, register.bintrayPassword) + val uploadUrl = "$artifactoryUrl/$artifactoryBuildsDirectory/${register.target}/${buildsFileName}" + sendUploadRequest(uploadUrl, buildsDescription, extraHeaders = listOf(getArtifactoryHeader(register.artifactoryApiKey))) LocalCache.clean(register.target) LocalCache.fill(register.target) @@ -271,16 +271,17 @@ fun router() { response.sendStatus(200) }) - // Register golden results to normalize on Bintray. + // Register golden results to normalize on Artifactory. router.post("/registerGolden", { request, response -> val goldenResultsInfo = JSON.parse(JSON.stringify(request.body)) - val buildsDescription = StringBuilder(sendGetRequest("$downloadBintrayUrl/$goldenResultsFileName")) + val buildsDescription = StringBuilder(sendGetRequest("$artifactoryUrl/$artifactoryBuildsDirectory/$goldenResultsFileName")) goldenResultsInfo.goldenResults.forEach { buildsDescription.append("${it.benchmarkName}, ${it.metric}, ${it.value}\n") } // Upload new version of file. - val uploadUrl = "$uploadBintrayUrl/$bintrayPackage/latest/$goldenResultsFileName?publish=1&override=1" - sendUploadRequest(uploadUrl, buildsDescription.toString(), goldenResultsInfo.bintrayUser, goldenResultsInfo.bintrayPassword) + val uploadUrl = "$artifactoryUrl/$artifactoryBuildsDirectory/$goldenResultsFileName" + sendUploadRequest(uploadUrl, buildsDescription.toString(), + extraHeaders = listOf(getArtifactoryHeader(goldenResultsInfo.apiKey))) // Send response. response.sendStatus(200) }) @@ -318,7 +319,7 @@ fun router() { router.get("/delete/:target", { request, response -> val buildsToDelete: List = request.query.builds.toString().split(",").map { it.trim() } - val result = LocalCache.delete(request.params.target, buildsToDelete, request.query.user, request.query.key) + val result = LocalCache.delete(request.params.target, buildsToDelete, request.query.key) if (result) { response.sendStatus(200) } else { @@ -362,12 +363,16 @@ fun sendGetRequest(url: String, user: String? = null, password: String? = null, return response.getBody().toString() } -fun sendUploadRequest(url: String, fileContent: String, user: String? = null, password: String? = null) { +fun sendUploadRequest(url: String, fileContent: String, user: String? = null, password: String? = null, + extraHeaders: List> = emptyList()) { val request = require("sync-request") val headers = mutableListOf>("Content-type" to "text/plain") if (user != null && password != null) { headers.add("Authorization" to getAuth(user, password)) } + extraHeaders.forEach { + headers.add(it.first to it.second) + } val response = request("PUT", url, json( "headers" to json(*(headers.toTypedArray())), diff --git a/tools/performance-server/ui/src/main/kotlin/main.kt b/tools/performance-server/ui/src/main/kotlin/main.kt index b42e990f82f..dda2612dc6c 100644 --- a/tools/performance-server/ui/src/main/kotlin/main.kt +++ b/tools/performance-server/ui/src/main/kotlin/main.kt @@ -182,10 +182,10 @@ fun customizeChart(chart: dynamic, chartContainer: String, jquerySelector: dynam element = data.element.replace(rectangle) } // Add tooltips. - val linkToDetailedInfo = "https://kotlin-native-performance.labs.jb.gg/?report=bintray:" + + val linkToDetailedInfo = "https://kotlin-native-performance.labs.jb.gg/?report=artifactory:" + "${currentBuild.buildNumber}:${parameters["target"]}:nativeReport.json" + "${if (data.index - 1 >= 0) - "&compareTo=bintray:${buildsGroup.get(data.index - 1).buildNumber}:${parameters["target"]}:nativeReport.json" + "&compareTo=artifactory:${buildsGroup.get(data.index - 1).buildNumber}:${parameters["target"]}:nativeReport.json" else ""}" val information = buildString { append("${currentBuild.buildNumber}
")