Added register task and some fixes for TeamCity (#2785)

This commit is contained in:
LepilkinaElena
2019-03-19 17:25:48 +03:00
committed by GitHub
parent feec5b2cbd
commit d8c1e85025
5 changed files with 190 additions and 21 deletions
+14
View File
@@ -56,6 +56,7 @@ task slackReport(type: RegressionsReporter) {
defaultBranch = project.findProperty('kotlin.native.default.branch') ?: "master"
def target = System.getProperty("os.name")
summaryFile = "${targetsResults}/${target}.txt"
bundleBuild = project.findProperty('kotlin.bundleBuild') == null ? false : true
}
}
@@ -80,6 +81,19 @@ private def uploadBenchmarkResultToBintray(String fileName) {
}
}
task registerBuild(type: BuildRegister) {
// Get bundle size.
bundleSize = null
if (project.findProperty('kotlin.bundleBuild') != null) {
def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist'
dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist"
bundleSize = (new File(dist)).directorySize()
}
currentBenchmarksReportFile = "${buildDir.absolutePath}/${nativeJson}"
analyzer = MPPTools.findFile("${analyzerTool}${MPPTools.getNativeProgramExtension()}",
"${rootBuildDirectory}/${analyzerToolDirectory}")
}
def mergeReports(String fileName) {
def reports = []
subprojects.each {
@@ -0,0 +1,137 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import com.ullink.slack.simpleslackapi.impl.SlackSessionFactory
import org.jetbrains.report.json.*
import java.io.FileInputStream
import java.io.IOException
import java.io.File
import java.io.OutputStreamWriter
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.concurrent.TimeUnit
import java.net.HttpURLConnection
import java.net.URL
import java.util.Base64
import java.util.Properties
/**
* Task to produce regressions report and send it to slack. Requires a report with current benchmarks result
* and path to analyzer tool
*
* @property currentBenchmarksReportFile path to file with becnhmarks result
* @property analyzer path to analyzer tool
* @property bundleSize size of build
*/
open class BuildRegister : DefaultTask() {
@Input
lateinit var currentBenchmarksReportFile: String
@Input
lateinit var analyzer: String
var bundleSize: Int? = null
val buildInfoToken: Int = 4
val compileTimeSamplesNumber: Int = 2
val buildNumberTokens: Int = 3
val performanceServer = "https://kotlin-native-perf-summary.labs.jb.gg"
private fun sendPostRequest(url: String, body: String) : String {
val connection = URL(url).openConnection() as HttpURLConnection
return connection.apply {
setRequestProperty("Content-Type", "application/json; charset=utf-8")
requestMethod = "POST"
doOutput = true
val outputWriter = OutputStreamWriter(outputStream)
outputWriter.write(body)
outputWriter.flush()
}.let {
if (it.responseCode == 200) it.inputStream else it.errorStream
}.let { streamToRead ->
BufferedReader(InputStreamReader(streamToRead)).use {
val response = StringBuffer()
var inputLine = it.readLine()
while (inputLine != null) {
response.append(inputLine)
inputLine = it.readLine()
}
it.close()
response.toString()
}
}
}
@TaskAction
fun run() {
// Get TeamCity properties.
val teamcityConfig = System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") ?:
error("Can't load teamcity config!")
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")
// Get summary information.
val output = arrayOf("$analyzer", "summary", "-exec-samples", "all", "-compile", "samples",
"-compile-samples", "HelloWorld,Videoplayer", "-codesize-samples", "all", "$currentBenchmarksReportFile")
.runCommand()
// Postprocess information.
val buildInfoParts = output.split(',')
if (buildInfoParts.size != buildInfoToken) {
error("Problems with getting summary information using $analyzer and $currentBenchmarksReportFile.")
}
val (failures, executionTime, compileTime, codeSize) = buildInfoParts.map { it.trim() }
// Add legends.
val geometricMean = "Geometric Mean-"
val executionTimeInfo = "$geometricMean$executionTime"
val codeSizeInfo = "$geometricMean$codeSize"
val compileTimeSamples = compileTime.split(';')
if (compileTimeSamples.size != compileTimeSamplesNumber) {
error("Problems with getting compile time samples value. Expected at least $compileTimeSamplesNumber samples, got ${compileTimeSamples.size}")
}
val (helloWorldCompile, videoplayerCompile) = compileTimeSamples
val compileTimeInfo = "HelloWorld-$helloWorldCompile;Videoplayer-$videoplayerCompile"
val target = System.getProperty("os.name").replace("\\s".toRegex(), "")
val buildNumberParts = buildNumber.split("-")
if (buildNumberParts.size != buildNumberTokens) {
error("Wrong format of build number $buildNumber.")
}
val (_, buildType, _) = buildNumberParts
// Send post request to register build.
val requestBody = buildString {
append("{\"buildId\":\"$buildId\",")
append("\"teamCityUser\":\"$teamCityUser\",")
append("\"teamCityPassword\":\"$teamCityPassword\",")
append("\"bintrayUser\": \"$bintrayUser\", ")
append("\"bintrayPassword\":\"$bintrayApiKey\", ")
append("\"target\": \"$target\",")
append("\"buildType\": \"$buildType\",")
append("\"failuresNumber\": $failures,")
append("\"executionTime\": \"$executionTimeInfo\",")
append("\"compileTime\": \"$compileTimeInfo\",")
append("\"codeSize\": \"$codeSizeInfo\",")
append("\"bundleSize\": ${bundleSize?.let {"\"$bundleSize\""} ?: bundleSize}}")
}
println(sendPostRequest("$performanceServer/register", requestBody))
}
}
@@ -24,23 +24,6 @@ import java.net.URL
import java.util.Base64
import java.util.Properties
// Run command line from string.
fun Array<String>.runCommand(workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS): String {
return try {
ProcessBuilder(*this)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().apply {
waitFor(timeoutAmount, timeoutUnit)
}.inputStream.bufferedReader().readText()
} catch (e: IOException) {
error("Couldn't run command $this")
}
}
data class Commit(val revision: String, val developer: String, val webUrlWithDescription: String)
// List of commits.
@@ -78,6 +61,7 @@ class CommitsList(data: JsonElement): ConvertedFromJson {
* @property htmlReport name of result html report
* @property defaultBranch name of default branch
* @property summaryFile name of file with short summary
* @property bundleBuild property to show if current build is full or not
*/
open class RegressionsReporter : DefaultTask() {
@@ -114,6 +98,9 @@ open class RegressionsReporter : DefaultTask() {
@Input
lateinit var summaryFile: String
@Input
var bundleBuild: Boolean = false
private fun tabUrl(buildId: String, buildTypeId: String, tab: String) =
"$teamCityUrl/viewLog.html?buildId=$buildId&buildTypeId=$buildTypeId&tab=$tab"
@@ -239,8 +226,10 @@ open class RegressionsReporter : DefaultTask() {
session.connect()
if (branch == defaultBranch) {
val channel = session.findChannelByName(buildProperties.getProperty("konan-channel-name"))
session.sendMessage(channel, message)
if (bundleBuild) {
val channel = session.findChannelByName(buildProperties.getProperty("konan-channel-name"))
session.sendMessage(channel, message)
}
} else {
changesList.commits.filter { it.developer in slackUsers }. map { it.developer }
.toSet().forEach {
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import java.io.FileInputStream
import java.io.IOException
import java.io.File
import java.util.concurrent.TimeUnit
// Run command line from string.
fun Array<String>.runCommand(workingDir: File = File("."),
timeoutAmount: Long = 60,
timeoutUnit: TimeUnit = TimeUnit.SECONDS): String {
return try {
ProcessBuilder(*this)
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().apply {
waitFor(timeoutAmount, timeoutUnit)
}.inputStream.bufferedReader().readText()
} catch (e: IOException) {
error("Couldn't run command $this")
}
}
@@ -82,6 +82,9 @@ fun getChartOptions(samples: Array<String>): dynamic {
val axisXObject: dynamic = object{}
axisXObject["offset"] = 40
chartOptions["axisX"] = axisXObject
val axisYObject: dynamic = object{}
axisYObject["offset"] = 70
chartOptions["axisY"] = axisYObject
val legendObject: dynamic = object{}
legendObject["legendNames"] = samples
chartOptions["plugins"] = arrayOf(Chartist.plugins.legend(legendObject))
@@ -236,7 +239,7 @@ fun main(args: Array<String>) {
val labels = mutableListOf<String>()
val executionTime = mutableMapOf<String, MutableList<Double?>>()
val compileTime = mutableMapOf<String, MutableList<Double?>>()
val codeSize = mutableMapOf<String, MutableList<Int?>>()
val codeSize = mutableMapOf<String, MutableList<Double?>>()
val bundleSize = mutableListOf<Int?>()
builds.forEach {
@@ -248,7 +251,7 @@ fun main(args: Array<String>) {
}
separateValues(it.executionTime, executionTime) { value -> value.toDouble() }
separateValues(it.compileTime, compileTime) { value -> value.toDouble() }
separateValues(it.codeSize, codeSize) { value -> value.toInt() }
separateValues(it.codeSize, codeSize) { value -> value.toDouble() }
bundleSize.add(it.bundleSize?.toInt())
}