diff --git a/libraries/tools/kotlin-gradle-statistics/ReadMe.md b/libraries/tools/kotlin-gradle-statistics/ReadMe.md new file mode 100644 index 00000000000..55e0ba9837a --- /dev/null +++ b/libraries/tools/kotlin-gradle-statistics/ReadMe.md @@ -0,0 +1,9 @@ +# Kotlin gradle statistic + +### Changes +After any change in this module, please increase VERSION in of one of the enums: +* [BooleanMetrics.kt](src%2Fmain%2Fkotlin%2Forg%2Fjetbrains%2Fkotlin%2Fstatistics%2Fmetrics%2FBooleanMetrics.kt) +* [NumericalMetrics.kt](src%2Fmain%2Fkotlin%2Forg%2Fjetbrains%2Fkotlin%2Fstatistics%2Fmetrics%2FNumericalMetrics.kt) +* [StringMetrics.kt](src%2Fmain%2Fkotlin%2Forg%2Fjetbrains%2Fkotlin%2Fstatistics%2Fmetrics%2FStringMetrics.kt) + +The increasing of this value is necessary for auto increasing version in [KotlinGradleFUSCollector.kt](https://jetbrains.team/p/ij/repositories/intellij/files/community/plugins/kotlin/gradle/gradle/src/org/jetbrains/kotlin/idea/gradle/statistics/KotlinGradleFUSCollector.kt) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/BooleanMetrics.kt b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/BooleanMetrics.kt index 7140a99489b..467d0810e76 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/BooleanMetrics.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/BooleanMetrics.kt @@ -68,5 +68,9 @@ enum class BooleanMetrics(val type: BooleanOverridePolicy, val anonymization: Bo TESTS_EXECUTED(OVERRIDE, SAFE), MAVEN_PUBLISH_EXECUTED(OVERRIDE, SAFE), BUILD_FAILED(OVERRIDE, SAFE), - KOTLIN_COMPILATION_FAILED(OR, SAFE) + KOTLIN_COMPILATION_FAILED(OR, SAFE); + + companion object { + const val VERSION = 1 + } } diff --git a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt index a9ce40e0577..b485d3e2afe 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/NumericalMetrics.kt @@ -62,5 +62,9 @@ enum class NumericalMetrics(val type: NumberOverridePolicy, val anonymization: N // User scenarios // this value is not reported, only time intervals from the previous build are used - BUILD_FINISH_TIME(OVERRIDE, SAFE) + BUILD_FINISH_TIME(OVERRIDE, SAFE); + + companion object { + const val VERSION = 1 + } } diff --git a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt index af5197f3539..2a65d25b77c 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/metrics/StringMetrics.kt @@ -88,5 +88,9 @@ enum class StringMetrics(val type: StringOverridePolicy, val anonymization: Stri USE_OLD_BACKEND(CONCAT, AllowedListAnonymizer(listOf("true", "false"))), USE_FIR(CONCAT, AllowedListAnonymizer(listOf("true", "false"))), - JS_PROPERTY_LAZY_INITIALIZATION(CONCAT, AllowedListAnonymizer(listOf("true", "false"))), + JS_PROPERTY_LAZY_INITIALIZATION(CONCAT, AllowedListAnonymizer(listOf("true", "false"))); + + companion object { + const val VERSION = 1 + } } diff --git a/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/MetricPolicyTest.kt b/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/MetricPolicyTest.kt similarity index 97% rename from libraries/tools/kotlin-gradle-statistics/src/test/kotlin/MetricPolicyTest.kt rename to libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/MetricPolicyTest.kt index 9e0e2a1c927..081115fe3f2 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/MetricPolicyTest.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/MetricPolicyTest.kt @@ -1,7 +1,10 @@ /* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 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.statistics + import org.jetbrains.kotlin.statistics.fileloggers.MetricsContainer import org.jetbrains.kotlin.statistics.metrics.ConcatMetricContainer import org.jetbrains.kotlin.statistics.metrics.NumberAnonymizationPolicy.RANDOM_10_PERCENT diff --git a/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/ModuleChangesCatchingTest.kt b/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/ModuleChangesCatchingTest.kt new file mode 100644 index 00000000000..3244b3b8507 --- /dev/null +++ b/libraries/tools/kotlin-gradle-statistics/src/test/kotlin/org/jetbrains/kotlin/statistics/ModuleChangesCatchingTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2010-2023 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.statistics + +import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics +import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics +import org.jetbrains.kotlin.statistics.metrics.StringMetrics +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.security.MessageDigest +import kotlin.test.Test +import kotlin.test.assertEquals + +private const val SOURCE_CODE_RELATIVE_PATH = + "libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics" +private const val BOOLEAN_METRICS_RELATIVE_PATH = "$SOURCE_CODE_RELATIVE_PATH/metrics/BooleanMetrics.kt" +private const val STRING_METRICS_RELATIVE_PATH = "$SOURCE_CODE_RELATIVE_PATH/metrics/StringMetrics.kt" +private const val NUMERICAL_METRICS_RELATIVE_PATH = "$SOURCE_CODE_RELATIVE_PATH/metrics/NumericalMetrics.kt" + +private val STRING_METRICS_EXPECTED_VERSION_AND_HASH = Pair(1, "90347332db2ce54b51e7daa64595371e") +private val BOOLEAN_METRICS_EXPECTED_VERSION_AND_HASH = Pair(1, "b1d0eb433e0df5544a33d4c944e66e45") +private val NUMERICAL_METRICS_EXPECTED_VERSION_AND_HASH = Pair(1, "8fda0e0845f12f40346a9e4c5cae5989") +private val SOURCE_FOLDER_EXPECTED_VERSION_AND_HASH = + Pair( + STRING_METRICS_EXPECTED_VERSION_AND_HASH.first + + BOOLEAN_METRICS_EXPECTED_VERSION_AND_HASH.first + + NUMERICAL_METRICS_EXPECTED_VERSION_AND_HASH.first, + "31c6533f2b6d2bec302cc44172892e5f" + ) +private const val HASH_ALG = "MD5" + +/** + * This class searches for all the changes in kotlin-gradle-statistics + * and if there is such changes then it requires to upgrade version of connected metrics. + */ +class ModuleChangesCatchingTest { + + /** + * Test checks for that the version of [StringMetrics] was increased after changes in this file + */ + @Test + fun testChecksCorrectChangingStringMetricsVersion() { + val actualStringMetricsVersionAndHash = + Pair(StringMetrics.VERSION, calculateFileChecksum(STRING_METRICS_RELATIVE_PATH)) + assertEquals( + STRING_METRICS_EXPECTED_VERSION_AND_HASH, actualStringMetricsVersionAndHash, + "Hash of ${StringMetrics::class.qualifiedName} has been changed, please increase VERSION value. " + + "Also you need to update hash and version in this test class." + ) + } + + /** + * Test checks for that the version of [BooleanMetrics] was increased after changes in this file + */ + @Test + fun testChecksCorrectChangingBooleanMetricsVersion() { + val actualBooleanMetricsVersionAndHash = + Pair(BooleanMetrics.VERSION, calculateFileChecksum(BOOLEAN_METRICS_RELATIVE_PATH)) + assertEquals( + BOOLEAN_METRICS_EXPECTED_VERSION_AND_HASH, actualBooleanMetricsVersionAndHash, + "Hash of ${BooleanMetrics::class.qualifiedName} has been changed, please increase VERSION value. " + + "Also you need to update hash and version in this test class." + ) + } + + /** + * Test checks for that the version of [NumericalMetrics] was increased after changes in this file + */ + @Test + fun testChecksCorrectChangingNumericalMetricsVersion() { + val actualNumericalMetricsVersionAndHash = + Pair(NumericalMetrics.VERSION, calculateFileChecksum(NUMERICAL_METRICS_RELATIVE_PATH)) + assertEquals( + NUMERICAL_METRICS_EXPECTED_VERSION_AND_HASH, actualNumericalMetricsVersionAndHash, + "Hash of ${NumericalMetrics::class.qualifiedName} has been changed, please increase VERSION value. " + + "Also you need to update hash and version in this test class." + ) + } + + @Test + fun testChecksTotalFilesChecksum() { + val pathToExclude = + setOf( + Paths.get(STRING_METRICS_RELATIVE_PATH).toAbsolutePath().toString(), + Paths.get(BOOLEAN_METRICS_RELATIVE_PATH).toAbsolutePath().toString(), + Paths.get(NUMERICAL_METRICS_RELATIVE_PATH).toAbsolutePath().toString() + ) + val actualSourceFolderVersionAndHash = + Pair( + NumericalMetrics.VERSION + StringMetrics.VERSION + BooleanMetrics.VERSION, + calculateDirectoryCheckSum(SOURCE_CODE_RELATIVE_PATH, pathToExclude) + ) + assertEquals( + SOURCE_FOLDER_EXPECTED_VERSION_AND_HASH, actualSourceFolderVersionAndHash, + "Hash of $SOURCE_CODE_RELATIVE_PATH has been changed, please increase VERSION value in one of the enums StringMetrics, NumericalMetrics, BooleanMetrics." + + "Also you need to update hash and version in this test class." + ) + } + + private fun calculateFileChecksum(filePathStr: String): String { + return calculateMD5HashForFileContent(Paths.get(filePathStr)).convertToHexString() + } + + private fun calculateDirectoryCheckSum( + dirPathStr: String, + pathsToExclude: Set = setOf(), + ): String { + return File(dirPathStr) + .walk() + .filter { file -> file.isFile } + .filter { file -> !pathsToExclude.contains(file.absolutePath) } + .map { file -> calculateMD5HashForFileContent(file.toPath()) } + .fold(byteArrayOf()) { acc, fileHash -> acc + fileHash } + .getMD5Hash() + .convertToHexString() + } + + private fun calculateMD5HashForFileContent(path: Path): ByteArray { + return Files.readAllBytes(path).getMD5Hash() + } + + private fun ByteArray.getMD5Hash(): ByteArray { + return MessageDigest.getInstance(HASH_ALG).digest(this) + } + + private fun ByteArray.convertToHexString(): String { + return this.joinToString("") { "%02x".format(it) } + } + +} \ No newline at end of file