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

This commit is contained in:
Nataliya.Valtman
2023-05-22 12:25:33 +02:00
committed by Space Team
parent f2f979134d
commit af05f4c201
5 changed files with 183 additions and 42 deletions
@@ -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) {
@@ -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) {
@@ -54,7 +54,7 @@ internal class BuildScanFlowAction : FlowAction<BuildScanFlowAction.Parameters>
}
override fun execute(parameters: Parameters) {
parameters.buildMetricService.orNull?.addCollectedTagsToBuildScan(parameters.buildScanExtensionHolder.orNull)
parameters.buildMetricService.orNull?.addBuildScanReport(parameters.buildScanExtensionHolder.orNull)
}
}
@@ -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<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 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
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 @@ abstract class BuildMetricsService : BuildService<BuildMetricsService.Parameters
}
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
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<BuildMetricsService.Parameters
}
}
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(
@@ -68,21 +68,7 @@ class BuildReportsService {
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 @@ class BuildReportsService {
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 @@ 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<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)