Added register task and some fixes for TeamCity (#2785)
This commit is contained in:
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user