diff --git a/tools/performance-server/package-lock.json b/tools/performance-server/package-lock.json index 3214b093820..aad66f40392 100644 --- a/tools/performance-server/package-lock.json +++ b/tools/performance-server/package-lock.json @@ -81,11 +81,6 @@ } } }, - "bower": { - "version": "1.8.8", - "resolved": "https://registry.npmjs.org/bower/-/bower-1.8.8.tgz", - "integrity": "sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", diff --git a/tools/performance-server/shared/src/main/kotlin/org/jetbrains/build/Build.kt b/tools/performance-server/shared/src/main/kotlin/org/jetbrains/build/Build.kt new file mode 100644 index 00000000000..3630710d801 --- /dev/null +++ b/tools/performance-server/shared/src/main/kotlin/org/jetbrains/build/Build.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.jetbrains.build + +import org.jetbrains.report.* +import org.jetbrains.report.json.* + +data class Build(val buildNumber: String, val startTime: String, val finishTime: String, val branch: String, + val commits: String, val buildType: String, val failuresNumber: Int, val executionTime: String, + val compileTime: String, val codeSize: String, val bundleSize: String?) { + + companion object: EntityFromJsonFactory { + override fun create(data: JsonElement): Build { + if (data is JsonObject) { + val buildNumber = elementToString(data.getRequiredField("buildNumber"), "buildNumber") + val startTime = elementToString(data.getRequiredField("startTime"), "startTime") + val finishTime = elementToString(data.getRequiredField("finishTime"), "finishTime") + val branch = elementToString(data.getRequiredField("branch"), "branch") + val commits = elementToString(data.getRequiredField("commits"), "commits") + val buildType = elementToString(data.getRequiredField("buildType"), "buildType") + val failuresNumber = elementToInt(data.getRequiredField("failuresNumber"), "failuresNumber") + val executionTime = elementToString(data.getRequiredField("executionTime"), "executionTime") + val compileTime = elementToString(data.getRequiredField("compileTime"), "compileTime") + val codeSize = elementToString(data.getRequiredField("codeSize"), "codeSize") + val bundleSize = elementToStringOrNull(data.getRequiredField("bundleSize"), "bundleSize") + return Build(buildNumber, startTime, finishTime, branch, commits, buildType, failuresNumber, executionTime, + compileTime, codeSize, bundleSize) + } else { + error("Top level entity is expected to be an object. Please, check origin files.") + } + } + } + + private fun formatTime(time: String, targetZone: Int = 3): String { + val matchResult = "^\\d{8}T(\\d{2})(\\d{2})\\d{2}((\\+|-)\\d{2})".toRegex().find(time)?.groupValues + matchResult?.let { + val timeZone = matchResult[3].toInt() + val timeDifference = targetZone - timeZone + var hours = (matchResult[1].toInt() + timeDifference) + if (hours > 23) { + hours -= 24 + } + return "${if (hours < 10) "0$hours" else "$hours"}:${matchResult[2]}" + } ?: error { "Wrong format of time $startTime" } + } + + val date: String by lazy { + val matchResult = "^(\\d{4})(\\d{2})(\\d{2})".toRegex().find(startTime)?.groupValues + matchResult?.let { "${matchResult[3]}/${matchResult[2]}/${matchResult[1]}" } + ?: error { "Wrong format of time $startTime" } + } + + val formattedStartTime: String by lazy { + formatTime(startTime) + } + + val formattedFinishTime: String by lazy { + formatTime(finishTime) + } +} \ No newline at end of file diff --git a/tools/performance-server/src/main/kotlin/routes/route.kt b/tools/performance-server/src/main/kotlin/routes/route.kt index 74ac713d85d..5eedd7c7780 100644 --- a/tools/performance-server/src/main/kotlin/routes/route.kt +++ b/tools/performance-server/src/main/kotlin/routes/route.kt @@ -188,6 +188,11 @@ class CommitsList(data: JsonElement): ConvertedFromJson { fun getBuildsInfoFromBintray(target: String) = sendGetRequest("$downloadBintrayUrl/$target/$buildsFileName") +fun checkBuildType(currentType: String, targetType: String): Boolean { + val releasesBuildTypes = listOf("release", "eap", "rc1", "rc2") + return if (targetType == "release") currentType in releasesBuildTypes else currentType == targetType +} + // Parse and postprocess result of response with build description. fun prepareBuildsResponse(builds: Collection, type: String, branch: String, buildNumber: String? = null): List { val buildsObjects = mutableListOf() @@ -197,7 +202,7 @@ fun prepareBuildsResponse(builds: Collection, type: String, branch: Stri error("Build description $it doesn't contain all necessary information. " + "File with data could be corrupted.") } - if ((tokens[5] == type || type == "day") && (branch == tokens[3] || branch == "all") + if ((checkBuildType(tokens[5], type) || type == "day") && (branch == tokens[3] || branch == "all") || tokens[0] == buildNumber) { buildsObjects.add(Build(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], tokens[6].toInt(), tokens[7], tokens[8], tokens[9], @@ -214,6 +219,7 @@ fun router() { // Register build on Bintray. router.post("/register", { request, response -> + val maxCommitsNumber = 5 val register = BuildRegister.create(JSON.stringify(request.body)) // Get information from TeamCity. @@ -222,8 +228,17 @@ fun router() { register.teamCityPassword, true) val commitsList = CommitsList(JsonTreeParser.parse(changes)) val commitsDescription = buildString { - commitsList.commits.forEach { - append("${it.revision} by ${it.developer};") + if (commitsList.commits.size > maxCommitsNumber) { + append("${commitsList.commits.get(0).revision} by ${commitsList.commits.get(0).developer};") + append("${commitsList.commits.get(1).revision} by ${commitsList.commits.get(1).developer};") + append("...;") + val beforeLast = commitsList.commits.lastIndex - 1 + append("${commitsList.commits.get(beforeLast).revision} by ${commitsList.commits.get(beforeLast).developer};") + append("${commitsList.commits.last().revision} by ${commitsList.commits.last().developer};") + } else { + commitsList.commits.forEach { + append("${it.revision} by ${it.developer};") + } } } diff --git a/tools/performance-server/ui/css/style.css b/tools/performance-server/ui/css/style.css index 6d604d90683..ad8e1c06073 100644 --- a/tools/performance-server/ui/css/style.css +++ b/tools/performance-server/ui/css/style.css @@ -67,4 +67,15 @@ .ct-series-c .ct-point { /* Set the colour of this series line */ stroke: mediumorchid; +} + +.ct-series-d .ct-line { + /* Set the colour of this series line */ + stroke: mediumorchid; +} + +.ct-series-d .ct-point { + /* Set the colour of this series line */ + stroke: mediumorchid; + stroke-width: 20; } \ No newline at end of file diff --git a/tools/performance-server/ui/src/main/kotlin/main.kt b/tools/performance-server/ui/src/main/kotlin/main.kt index 0419974577f..fa77619a76a 100644 --- a/tools/performance-server/ui/src/main/kotlin/main.kt +++ b/tools/performance-server/ui/src/main/kotlin/main.kt @@ -294,7 +294,7 @@ fun main(args: Array) { getChartOptions(compileTime.keys.toTypedArray(), "Time, milliseconds")) val codeSizeChart = Chartist.Line("#codesize_chart", getChartData(labels, codeSize.values, sizeClassName), getChartOptions(codeSize.keys.toTypedArray(), "Size, KB", arrayOf("ct-series-2"))) - val bundleSizeChart = Chartist.Line("#bundlesize_chart", getChartData(labels, listOf(bundleSize), sizeClassName), + val bundleSizeChart = Chartist.Line("#bundlesize_chart", getChartData(labels, listOf(bundleSize), "ct-series-d"), getChartOptions(arrayOf("Bundle size"), "Size, MB", arrayOf("ct-series-2"))) // Tooltips and higlights.