diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildReportsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildReportsIT.kt index d414ac9e9d8..77b8e29a73a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildReportsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildReportsIT.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle +import org.gradle.api.logging.LogLevel import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.internal.build.metrics.GradleBuildMetricsData import org.jetbrains.kotlin.gradle.report.BuildReportType @@ -99,7 +100,8 @@ class BuildReportsIT : KGPBaseTest() { val metricsFile = projectPath.resolve("metrics.bin").toFile() build( "compileKotlin", - "-Pkotlin.internal.single.build.metrics.file=${metricsFile.absolutePath}" + "-Pkotlin.build.report.output=SINGLE_FILE", + "-Pkotlin.build.report.single_file=${metricsFile.absolutePath}" ) assertTrue { metricsFile.exists() } @@ -109,4 +111,33 @@ class BuildReportsIT : KGPBaseTest() { } } } + + @DisplayName("custom value limit") + @GradleTest + fun testCustomValueLimitForBuildScan(gradleVersion: GradleVersion) { + project("simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)) { + build( + "compileKotlin", + "-Pkotlin.build.report.output=BUILD_SCAN", + "-Pkotlin.build.report.build_scan.custom_values_limit=0", + "--scan" + ) { + assertOutputContains("Can't add any more custom values into build scan") + } + } + } + + @DisplayName("build scan listener lazy initialisation") + @GradleTest + fun testBuildScanListenerLazyInitialisation(gradleVersion: GradleVersion) { + project("simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)) { + build( + "compileKotlin", + "-Pkotlin.build.report.output=BUILD_SCAN", + "-Pkotlin.build.report.build_scan.custom_values_limit=0", + ) { + assertOutputDoesNotContain("Can't add any more custom values into build scan") + } + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationCacheIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationCacheIT.kt index 70b63e8a4f2..74c936da94b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationCacheIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationCacheIT.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle +import org.gradle.api.logging.LogLevel import org.gradle.api.logging.configuration.WarningMode import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.report.BuildReportType @@ -252,6 +253,22 @@ class ConfigurationCacheIT : AbstractConfigurationCacheIT() { } } } + + @JvmGradlePluginTests + @DisplayName("with build build scan report") + @GradleTest + fun testBuildScanReportSmokeTestForConfigurationCache(gradleVersion: GradleVersion) { + project("simpleProject", gradleVersion) { + val buildOptions = defaultBuildOptions.copy(buildReport = listOf(BuildReportType.BUILD_SCAN), logLevel = LogLevel.DEBUG) + build("clean", "assemble", "-Pkotlin.build.report.build_scan.custom_values_limit=0", "--scan", buildOptions = buildOptions) { + assertOutputContains("Can't add any more custom values into build scan") + } + + build("clean", "assemble", "-Pkotlin.build.report.build_scan.custom_values_limit=0", "--scan", buildOptions = buildOptions) { + assertOutputContains("Can't add any more custom values into build scan") + } + } + } } abstract class AbstractConfigurationCacheIT : KGPBaseTest() { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt index 991d3043043..73f76217cf5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.gradle.plugin -import com.gradle.scan.plugin.BuildScanExtension import org.gradle.api.Project import org.gradle.api.logging.Logging import org.gradle.api.provider.Provider @@ -14,10 +13,6 @@ import org.gradle.api.services.BuildServiceParameters import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers -import org.jetbrains.kotlin.gradle.plugin.statistics.BuildScanStatisticsListener -import org.jetbrains.kotlin.gradle.report.BuildReportType -import org.jetbrains.kotlin.gradle.report.ReportingSettings -import org.jetbrains.kotlin.gradle.report.reportingSettings import java.io.File internal abstract class KotlinGradleBuildServices : BuildService, AutoCloseable { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index e63f5677d97..1f83d929342 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.internal.KOTLIN_COMPILER_EMBEDDABLE import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP import org.jetbrains.kotlin.gradle.logging.kotlinDebug -import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.runMultiplatformAndroidGradlePluginCompatibilityHealthCheck import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformAndroidGradlePluginCompatibilityHealthCheck.runMultiplatformAndroidGradlePluginCompatibilityHealthCheckWhenAndroidIsApplied import org.jetbrains.kotlin.gradle.plugin.internal.* import org.jetbrains.kotlin.gradle.plugin.internal.BasePluginConfiguration diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt index f2b760b337f..0db34334a90 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt @@ -97,6 +97,9 @@ internal class PropertiesProvider private constructor(private val project: Proje val buildReportHttpPassword: String? get() = this.property("kotlin.build.report.http.password") + val buildReportBuildScanCustomValuesLimit: Int + get() = property("kotlin.build.report.build_scan.custom_values_limit")?.toInt() ?: 1000 + val buildReportMetrics: Boolean get() = booleanProperty("kotlin.build.report.metrics") ?: false diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildScanStatisticsListener.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildScanStatisticsListener.kt deleted file mode 100644 index 552c614d043..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildScanStatisticsListener.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.plugin.statistics - -import com.gradle.scan.plugin.BuildScanExtension -import org.gradle.api.logging.Logging -import org.gradle.tooling.events.FinishEvent -import org.gradle.tooling.events.OperationCompletionListener -import org.gradle.tooling.events.task.TaskFinishEvent -import org.jetbrains.kotlin.build.report.metrics.SizeMetricType -import org.jetbrains.kotlin.gradle.plugin.stat.CompileStatisticsData -import org.jetbrains.kotlin.gradle.utils.formatSize -import org.jetbrains.kotlin.konan.file.File -import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult -import java.util.* -import kotlin.system.measureTimeMillis - -class BuildScanStatisticsListener( - private val buildScan: BuildScanExtension, - val projectName: String, - val label: String?, - val kotlinVersion: String, - val buildUuid: String -) : OperationCompletionListener, AutoCloseable { - companion object { - const val lengthLimit = 100_000 - const val customValuesLimit = 950 //git plugin and others can add custom values as well - } - - private val tags = LinkedHashSet() - private val log = Logging.getLogger(this.javaClass) - private var customValues = 0 // doesn't need to be thread-safe - - override fun onFinish(event: FinishEvent?) { - if (event is TaskFinishEvent) { - val (collectDataDuration, compileStatData) = measureTimeMillisWithResult { - KotlinBuildStatListener.prepareData(event, projectName, buildUuid, label, kotlinVersion) - } - log.debug("Collect data takes $collectDataDuration: $compileStatData") - - compileStatData?.also { - report(it) - } - } - } - - override fun close() { - } - - fun report(data: CompileStatisticsData) { - val elapsedTime = measureTimeMillis { - if (!tags.contains(buildUuid)) { - tags.add(buildUuid) - } - data.label?.takeIf { !tags.contains(it) }?.also { - buildScan.tag(it) - tags.add(it) - } - data.tags - .filter { !tags.contains(it) } - .forEach { - buildScan.tag(it) - tags.add(it) - } - - if (customValues < customValuesLimit) { - readableString(data).forEach { - if (customValues < customValuesLimit) { - buildScan.value(data.taskName, it) - customValues++ - } else { - log.debug("Statistic data for ${data.taskName} was cut due to custom values limit.") - } - } - } else { - log.debug("Can't add any more custom values into build scan.") - } - } - - log.debug("Report statistic to build scan takes $elapsedTime ms") - } - - private fun readableString(data: CompileStatisticsData): List { - val readableString = StringBuilder() - if (data.nonIncrementalAttributes.isEmpty()) { - readableString.append("Incremental build; ") - data.changes.joinTo(readableString, prefix = "Changes: [", postfix = "]; ") { it.substringAfterLast(File.separator) } - } else { - data.nonIncrementalAttributes.joinTo(readableString, prefix = "Non incremental build because: [", postfix = "]; ") { it.readableString } - } - - val timeData = - data.buildTimesMetrics.map { (key, value) -> "${key.readableString}: ${value}ms" } //sometimes it is better to have separate variable to be able debug - val perfData = data.performanceMetrics.map { (key, value) -> - when (key.type) { - SizeMetricType.BYTES -> "${key.readableString}: ${formatSize(value)}" - else -> "${key.readableString}: $value}" - } - } - timeData.union(perfData).joinTo(readableString, ",", "Performance: [", "]") - - return splitStringIfNeed(readableString.toString(), lengthLimit) - } - - private fun splitStringIfNeed(str: String, lengthLimit: Int): List { - val splattedString = ArrayList() - var tempStr = str - while (tempStr.length > lengthLimit) { - val subSequence = tempStr.substring(lengthLimit) - var index = subSequence.lastIndexOf(';') - if (index == -1) { - index = subSequence.lastIndexOf(',') - if (index == -1) { - index = lengthLimit - } - } - splattedString.add(tempStr.substring(index)) - tempStr = tempStr.substring(index) - - } - splattedString.add(tempStr) - return splattedString - } -} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatListener.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatListener.kt deleted file mode 100644 index eac13238088..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatListener.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.gradle.plugin.statistics - -import org.gradle.tooling.events.task.TaskFailureResult -import org.gradle.tooling.events.task.TaskFinishEvent -import org.gradle.tooling.events.task.TaskSkippedResult -import org.gradle.tooling.events.task.TaskSuccessResult -import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults -import org.jetbrains.kotlin.gradle.plugin.stat.CompileStatisticsData -import org.jetbrains.kotlin.gradle.plugin.stat.StatTag -import org.jetbrains.kotlin.gradle.report.TaskExecutionResult -import org.jetbrains.kotlin.incremental.ChangedFiles -import org.jetbrains.kotlin.utils.addToStdlib.ifTrue -import java.lang.management.ManagementFactory -import java.net.InetAddress -import java.util.* - -enum class TaskExecutionState { - SKIPPED, - FAILED, - UNKNOWN, - SUCCESS, - FROM_CACHE, - UP_TO_DATE - ; -} - -class KotlinBuildStatListener { - companion object { - val hostName: String? = try { - InetAddress.getLocalHost().hostName - } catch (_: Exception) { - //do nothing - null - } - - private fun availableForStat(taskPath: String): Boolean { - return taskPath.contains("Kotlin") && (TaskExecutionResults[taskPath] != null) - } - - internal fun prepareData( - event: TaskFinishEvent, - projectName: String, - uuid: String, - label: String?, - kotlinVersion: String, - additionalTags: List = emptyList() - ): CompileStatisticsData? { - val result = event.result - val taskPath = event.descriptor.taskPath - val durationMs = result.endTime - result.startTime - val taskResult = when (result) { - is TaskSuccessResult -> when { - result.isFromCache -> TaskExecutionState.FROM_CACHE - result.isUpToDate -> TaskExecutionState.UP_TO_DATE - else -> TaskExecutionState.SUCCESS - } - - is TaskSkippedResult -> TaskExecutionState.SKIPPED - is TaskFailureResult -> TaskExecutionState.FAILED - else -> TaskExecutionState.UNKNOWN - } - - if (!availableForStat(taskPath)) { - return null - } - - val taskExecutionResult = TaskExecutionResults[taskPath] - val buildTimesMs = taskExecutionResult?.buildMetrics?.buildTimes?.asMapMs()?.filterValues { value -> value != 0L } ?: emptyMap() - val perfData = - taskExecutionResult?.buildMetrics?.buildPerformanceMetrics?.asMap()?.filterValues { value -> value != 0L } ?: emptyMap() - val changes = when (val changedFiles = taskExecutionResult?.taskInfo?.changedFiles) { - is ChangedFiles.Known -> changedFiles.modified.map { it.absolutePath } + changedFiles.removed.map { it.absolutePath } - is ChangedFiles.Dependencies -> changedFiles.modified.map { it.absolutePath } + changedFiles.removed.map { it.absolutePath } - else -> emptyList() - - } - return CompileStatisticsData( - durationMs = durationMs, - taskResult = taskResult.name, - label = label, - buildTimesMetrics = buildTimesMs, - performanceMetrics = perfData, - projectName = projectName, - taskName = taskPath, - changes = changes, - tags = parseTags(taskExecutionResult, additionalTags).map { it.name }, - nonIncrementalAttributes = taskExecutionResult?.buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys ?: emptySet(), - hostName = hostName, - kotlinVersion = kotlinVersion, - buildUuid = uuid, - finishTime = System.currentTimeMillis(), - compilerArguments = taskExecutionResult?.taskInfo?.compilerArguments?.asList() ?: emptyList() - ) - } - - private fun parseTags(taskExecutionResult: TaskExecutionResult?, additionalTags: List): List { - val tags = ArrayList(additionalTags) - - val nonIncrementalAttributes = taskExecutionResult?.buildMetrics?.buildAttributes?.asMap() ?: emptyMap() - - if (nonIncrementalAttributes.isEmpty()) { - tags.add(StatTag.INCREMENTAL) - } else { - tags.add(StatTag.NON_INCREMENTAL) - } - - val taskInfo = taskExecutionResult?.taskInfo - - taskInfo?.withAbiSnapshot?.ifTrue { - tags.add(StatTag.ABI_SNAPSHOT) - } - taskInfo?.withArtifactTransform?.ifTrue { - tags.add(StatTag.ARTIFACT_TRANSFORM) - } - - val debugConfiguration = "-agentlib:" - if (ManagementFactory.getRuntimeMXBean().inputArguments.firstOrNull { it.startsWith(debugConfiguration) } != null) { - tags.add(StatTag.GRADLE_DEBUG) - } - return tags - } - - } - -} - - diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildReportsService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildReportsService.kt index 40cd1805f80..f30b63fd293 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildReportsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildReportsService.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.gradle.report import com.google.gson.Gson -import com.gradle.scan.plugin.BuildScanExtension import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logging @@ -17,24 +16,34 @@ import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters import org.gradle.tooling.events.FinishEvent import org.gradle.tooling.events.OperationCompletionListener +import org.gradle.tooling.events.task.TaskFailureResult import org.gradle.tooling.events.task.TaskFinishEvent +import org.gradle.tooling.events.task.TaskSkippedResult +import org.gradle.tooling.events.task.TaskSuccessResult +import org.jetbrains.kotlin.build.report.metrics.SizeMetricType import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion +import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults import org.jetbrains.kotlin.gradle.plugin.stat.BuildFinishStatisticsData +import org.jetbrains.kotlin.gradle.plugin.stat.CompileStatisticsData import org.jetbrains.kotlin.gradle.plugin.stat.GradleBuildStartParameters import org.jetbrains.kotlin.gradle.plugin.stat.StatTag -import org.jetbrains.kotlin.gradle.plugin.statistics.BuildScanStatisticsListener -import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatListener import org.jetbrains.kotlin.gradle.report.data.BuildExecutionData +import org.jetbrains.kotlin.gradle.utils.formatSize import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable +import org.jetbrains.kotlin.incremental.ChangedFiles +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.utils.addToStdlib.ifTrue +import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult import java.io.IOException +import java.lang.management.ManagementFactory import java.net.HttpURLConnection +import java.net.InetAddress import java.net.URL import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit import kotlin.system.measureTimeMillis abstract class BuildReportsService : BuildService, AutoCloseable, OperationCompletionListener { @@ -45,8 +54,8 @@ abstract class BuildReportsService : BuildService? = null - + private val tags = LinkedHashSet() + private var customValues = 0 // doesn't need to be thread-safe init { log.info("Build report service is registered. Unique build id: $buildUuid") @@ -112,35 +121,11 @@ abstract class BuildReportsService : BuildService { + val readableString = StringBuilder() + if (data.nonIncrementalAttributes.isEmpty()) { + readableString.append("Incremental build; ") + data.changes.joinTo(readableString, prefix = "Changes: [", postfix = "]; ") { it.substringAfterLast(File.separator) } + } else { + data.nonIncrementalAttributes.joinTo( + readableString, + prefix = "Non incremental build because: [", + postfix = "]; " + ) { it.readableString } + } + + val timeData = + data.buildTimesMetrics.map { (key, value) -> "${key.readableString}: ${value}ms" } //sometimes it is better to have separate variable to be able debug + val perfData = data.performanceMetrics.map { (key, value) -> + when (key.type) { + SizeMetricType.BYTES -> "${key.readableString}: ${formatSize(value)}" + else -> "${key.readableString}: $value}" + } + } + timeData.union(perfData).joinTo(readableString, ",", "Performance: [", "]") + + return splitStringIfNeed(readableString.toString(), lengthLimit) + } + + private fun splitStringIfNeed(str: String, lengthLimit: Int): List { + val splattedString = ArrayList() + var tempStr = str + while (tempStr.length > lengthLimit) { + val subSequence = tempStr.substring(lengthLimit) + var index = subSequence.lastIndexOf(';') + if (index == -1) { + index = subSequence.lastIndexOf(',') + if (index == -1) { + index = lengthLimit + } + } + splattedString.add(tempStr.substring(index)) + tempStr = tempStr.substring(index) + + } + splattedString.add(tempStr) + return splattedString + } + companion object { + private val log = Logging.getLogger(this.javaClass) + const val lengthLimit = 100_000 + fun getStartParameters(project: Project) = project.gradle.startParameter.let { GradleBuildStartParameters( tasks = it.taskRequests.flatMap { it.args }, @@ -251,12 +347,19 @@ abstract class BuildReportsService : BuildService + it.get().addBuildScanReport(event, BuildScanExtensionHolder(buildScanExtension)) + } + }) + } } } @@ -270,6 +373,112 @@ abstract class BuildReportsService : BuildService = emptyList() + ): CompileStatisticsData? { + val result = event.result + val taskPath = event.descriptor.taskPath + val durationMs = result.endTime - result.startTime + val taskResult = when (result) { + is TaskSuccessResult -> when { + result.isFromCache -> TaskExecutionState.FROM_CACHE + result.isUpToDate -> TaskExecutionState.UP_TO_DATE + else -> TaskExecutionState.SUCCESS + } + + is TaskSkippedResult -> TaskExecutionState.SKIPPED + is TaskFailureResult -> TaskExecutionState.FAILED + else -> TaskExecutionState.UNKNOWN + } + + if (!availableForStat(taskPath)) { + return null + } + + val taskExecutionResult = TaskExecutionResults[taskPath] + val buildTimesMs = taskExecutionResult?.buildMetrics?.buildTimes?.asMapMs()?.filterValues { value -> value != 0L } ?: emptyMap() + val perfData = + taskExecutionResult?.buildMetrics?.buildPerformanceMetrics?.asMap()?.filterValues { value -> value != 0L } ?: emptyMap() + val changes = when (val changedFiles = taskExecutionResult?.taskInfo?.changedFiles) { + is ChangedFiles.Known -> changedFiles.modified.map { it.absolutePath } + changedFiles.removed.map { it.absolutePath } + is ChangedFiles.Dependencies -> changedFiles.modified.map { it.absolutePath } + changedFiles.removed.map { it.absolutePath } + else -> emptyList() + + } + return CompileStatisticsData( + durationMs = durationMs, + taskResult = taskResult.name, + label = label, + buildTimesMetrics = buildTimesMs, + performanceMetrics = perfData, + projectName = projectName, + taskName = taskPath, + changes = changes, + tags = parseTags(taskExecutionResult, additionalTags).map { it.name }, + nonIncrementalAttributes = taskExecutionResult?.buildMetrics?.buildAttributes?.asMap()?.filter { it.value > 0 }?.keys + ?: emptySet(), + hostName = hostName, + kotlinVersion = kotlinVersion, + buildUuid = uuid, + finishTime = System.currentTimeMillis(), + compilerArguments = taskExecutionResult?.taskInfo?.compilerArguments?.asList() ?: emptyList() + ) + } + + val hostName: String? = try { + InetAddress.getLocalHost().hostName + } catch (_: Exception) { + //do nothing + null + } + + private fun availableForStat(taskPath: String): Boolean { + return taskPath.contains("Kotlin") && (TaskExecutionResults[taskPath] != null) + } + + private fun parseTags(taskExecutionResult: TaskExecutionResult?, additionalTags: List): List { + val tags = ArrayList(additionalTags) + + val nonIncrementalAttributes = taskExecutionResult?.buildMetrics?.buildAttributes?.asMap() ?: emptyMap() + + if (nonIncrementalAttributes.isEmpty()) { + tags.add(StatTag.INCREMENTAL) + } else { + tags.add(StatTag.NON_INCREMENTAL) + } + + val taskInfo = taskExecutionResult?.taskInfo + + taskInfo?.withAbiSnapshot?.ifTrue { + tags.add(StatTag.ABI_SNAPSHOT) + } + taskInfo?.withArtifactTransform?.ifTrue { + tags.add(StatTag.ARTIFACT_TRANSFORM) + } + + val debugConfiguration = "-agentlib:" + if (ManagementFactory.getRuntimeMXBean().inputArguments.firstOrNull { it.startsWith(debugConfiguration) } != null) { + tags.add(StatTag.GRADLE_DEBUG) + } + return tags + } + } -} \ No newline at end of file +} + +enum class TaskExecutionState { + SKIPPED, + FAILED, + UNKNOWN, + SUCCESS, + FROM_CACHE, + UP_TO_DATE + ; +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildScanExtensionHolder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildScanExtensionHolder.kt new file mode 100644 index 00000000000..f52f870989b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildScanExtensionHolder.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.report + +import com.gradle.scan.plugin.BuildScanExtension + +class BuildScanExtensionHolder(val buildScan: BuildScanExtension?) : java.io.Serializable { + constructor(extension: Any?) : this(extension as BuildScanExtension) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/ReportingSettings.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/ReportingSettings.kt index 6c4445d5d2d..50db59f2057 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/ReportingSettings.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/ReportingSettings.kt @@ -14,6 +14,7 @@ data class ReportingSettings( val buildReportLabel: String? = null, val fileReportSettings: FileReportSettings? = null, val httpReportSettings: HttpReportSettings? = null, + val buildScanReportSettings: BuildScanSettings? = null, val singleOutputFile: File? = null ) : Serializable { companion object { @@ -38,4 +39,12 @@ data class HttpReportSettings( companion object { const val serialVersionUID: Long = 0 } +} + +data class BuildScanSettings( + val customValueLimit: Int +): Serializable { + companion object { + const val serialVersionUID: Long = 0 + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt index 543cd1f87b1..477eb8fd76d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt @@ -37,8 +37,14 @@ internal fun reportingSettings(rootProject: Project): ReportingSettings { null } + val buildScanSettings = if (buildReportOutputTypes.contains(BuildReportType.BUILD_SCAN)) { + BuildScanSettings(properties.buildReportBuildScanCustomValuesLimit) + } else { + null + } + //temporary solution. support old property - val oldSingleBuildMetric = properties.singleBuildMetricsFile?.also { buildReportOutputTypes.add(BuildReportType.SINGLE_FILE) } + val oldSingleBuildMetric = properties.singleBuildMetricsFile?.also { buildReportOutputTypes.add(BuildReportType.SINGLE_FILE) } val singleOutputFile = if (buildReportOutputTypes.contains(BuildReportType.SINGLE_FILE)) { properties.buildReportSingleFile ?: oldSingleBuildMetric @@ -49,6 +55,7 @@ internal fun reportingSettings(rootProject: Project): ReportingSettings { buildReportLabel = properties.buildReportLabel, fileReportSettings = fileReportSettings, httpReportSettings = httpReportSettings, + buildScanReportSettings = buildScanSettings, buildReportOutputs = buildReportOutputTypes, singleOutputFile = singleOutputFile, ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt index 84f9639ed94..51c34c71c68 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt @@ -59,13 +59,13 @@ internal abstract class AbstractKotlinCompileConfig task.kotlinDaemonJvmArguments.set(providers.provider { kotlinDaemonJvmArgs.split("\\s+".toRegex())