From af05f4c2010b69ebf13956cc9c97dfd4b57f15f0 Mon Sep 17 00:00:00 2001 From: "Nataliya.Valtman" Date: Mon, 22 May 2023 12:25:33 +0200 Subject: [PATCH] KT-58662 Fix build reports for Gradle 8.1 with Configuration Cache --- .../jetbrains/kotlin/gradle/BuildReportsIT.kt | 80 +++++++++++++++++++ .../kotlin/gradle/ConfigurationCacheIT.kt | 10 +++ .../plugin/StatisticsBuildFlowManager.kt | 2 +- .../gradle/report/BuildMetricsService.kt | 68 ++++++++++------ .../gradle/report/BuildReportsService.kt | 65 ++++++++++----- 5 files changed, 183 insertions(+), 42 deletions(-) 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 060e6e619ed..81ebf71a0e4 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 @@ -29,6 +29,11 @@ class BuildReportsIT : KGPBaseTest() { get() = projectPath.getSingleFileInDir("build/reports/kotlin-build") @DisplayName("Build report is created") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildReportSmokeTest(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -43,6 +48,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("Build report output property accepts only certain values") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildReportOutputProperty(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -53,24 +63,44 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("Build metrics produces valid report") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildMetricsSmokeTest(gradleVersion: GradleVersion) { testBuildReportInFile("simpleProject", "assemble", gradleVersion) } @DisplayName("Build metrics produces valid report for mpp-jvm") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildMetricsForMppJvm(gradleVersion: GradleVersion) { testBuildReportInFile("mppJvmWithJava", "assemble", gradleVersion) } @DisplayName("Build metrics produces valid report for mpp-js") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildMetricsForMppJs(gradleVersion: GradleVersion) { testBuildReportInFile("kotlin-js-package-module-name", "assemble", gradleVersion) } @DisplayName("Build metrics produces valid report for JS project") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildMetricsForJsProject(gradleVersion: GradleVersion) { testBuildReportInFile("kotlin-js-plugin-project", "compileKotlinJs", gradleVersion, @@ -119,6 +149,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("Compiler build metrics report is produced") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testCompilerBuildMetricsSmokeTest(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -135,6 +170,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("with no kotlin task executed") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testFileReportWithoutKotlinTask(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -149,6 +189,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("validation") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testSingleBuildMetricsFileValidation(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -161,6 +206,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("deprecated property") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testDeprecatedAndNewSingleBuildMetricsFile(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -176,6 +226,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("smoke") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testSingleBuildMetricsFileSmoke(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -195,6 +250,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("custom value limit") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testCustomValueLimitForBuildScan(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)) { @@ -210,6 +270,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("build scan listener lazy initialisation") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildScanListenerLazyInitialisation(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion, buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)) { @@ -226,6 +291,11 @@ class BuildReportsIT : KGPBaseTest() { private val kotlinErrorPath = ".gradle/kotlin/errors" @DisplayName("Error file is created") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testErrorsFileSmokeTest(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -265,6 +335,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("Error file should not contain compilation exceptions") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testErrorsFileWithCompilationError(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { @@ -280,6 +355,11 @@ class BuildReportsIT : KGPBaseTest() { } @DisplayName("build scan metrics validation") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildScanMetricsValidation(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { 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 57d1a935996..e04d1acfacb 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 @@ -232,6 +232,11 @@ class ConfigurationCacheIT : AbstractConfigurationCacheIT() { @JvmGradlePluginTests @DisplayName("with build report") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildReportSmokeTestForConfigurationCache(gradleVersion: GradleVersion) { project( @@ -251,6 +256,11 @@ class ConfigurationCacheIT : AbstractConfigurationCacheIT() { @JvmGradlePluginTests @DisplayName("with build scan report") + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6], //build scan reports doesn't work properly for Gradle 8.0 + maxVersion = TestVersions.Gradle.G_8_1 + ) @GradleTest fun testBuildScanReportSmokeTestForConfigurationCache(gradleVersion: GradleVersion) { project("simpleProject", gradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt index 7bcaf476786..cc937c0841e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt @@ -54,7 +54,7 @@ internal class BuildScanFlowAction : FlowAction } override fun execute(parameters: Parameters) { - parameters.buildMetricService.orNull?.addCollectedTagsToBuildScan(parameters.buildScanExtensionHolder.orNull) + parameters.buildMetricService.orNull?.addBuildScanReport(parameters.buildScanExtensionHolder.orNull) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt index 3348468ae5c..8c3aaf909d3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt @@ -17,6 +17,7 @@ import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters import org.gradle.api.tasks.Internal import org.gradle.tooling.events.FailureResult +import org.gradle.tooling.events.FinishEvent import org.gradle.tooling.events.OperationCompletionListener import org.gradle.tooling.events.task.TaskExecutionResult import org.gradle.tooling.events.task.TaskFailureResult @@ -52,7 +53,7 @@ internal interface UsesBuildMetricsService : Task { val buildMetricsService: Property } -abstract class BuildMetricsService : BuildService, AutoCloseable { +abstract class BuildMetricsService : BuildService, AutoCloseable, OperationCompletionListener { //Part of BuildReportService interface Parameters : BuildServiceParameters { @@ -165,6 +166,14 @@ abstract class BuildMetricsService : BuildService) { + private fun subscribeForTaskEvents(project: Project, buildMetricServiceProvider: Provider) { // BuildScanExtension cant be parameter nor BuildService's field val buildScanExtension = project.rootProject.extensions.findByName("buildScan") val buildScan = buildScanExtension?.let { BuildScanExtensionHolder(it) } + val buildMetricService = buildMetricServiceProvider.get() + val buildScanReportSettings = buildMetricService.parameters.reportingSettings.orNull?.buildScanReportSettings + val gradle80withBuildScanReport = + GradleVersion.current().baseVersion == GradleVersion.version("8.0") && buildScanReportSettings != null && buildScan != null + + if (!gradle80withBuildScanReport) { + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(buildMetricServiceProvider) + } - val buildScanReportSettings = buildMetricService.get().parameters.reportingSettings.orNull?.buildScanReportSettings - BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider { - OperationCompletionListener { event -> - if (event is TaskFinishEvent) { - val buildOperation = buildMetricService.get().updateBuildOperationRecord(event) - val buildParameters = buildMetricService.get().parameters.toBuildReportParameters() - val buildReportService = buildMetricService.map { it.buildReportService } - buildReportService.get().onFinish(event, buildOperation, buildParameters, buildScan) - } - } - }) if (buildScanReportSettings != null) { - buildScan?.also { - buildMetricService.map { it.buildReportService }.get().initBuildScanTags( - it, buildMetricService.get().parameters.label.orNull - ) - if (GradleVersion.current().baseVersion < GradleVersion.version("8.0")) { - it.buildScan.buildFinished { - buildMetricService.map { it.addCollectedTagsToBuildScan(buildScan) } + buildScan?.also { buildScanHolder -> + when { + GradleVersion.current().baseVersion < GradleVersion.version("8.0") -> { + buildScanHolder.buildScan.buildFinished { + buildMetricServiceProvider.map {it.addBuildScanReport(buildScan)}.get() + } } + GradleVersion.current().baseVersion < GradleVersion.version("8.1") -> { + buildMetricService.buildReportService.initBuildScanTags(buildScan, buildMetricService.parameters.label.orNull) + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider { + OperationCompletionListener { event -> + if (event is TaskFinishEvent) { + val buildOperation = buildMetricService.updateBuildOperationRecord(event) + val buildParameters = buildMetricService.parameters.toBuildReportParameters() + val buildReportService = buildMetricServiceProvider.map { it.buildReportService }.get() + buildReportService.addBuildScanReport(event, buildOperation, buildParameters, buildScanHolder) + buildReportService.onFinish(event, buildOperation, buildParameters) + } + } + + }) + } + else -> {}//do nothing, BuildScanFlowAction is used } } } - } fun registerIfAbsent(project: Project) = registerIfAbsentImpl(project)?.also { serviceProvider -> @@ -276,11 +296,13 @@ abstract class BuildMetricsService : BuildService, + parameters: BuildReportParameters, + onlyKotlinTask: Boolean, + metricsToShow: Set? = null + ) = buildOperationRecords.mapNotNull { + prepareData( + taskResult = null, + it.path, + it.startTimeMs, + it.totalTimeMs + it.startTimeMs, + parameters.projectName, + buildUuid, + parameters.label, + parameters.kotlinVersion, + it, + onlyKotlinTask = onlyKotlinTask, + parameters.additionalTags, + metricsToShow = metricsToShow + ) + } + fun onFinish( event: TaskFinishEvent, buildOperation: BuildOperationRecord, - parameters: BuildReportParameters, buildScan: BuildScanExtensionHolder? + parameters: BuildReportParameters ) { - buildScan?.also { addBuildScanReport(event, buildOperation, parameters, it) } addHttpReport(event, buildOperation, parameters) } @@ -177,7 +184,7 @@ class BuildReportsService { } - private fun addBuildScanReport( + internal fun addBuildScanReport( event: TaskFinishEvent, buildOperationRecord: BuildOperationRecord, parameters: BuildReportParameters, @@ -201,6 +208,28 @@ class BuildReportsService { } } + internal fun addBuildScanReport( + buildOperationRecords: Collection, + parameters: BuildReportParameters, + buildScanExtension: BuildScanExtensionHolder + ) { + val buildScanSettings = parameters.reportingSettings.buildScanReportSettings ?: return + + val (collectDataDuration, compileStatData) = measureTimeMillisWithResult { + transformOperationRecordsToCompileStatisticsData( + buildOperationRecords, + parameters, + onlyKotlinTask = true, + metricsToShow = buildScanSettings.metrics + ) + } + log.debug("Collect data takes $collectDataDuration: $compileStatData") + + compileStatData.forEach { + addBuildScanReport(it, buildScanSettings.customValueLimit, buildScanExtension) + } + } + private fun addBuildScanReport(data: CompileStatisticsData, customValuesLimit: Int, buildScan: BuildScanExtensionHolder) { val elapsedTime = measureTimeMillis { tags.addAll(data.tags)