From a8761e0850b5b0d6294951f75da5517f4c7bece7 Mon Sep 17 00:00:00 2001 From: Vladimir Sitnikov Date: Tue, 24 Jun 2025 11:10:20 +0300 Subject: [PATCH] feat: make gradle-extensions compatible with configuration cache --- ...rintGitHubActionsMarkersForFailingTasks.kt | 43 +++++++++------ .../vlsi/gradle/ProjectExtensionsPlugin.kt | 53 +++++++++++++++---- .../github/vlsi/gradle/ReportBuildFailures.kt | 13 +++-- .../github/vlsi/gradle/ThrowablePrinter.kt | 14 +++++ .../vlsi/gradle/test/dsl/PrintTestResults.kt | 5 +- 5 files changed, 94 insertions(+), 34 deletions(-) diff --git a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/PrintGitHubActionsMarkersForFailingTasks.kt b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/PrintGitHubActionsMarkersForFailingTasks.kt index 509065f1..4b039780 100644 --- a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/PrintGitHubActionsMarkersForFailingTasks.kt +++ b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/PrintGitHubActionsMarkersForFailingTasks.kt @@ -17,28 +17,41 @@ package com.github.vlsi.gradle import com.github.vlsi.gradle.github.GitHubActionsLogger -import org.gradle.api.Task -import org.gradle.api.execution.TaskExecutionListener -import org.gradle.api.tasks.TaskState +import com.github.vlsi.gradle.styledtext.StyledTextBuilder +import org.gradle.api.provider.Property +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.tooling.events.FinishEvent +import org.gradle.tooling.events.OperationCompletionListener +import org.gradle.tooling.events.task.TaskFailureResult +import org.gradle.tooling.events.task.TaskFinishEvent -object PrintGitHubActionsMarkersForFailingTasks : TaskExecutionListener { - override fun beforeExecute(task: Task) = Unit +abstract class PrintGitHubActionsMarkersForFailingTasksParameters: BuildServiceParameters { + abstract val fullTrace: Property +} - override fun afterExecute(task: Task, state: TaskState) { - state.failure?.let { throwable -> - val sb = task.project.createStyledBuilder().apply { - // GitHub "annotations" do not support coloring - enableStyle = false - } - val printer = task.project.createThrowablePrinter().apply { +abstract class PrintGitHubActionsMarkersForFailingTasks : BuildService, + OperationCompletionListener { + override fun onFinish(event: FinishEvent) { + if (event !is TaskFinishEvent) { + return + } + val result = event.result + if (result !is TaskFailureResult) { + return + } + result.failures.forEach { failure -> + // GitHub "annotations" do not support coloring + val sb = StyledTextBuilder(enableStyle = false) + val printer = createThrowablePrinter(fullTrace = parameters.fullTrace.get()).apply { indent = "" } - printer.print(throwable, sb) + printer.print(failure, sb) println( """ - ${GitHubActionsLogger.startGroup("${task.path} failure marker")} + ${GitHubActionsLogger.startGroup("${event.descriptor.taskPath} failure marker")} ${GitHubActionsLogger.error( - task.toString(), + event.descriptor.name.toString(), line = null, col = null, message = sb.toString() diff --git a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ProjectExtensionsPlugin.kt b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ProjectExtensionsPlugin.kt index 463322f8..2ea3fc7b 100644 --- a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ProjectExtensionsPlugin.kt +++ b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ProjectExtensionsPlugin.kt @@ -18,19 +18,57 @@ package com.github.vlsi.gradle import com.github.vlsi.gradle.github.GitHubActionsLogger import com.github.vlsi.gradle.properties.dsl.props -import com.github.vlsi.gradle.styledtext.StyledTextBuilder import com.github.vlsi.gradle.test.dsl.printTestResults import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.configuration.BuildFeatures +import org.gradle.api.invocation.Gradle import org.gradle.api.tasks.testing.AbstractTestTask import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.build.event.BuildEventsListenerRegistry +import org.gradle.kotlin.dsl.registerIfAbsent +import org.gradle.kotlin.dsl.support.serviceOf import org.gradle.kotlin.dsl.withType +import org.gradle.util.GradleVersion class ProjectExtensionsPlugin : Plugin { + private val Gradle.configurationCacheEnabled: Boolean + get() { + if (GradleVersion.current() >= GradleVersion.version("8.5")) { + return serviceOf().configurationCache.active.get() + } + return try { + startParameter.javaClass.getMethod("isConfigurationCache").invoke(startParameter) as Boolean + } catch (e: Exception) { + false + } + } + override fun apply(target: Project) { - target.gradle.addBuildListener(ReportBuildFailures) + val enableStyle = !target.props.bool( + "nocolor", + default = System.getProperty("os.name").contains("windows", ignoreCase = true) + ) + val fullTrace = target.props.bool("fulltrace") + if (!target.gradle.configurationCacheEnabled) { + target.gradle.addBuildListener( + ReportBuildFailures( + enableStyle = enableStyle, + fullTrace = fullTrace + ) + ) + } if (GitHubActionsLogger.isEnabled) { - target.gradle.addListener(PrintGitHubActionsMarkersForFailingTasks) + val gitHubMarkers = target.gradle.sharedServices.registerIfAbsent( + "PrintGitHubActionsMarkersForFailingTasks", + PrintGitHubActionsMarkersForFailingTasks::class + ) { + parameters { + this.fullTrace.set(fullTrace) + } + } + target.gradle.serviceOf() + .onTaskCompletion(gitHubMarkers) } target.tasks.withType().configureEach { testLogging { @@ -45,13 +83,8 @@ class ProjectExtensionsPlugin : Plugin { } } -internal fun Project.createStyledBuilder() = StyledTextBuilder().apply { - enableStyle = !project.props.bool("nocolor", - default = System.getProperty("os.name").contains("windows", ignoreCase = true)) -} - -internal fun Project.createThrowablePrinter() = ThrowablePrinter().apply { - if (project.props.bool("fulltrace")) { +internal fun createThrowablePrinter(fullTrace: Boolean) = ThrowablePrinter().apply { + if (fullTrace) { classExcludes.clear() hideThrowables.clear() hideStacktraces.clear() diff --git a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ReportBuildFailures.kt b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ReportBuildFailures.kt index 3500065d..bb4c3454 100644 --- a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ReportBuildFailures.kt +++ b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ReportBuildFailures.kt @@ -22,16 +22,15 @@ import com.github.vlsi.gradle.styledtext.StyledTextBuilder import org.gradle.BuildAdapter import org.gradle.BuildResult -object ReportBuildFailures : BuildAdapter() { +class ReportBuildFailures( + val enableStyle: Boolean, + val fullTrace: Boolean, +) : BuildAdapter() { override fun buildFinished(result: BuildResult) { val failure = result.failure ?: return val gradle = result.gradle - val (sb, throwablePrinter) = if (gradle == null) { - StyledTextBuilder() to ThrowablePrinter() - } else { - gradle.rootProject.createStyledBuilder() to - gradle.rootProject.createThrowablePrinter() - } + val sb = StyledTextBuilder(enableStyle = enableStyle) + val throwablePrinter = createThrowablePrinter(fullTrace = fullTrace) throwablePrinter.indent = " " sb.appendPlatformLine() sb.append(result.action).append(" ") diff --git a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ThrowablePrinter.kt b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ThrowablePrinter.kt index 80acf445..aacace94 100644 --- a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ThrowablePrinter.kt +++ b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/ThrowablePrinter.kt @@ -29,6 +29,7 @@ import org.gradle.internal.UncheckedException import org.gradle.internal.exceptions.LocationAwareException import org.gradle.internal.exceptions.MultiCauseException import org.gradle.internal.serialize.PlaceholderException +import org.gradle.tooling.Failure import java.sql.SQLException import java.util.* @@ -170,6 +171,19 @@ class ThrowablePrinter { val causedBy: List? ) + fun print(failure: Failure, out: Appendable, baseIndent: String = indent): Appendable { + out.append(baseIndent).append(failure.message) + if (failure.causes.isEmpty()) { + return out + } + for (cause in failure.causes) { + out.appendPlatformLine().append(baseIndent).append("Caused by:") + out.appendPlatformLine() + print(cause, out, "$baseIndent ") + } + return out + } + fun print(root: Throwable, out: Appendable, baseIndent: String = indent): Appendable { val dejaVu = Collections.newSetFromMap(IdentityHashMap()) diff --git a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/test/dsl/PrintTestResults.kt b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/test/dsl/PrintTestResults.kt index 59775818..6f8e014d 100644 --- a/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/test/dsl/PrintTestResults.kt +++ b/plugins/gradle-extensions-plugin/src/main/kotlin/com/github/vlsi/gradle/test/dsl/PrintTestResults.kt @@ -64,6 +64,7 @@ fun AbstractTestTask.printTestResults( default = System.getProperty("os.name").contains("windows", ignoreCase = true)), showStacktrace: Boolean = true ) { + val fullTrace = project.props.bool("fulltrace") // https://github.com/junit-team/junit5/issues/2041 // Gradle does not print parameterized test names yet :( // Hopefully it will be fixed in Gradle 6.1 @@ -102,7 +103,7 @@ fun AbstractTestTask.printTestResults( .withStyle(if (durationMillis >= slowTestLogThreshold) Style.BOLD else UNCHANGED) sb.append(resultType).append(" ").append(duration) sb.append(", ").appendTestName(displayName) - val throwablePrinter = project.createThrowablePrinter().apply { + val throwablePrinter = createThrowablePrinter(fullTrace = fullTrace).apply { indent = " " test.className?.let { className -> frameStyles += { @@ -169,7 +170,7 @@ fun AbstractTestTask.printTestResults( sb.appendTestName(displayName) } if (showStacktrace && result.exceptions.isNotEmpty()) { - val throwablePrinter = project.createThrowablePrinter().apply { + val throwablePrinter = createThrowablePrinter(fullTrace = fullTrace).apply { indent = " " } result.exceptions.forEach {