KT-58662 Fix build reports for Gradle 8.1 with Configuration Cache

(cherry picked from commit af05f4c2010b69ebf13956cc9c97dfd4b57f15f0)
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 060e6e6..81ebf71 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 @@
         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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     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 @@
     }
 
     @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 @@
     }
 
     @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 57d1a93..e04d1ac 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 @@
 
     @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 @@
 
     @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 7bcaf47..cc937c0 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 @@
     }
 
     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 3348468..8c3aaf9 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.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 @@
     val buildMetricsService: Property<BuildMetricsService?>
 }
 
-abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters>, AutoCloseable {
+abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters>, AutoCloseable, OperationCompletionListener {
 
     //Part of BuildReportService
     interface Parameters : BuildServiceParameters {
@@ -165,6 +166,14 @@
         buildReportService.close(buildOperationRecords, failureMessages.toList(), parameters.toBuildReportParameters())
     }
 
+    override fun onFinish(event: FinishEvent?) {
+        if (event is TaskFinishEvent) {
+            val buildOperation = updateBuildOperationRecord(event)
+            val buildParameters = parameters.toBuildReportParameters()
+            buildReportService.onFinish(event, buildOperation, buildParameters)
+        }
+    }
+
     companion object {
         private val serviceClass = BuildMetricsService::class.java
         private val serviceName = "${serviceClass.name}_${serviceClass.classLoader.hashCode()}"
@@ -221,35 +230,46 @@
 
         }
 
-        private fun subscribeForTaskEvents(project: Project, buildMetricService: Provider<BuildMetricsService>) {
+        private fun subscribeForTaskEvents(project: Project, buildMetricServiceProvider: Provider<BuildMetricsService>) {
             // 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
 
-            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 (!gradle80withBuildScanReport) {
+                BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(buildMetricServiceProvider)
+            }
+
             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 @@
         }
     }
 
-    internal fun addCollectedTagsToBuildScan(buildScan: BuildScanExtensionHolder?) {
+    internal fun addBuildScanReport(buildScan: BuildScanExtensionHolder?) {
         if (buildScan == null) return
+        buildReportService.initBuildScanTags(buildScan, parameters.label.orNull)
+        buildReportService.addBuildScanReport(buildOperationRecords, parameters.toBuildReportParameters(), buildScan)
+        parameters.buildConfigurationTags.orNull?.forEach { buildScan.buildScan.tag(it.readableString) }
         buildReportService.addCollectedTags(buildScan)
     }
-
 }
 
 internal class TaskRecord(
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 f4a6eda..8fa5a39 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
@@ -68,21 +68,7 @@
                 it.buildReportDir,
                 parameters.projectName,
                 it.includeMetricsInReport,
-                buildOperationRecords.mapNotNull {
-                    prepareData(
-                        taskResult = null,
-                        it.path,
-                        it.startTimeMs,
-                        it.totalTimeMs + it.startTimeMs,
-                        parameters.projectName,
-                        buildUuid,
-                        parameters.label,
-                        parameters.kotlinVersion,
-                        it,
-                        onlyKotlinTask = false,
-                        parameters.additionalTags
-                    )
-                },
+                transformOperationRecordsToCompileStatisticsData(buildOperationRecords, parameters, onlyKotlinTask = false),
                 parameters.startParameters,
                 failureMessages.filter { it.isNotEmpty() },
                 loggerAdapter
@@ -101,11 +87,32 @@
         executorService.shutdown()
     }
 
+    private fun transformOperationRecordsToCompileStatisticsData(
+        buildOperationRecords: Collection<BuildOperationRecord>,
+        parameters: BuildReportParameters,
+        onlyKotlinTask: Boolean,
+        metricsToShow: Set<String>? = 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 @@
 
     }
 
-    private fun addBuildScanReport(
+    internal fun addBuildScanReport(
         event: TaskFinishEvent,
         buildOperationRecord: BuildOperationRecord,
         parameters: BuildReportParameters,
@@ -201,6 +208,28 @@
         }
     }
 
+    internal fun addBuildScanReport(
+        buildOperationRecords: Collection<BuildOperationRecord>,
+        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)