KT-57224 Support Language version Tag

This commit is contained in:
nataliya.valtman
2023-03-27 12:20:47 +02:00
committed by Space Team
parent 95541da9a1
commit 4bb8bd3901
10 changed files with 121 additions and 54 deletions
@@ -17,6 +17,7 @@ import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.util.*
import io.ktor.util.collections.*
import org.gradle.api.logging.LogLevel
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.stat.*
import org.jetbrains.kotlin.gradle.report.BuildReportType
@@ -193,7 +194,7 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
@GradleTest
fun testHttpRequest(gradleVersion: GradleVersion) {
simpleTestHttpReport(gradleVersion) { taskData ->
assertContains(taskData.tags, "NON_INCREMENTAL")
assertContains(taskData.tags, StatTag.NON_INCREMENTAL)
assertContains(taskData.nonIncrementalAttributes.map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS")
assertFalse(taskData.performanceMetrics.keys.isEmpty())
assertFalse(taskData.buildTimesMetrics.keys.isEmpty())
@@ -216,7 +217,7 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
""".trimMargin()
)
}) { taskData ->
assertContains(taskData.tags, "NON_INCREMENTAL")
assertContains(taskData.tags, StatTag.NON_INCREMENTAL)
assertContains(taskData.nonIncrementalAttributes.map { it.name }, "UNKNOWN_CHANGES_IN_GRADLE_INPUTS")
assertFalse(taskData.performanceMetrics.keys.isEmpty())
assertFalse(taskData.buildTimesMetrics.keys.isEmpty())
@@ -246,15 +247,22 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
}
validateTaskData(port) { taskData ->
assertEquals(":lib:compileKotlin", taskData.taskName)
assertContentEquals(listOf("ARTIFACT_TRANSFORM", "CONFIGURATION_CACHE", "NON_INCREMENTAL"), taskData.tags.sorted(), )
assertContentEquals(
listOf(
StatTag.ARTIFACT_TRANSFORM,
StatTag.NON_INCREMENTAL,
StatTag.CONFIGURATION_CACHE,
StatTag.KOTLIN_1,
), taskData.tags.sorted(),
)
assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion,
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}"
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}"
)
}
validateTaskData(port) { taskData ->
assertEquals(":app:compileKotlin", taskData.taskName)
assertContentEquals(taskData.tags.sorted(), listOf("ARTIFACT_TRANSFORM", "CONFIGURATION_CACHE", "NON_INCREMENTAL"))
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.NON_INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted())
assertEquals(
defaultBuildOptions.kotlinVersion, taskData.kotlinVersion,
"Unexpected kotlinVersion: ${taskData.kotlinVersion} instead of ${defaultBuildOptions.kotlinVersion}"
@@ -266,11 +274,11 @@ class BuildStatisticsWithKtorIT : KGPBaseTest() {
//second build
validateTaskData(port) { taskData ->
assertEquals(":lib:compileKotlin", taskData.taskName)
assertContentEquals(taskData.tags.sorted(), listOf("ARTIFACT_TRANSFORM", "CONFIGURATION_CACHE", "INCREMENTAL"))
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted())
}
validateTaskData(port) { taskData ->
assertEquals(":app:compileKotlin", taskData.taskName)
assertContentEquals(taskData.tags.sorted(), listOf("ARTIFACT_TRANSFORM", "CONFIGURATION_CACHE", "INCREMENTAL"))
assertContentEquals(listOf(StatTag.ARTIFACT_TRANSFORM, StatTag.INCREMENTAL, StatTag.CONFIGURATION_CACHE, StatTag.KOTLIN_1), taskData.tags.sorted())
}
}
}
@@ -44,19 +44,13 @@ private fun File.updateSettingsGradle() {
private fun File.updateBuildKtsGradle() {
modify {
if (it.contains("buildscript {")) {
it.replaceFirst(
"dependencies {", "dependencies {\n" +
"classpath(\"org.jetbrains.kotlin:kotlin-compiler-args-properties:${'$'}test_fixes_version\")"
)
} else {
it.replace(
"plugins {",
"plugins {\nid(\"org.jetbrains.kotlin.test.kotlin-compiler-args-properties\")"
)
}
it.replace(
"plugins {",
"plugins {\nid(\"org.jetbrains.kotlin.test.kotlin-compiler-args-properties\")"
)
}
}
private fun File.updateBuildGradle() {
modify {
if (it.contains("buildscript {")) {
@@ -42,6 +42,8 @@ import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import java.io.File
import java.lang.ref.WeakReference
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
const val CREATED_CLIENT_FILE_PREFIX = "Created client-is-alive flag file: "
const val EXISTING_CLIENT_FILE_PREFIX = "Existing client-is-alive flag file: "
@@ -194,7 +196,9 @@ internal open class GradleCompilerRunner(
allWarningsAsErrors = compilerArgs.allWarningsAsErrors,
compilerExecutionSettings = compilerExecutionSettings,
errorsFile = errorsFile,
kotlinPluginVersion = getKotlinPluginVersion(loggerProvider)
kotlinPluginVersion = getKotlinPluginVersion(loggerProvider),
//no need to log warnings in MessageCollector hear it will be logged by compiler
kotlinLanguageVersion = parseLanguageVersion(compilerArgs.languageVersion, compilerArgs.useK2)
)
TaskLoggers.put(pathProvider, loggerProvider)
return runCompilerAsync(
@@ -203,6 +207,12 @@ internal open class GradleCompilerRunner(
)
}
//Copy of CommonCompilerArguments.parseOrConfigureLanguageVersion to avoid direct dependency
private fun parseLanguageVersion(languageVersion: String?, useK2: Boolean): KotlinVersion {
val explicitVersion = languageVersion?.let { KotlinVersion.fromVersion(languageVersion) } ?: KotlinVersion.DEFAULT
return if (useK2 && (explicitVersion < KotlinVersion.KOTLIN_2_0)) KotlinVersion.KOTLIN_2_0 else explicitVersion
}
protected open fun runCompilerAsync(
workArgs: GradleKotlinCompilerWorkArguments,
taskOutputsBackup: TaskOutputsBackup?
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.logging.*
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers
@@ -69,6 +70,7 @@ internal class GradleKotlinCompilerWorkArguments(
val compilerExecutionSettings: CompilerExecutionSettings,
val errorsFile: File?,
val kotlinPluginVersion: String,
val kotlinLanguageVersion: KotlinVersion,
) : Serializable {
companion object {
const val serialVersionUID: Long = 1
@@ -106,6 +108,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val compilerExecutionSettings = config.compilerExecutionSettings
private val errorsFile = config.errorsFile
private val kotlinPluginVersion = config.kotlinPluginVersion
private val kotlinLanguageVersion = config.kotlinLanguageVersion
private val log: KotlinLogger =
TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } }
@@ -138,6 +141,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
throwExceptionIfCompilationFailed(exitCode, executionStrategy)
} finally {
val taskInfo = TaskExecutionInfo(
kotlinLanguageVersion = kotlinLanguageVersion,
changedFiles = incrementalCompilationEnvironment?.changedFiles,
compilerArguments = if (reportingSettings.includeCompilerArguments) compilerArgs else emptyArray(),
withAbiSnapshot = incrementalCompilationEnvironment?.withAbiSnapshot,
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.BuildTime
import java.text.SimpleDateFormat
import java.util.*
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
//Sensitive data. This object is used directly for statistic via http
private val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").also { it.timeZone = TimeZone.getTimeZone("UTC")}
@@ -20,10 +21,11 @@ data class CompileStatisticsData(
val taskName: String?,
val taskResult: String,
val durationMs: Long,
val tags: List<String>,
val tags: List<StatTag>,
val changes: List<String>,
val buildUuid: String = "Unset",
val kotlinVersion: String,
val kotlinLanguageVersion: KotlinVersion?,
val hostName: String? = "Unset",
val finishTime: Long,
val timestamp: String = formatter.format(finishTime),
@@ -38,15 +40,19 @@ data class CompileStatisticsData(
)
enum class StatTag {
ABI_SNAPSHOT,
ARTIFACT_TRANSFORM,
INCREMENTAL,
NON_INCREMENTAL,
GRADLE_DEBUG,
KOTLIN_DEBUG,
CONFIGURATION_CACHE,
BUILD_CACHE,
enum class StatTag(val readableString: String) {
ABI_SNAPSHOT("ABI Snapshot"),
ARTIFACT_TRANSFORM("Classpath Snapshot"),
INCREMENTAL("Incremental compilation"),
NON_INCREMENTAL("Non incremental compilation"),
INCREMENTAL_AND_NON_INCREMENTAL("Incremental and Non incremental compilation"),
GRADLE_DEBUG("Gradle debug enabled"),
KOTLIN_DEBUG("Kotlin debug enabled"),
CONFIGURATION_CACHE("Configuration cache enabled"),
BUILD_CACHE("Build cache enabled"),
KOTLIN_1("Kotlin language version 1"),
KOTLIN_2("Kotlin language version 2"),
KOTLIN_1_AND_2("Kotlin language version 1 and 2"),
}
enum class BuildDataType {
@@ -74,7 +80,7 @@ data class BuildFinishStatisticsData(
val finishTime: Long,
val timestamp: String = formatter.format(finishTime),
val hostName: String? = "Unset",
val tags: List<String>,
val tags: List<StatTag>,
val gitBranch: String = "Unset"
)
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
internal interface UsesBuildMetricsService : Task {
@get:Internal
@@ -123,7 +124,8 @@ abstract class BuildMetricsService : BuildService<BuildServiceParameters.None>,
buildMetrics = buildMetrics,
didWork = result is TaskExecutionResult,
skipMessage = (result as? TaskSkippedResult)?.skipMessage,
icLogLines = taskExecutionResult?.icLogLines ?: emptyList()
icLogLines = taskExecutionResult?.icLogLines ?: emptyList(),
kotlinLanguageVersion = taskExecutionResult?.taskInfo?.kotlinLanguageVersion
)
)
if (result is TaskFailureResult) {
@@ -172,6 +174,7 @@ internal class TaskRecord(
override val didWork: Boolean,
override val skipMessage: String?,
override val icLogLines: List<String>,
val kotlinLanguageVersion: KotlinVersion?
) : BuildOperationRecord {
override val isFromKotlinPlugin: Boolean = classFqName.startsWith("org.jetbrains.kotlin")
}
@@ -54,7 +54,7 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
private val buildUuid = UUID.randomUUID().toString()
private var executorService: ExecutorService = Executors.newSingleThreadExecutor()
private val tags = LinkedHashSet<String>()
private val tags = LinkedHashSet<StatTag>()
private var customValues = 0 // doesn't need to be thread-safe
init {
@@ -201,13 +201,8 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
private fun addBuildScanReport(data: CompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) {
val elapsedTime = measureTimeMillis {
data.tags.forEach { tags.add(it) }
buildScan.buildScan?.also {
data.tags
.filter { !tags.contains(it) }
.forEach {
addBuildScanTag(buildScan, it)
}
if (customValues < customValuesLimit) {
readableString(data).forEach {
if (customValues < customValuesLimit) {
@@ -237,11 +232,6 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
customValues++
}
private fun addBuildScanTag(buildScan: BuildScanExtensionHolder, tag: String) {
buildScan.buildScan?.tag(tag)
tags.add(tag)
}
private fun readableString(data: CompileStatisticsData): List<String> {
val readableString = StringBuilder()
if (data.nonIncrementalAttributes.isEmpty()) {
@@ -255,6 +245,10 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
) { it.readableString }
}
data.kotlinLanguageVersion?.version?.also {
readableString.append("Kotlin language version: $it; ")
}
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) ->
@@ -296,6 +290,32 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
}
}
private fun addCollectedTags(buildScan: BuildScanExtensionHolder) {
replaceWithCombinedTag(
StatTag.KOTLIN_1,
StatTag.KOTLIN_2,
StatTag.KOTLIN_1_AND_2
)
replaceWithCombinedTag(
StatTag.INCREMENTAL,
StatTag.NON_INCREMENTAL,
StatTag.INCREMENTAL_AND_NON_INCREMENTAL
)
tags.forEach { buildScan.buildScan?.tag(it.readableString) }
}
private fun replaceWithCombinedTag(firstTag: StatTag, secondTag: StatTag, combinedTag: StatTag) {
val containsFirstTag = tags.remove(firstTag)
val containsSecondTag = tags.remove(secondTag)
when {
containsFirstTag && containsSecondTag -> tags.add(combinedTag)
containsFirstTag -> tags.add(firstTag)
containsSecondTag -> tags.add(secondTag)
}
}
companion object {
const val CUSTOM_VALUE_LENGTH_LIMIT = 100_000
@@ -342,19 +362,23 @@ abstract class BuildReportsService : BuildService<BuildReportsService.Parameters
//init gradle tags for build scan and http reports
it.parameters.additionalTags.value(setupTags(gradle))
}.also {
}.also { buildServiceProvider ->
if (reportingSettings.httpReportSettings != null) {
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it)
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(buildServiceProvider)
}
val buildScanExtension = project.rootProject.extensions.findByName("buildScan")
if (reportingSettings.buildScanReportSettings != null && buildScanExtension != null) {
it.get().initBuildScanTags(BuildScanExtensionHolder(buildScanExtension))
val buildScan = BuildScanExtensionHolder(buildScanExtension)
buildServiceProvider.get().initBuildScanTags(buildScan)
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider {
OperationCompletionListener { event ->
it.get().addBuildScanReport(event, BuildScanExtensionHolder(buildScanExtension))
buildServiceProvider.get().addBuildScanReport(event, buildScan)
}
})
buildScan.buildScan?.buildFinished {
buildServiceProvider.get().addCollectedTags(buildScan)
}
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.report
import org.jetbrains.kotlin.build.report.metrics.BuildMetrics
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.incremental.ChangedFiles
internal class TaskExecutionResult(
@@ -15,6 +16,7 @@ internal class TaskExecutionResult(
)
internal class TaskExecutionInfo(
val kotlinLanguageVersion: KotlinVersion? = null,
val changedFiles: ChangedFiles? = null,
val compilerArguments: Array<String> = emptyArray(),
val withArtifactTransform: Boolean? = false,
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import java.lang.management.ManagementFactory
import java.util.ArrayList
import java.util.concurrent.TimeUnit
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
private fun availableForStat(taskPath: String): Boolean {
@@ -75,10 +76,11 @@ internal fun prepareData(
projectName = projectName,
taskName = taskPath,
changes = changes,
tags = collectTags(taskExecutionResult, buildMetrics, additionalTags).map { it.name },
tags = collectTags(taskExecutionResult, buildMetrics, additionalTags),
nonIncrementalAttributes = buildAttributes,
hostName = BuildReportsService.hostName,
kotlinVersion = kotlinVersion,
kotlinLanguageVersion = taskExecutionResult?.taskInfo?.kotlinLanguageVersion,
buildUuid = uuid,
finishTime = System.currentTimeMillis(),
compilerArguments = taskExecutionResult?.taskInfo?.compilerArguments?.asList() ?: emptyList(),
@@ -156,7 +158,7 @@ private fun collectTags(
private fun collectTags(
taskExecutionResult: TaskExecutionResult?,
additionalTags: List<StatTag>,
): MutableList<StatTag>{
): MutableList<StatTag> {
val tags = ArrayList(additionalTags)
val taskInfo = taskExecutionResult?.taskInfo
@@ -166,10 +168,20 @@ private fun collectTags(
taskInfo?.withArtifactTransform?.ifTrue {
tags.add(StatTag.ARTIFACT_TRANSFORM)
}
taskInfo?.kotlinLanguageVersion?.also {
tags.add(getLanguageVersionTag(it))
}
val debugConfiguration = "-agentlib:"
if (ManagementFactory.getRuntimeMXBean().inputArguments.firstOrNull { it.startsWith(debugConfiguration) } != null) {
tags.add(StatTag.GRADLE_DEBUG)
}
return tags
}
private fun getLanguageVersionTag(languageVersion: KotlinVersion): StatTag {
return when {
languageVersion < KotlinVersion.KOTLIN_2_0 -> StatTag.KOTLIN_1
else -> StatTag.KOTLIN_2
}
}
@@ -24,16 +24,18 @@ import kotlin.math.sign
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
class ReportDataTest {
private val kotlinTaskPath = "testKotlin"
@Test
@Suppress("DEPRECATION")
fun testTags() {
TaskExecutionResults[kotlinTaskPath] = TaskExecutionResult(
buildMetrics = BuildMetrics(buildAttributes = BuildAttributes()),
taskInfo = TaskExecutionInfo(),
icLogLines = emptyList()
taskInfo = TaskExecutionInfo(kotlinLanguageVersion = KotlinVersion.KOTLIN_1_4),
icLogLines = emptyList(),
)
val buildOperationRecord =
taskRecord(BuildMetrics(buildAttributes = BuildAttributes().also { it.add(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND) }))
@@ -48,8 +50,9 @@ class ReportDataTest {
)
assertNotNull(statisticData)
assertTrue(statisticData.tags.contains(StatTag.KOTLIN_DEBUG.name))
assertTrue(statisticData.tags.contains(StatTag.NON_INCREMENTAL.name))
assertTrue(statisticData.tags.contains(StatTag.KOTLIN_DEBUG))
assertTrue(statisticData.tags.contains(StatTag.NON_INCREMENTAL))
assertTrue(statisticData.tags.contains(StatTag.KOTLIN_1))
}
private fun taskRecord(buildMetrics: BuildMetrics) = TaskRecord(
@@ -60,7 +63,8 @@ class ReportDataTest {
buildMetrics = buildMetrics,
didWork = true,
skipMessage = null,
icLogLines = emptyList()
icLogLines = emptyList(),
kotlinLanguageVersion = KotlinVersion.KOTLIN_1_8
)
@Test