Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2019 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.github.vlsi.gradle

import org.gradle.api.flow.BuildWorkResult
import org.gradle.api.flow.FlowAction
import org.gradle.api.flow.FlowParameters
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input

interface BuildFailurePrintFlowParameters: FlowParameters {
@get:Input
val enableStyle: Property<Boolean>
@get:Input
val fullTrace: Property<Boolean>
@get:Input
val buildWorkResult: Property<BuildWorkResult>
}

abstract class BuildFailurePrintFlowAction: FlowAction<BuildFailurePrintFlowParameters> {
override fun execute(parameters: BuildFailurePrintFlowParameters) {
val buildWorkResult = parameters.buildWorkResult.get()
buildWorkResult.failure.ifPresent { failure ->
printBuildFailures(
failure,
"Build",
enableStyle = parameters.enableStyle.get(),
fullTrace = parameters.fullTrace.get()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2019 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.github.vlsi.gradle

import org.gradle.api.services.BuildService
import org.gradle.api.services.BuildServiceParameters

interface BuildFailurePrintServiceParameters: BuildServiceParameters {
}

abstract class BuildFailurePrintService: BuildService<BuildFailurePrintServiceParameters> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2019 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.github.vlsi.gradle

import org.gradle.api.flow.FlowProviders
import org.gradle.api.flow.FlowScope
import javax.inject.Inject

interface FlowScopedServices {
@get:Inject
val flowScope: FlowScope
@get:Inject
val flowProviders: FlowProviders
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ 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.always
import org.gradle.kotlin.dsl.newInstance
import org.gradle.kotlin.dsl.registerIfAbsent
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.kotlin.dsl.withType
Expand All @@ -50,16 +52,23 @@ class ProjectExtensionsPlugin : Plugin<Project> {
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
)
val buildServiceId = "BuildFailurePrintService.sharedService"
val sharedServices = target.gradle.sharedServices
if (sharedServices.registrations.findByName(buildServiceId) == null) {
sharedServices.registerIfAbsent(
buildServiceId,
BuildFailurePrintService::class,
)
if (GradleVersion.current() >= GradleVersion.version("8.1")) {
reportBuildFailure(target, enableStyle, fullTrace)
} else if (!target.gradle.configurationCacheEnabled) {
target.gradle.addBuildListener(
ReportBuildFailures(enableStyle, fullTrace)
)
}
}
if (GitHubActionsLogger.isEnabled) {
val gitHubMarkers = target.gradle.sharedServices.registerIfAbsent(
val gitHubMarkers = sharedServices.registerIfAbsent(
"PrintGitHubActionsMarkersForFailingTasks",
PrintGitHubActionsMarkersForFailingTasks::class
) {
Expand All @@ -81,6 +90,17 @@ class ProjectExtensionsPlugin : Plugin<Project> {
printTestResults()
}
}

private fun reportBuildFailure(target: Project, enableStyle: Boolean, fullTrace: Boolean) {
val flowScopeServices = target.objects.newInstance<FlowScopedServices>()
flowScopeServices.flowScope.always(BuildFailurePrintFlowAction::class) {
parameters {
this.enableStyle.set(enableStyle)
this.fullTrace.set(fullTrace)
this.buildWorkResult.set(flowScopeServices.flowProviders.buildWorkResult)
}
}
}
}

internal fun createThrowablePrinter(fullTrace: Boolean) = ThrowablePrinter().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,46 @@ import com.github.vlsi.gradle.styledtext.Style
import com.github.vlsi.gradle.styledtext.StyledTextBuilder
import org.gradle.BuildAdapter
import org.gradle.BuildResult
import java.util.concurrent.atomic.AtomicBoolean

class ReportBuildFailures(
val enableStyle: Boolean,
val fullTrace: Boolean,
) : BuildAdapter() {
private val enableStyle: Boolean,
private val fullTrace: Boolean
): BuildAdapter() {
companion object {
private val buildCompleted = AtomicBoolean()
}
override fun buildFinished(result: BuildResult) {
val failure = result.failure ?: return
val gradle = result.gradle
val sb = StyledTextBuilder(enableStyle = enableStyle)
val throwablePrinter = createThrowablePrinter(fullTrace = fullTrace)
throwablePrinter.indent = " "
sb.appendPlatformLine()
sb.append(result.action).append(" ")
sb.withStyle(Style.BOLD) {
append(gradle?.rootProject?.name ?: "unknown rootProject")
sb.append(" ")
sb.withStyle(
StandardColor.RED.foreground) {
append("FAILURE")
}
if (!buildCompleted.compareAndSet(false, true)) {
return
}
// Sometimes the message interferes with Gradle's progress bar.
// So we print extra spaces so the garbage after "reason" is wiped out.
sb.appendPlatformLine(" reason: ")
throwablePrinter.print(failure, sb)
if (throwablePrinter.interestingCases > 0 || throwablePrinter.classExcludes.isEmpty()) {
println(sb.toString())
printBuildFailures(
result.failure ?: return,
action = result.action,
enableStyle = enableStyle,
fullTrace = fullTrace
)
}
}

fun printBuildFailures(failure: Throwable, action: String = "Build", enableStyle: Boolean, fullTrace: Boolean) {
val sb = StyledTextBuilder(enableStyle = enableStyle)
val throwablePrinter = createThrowablePrinter(fullTrace = fullTrace)
throwablePrinter.indent = " "
sb.appendPlatformLine()
sb.append(action).append(" ")
sb.withStyle(Style.BOLD) {
sb.append(" ")
sb.withStyle(
StandardColor.RED.foreground) {
append("FAILURE")
}
}
// Sometimes the message interferes with Gradle's progress bar.
// So we print extra spaces so the garbage after "reason" is wiped out.
sb.appendPlatformLine(" reason: ")
throwablePrinter.print(failure, sb)
if (throwablePrinter.interestingCases > 0 || throwablePrinter.classExcludes.isEmpty()) {
println(sb.toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import com.github.vlsi.gradle.styledtext.StandardColor
import com.github.vlsi.gradle.styledtext.Style
import com.github.vlsi.gradle.styledtext.StyledTextBuilder
import org.gradle.api.GradleException
import org.gradle.api.InvalidUserDataException
import org.gradle.api.UncheckedIOException
import org.gradle.api.internal.tasks.TaskDependencyResolveException
import org.gradle.api.tasks.TaskExecutionException
import org.gradle.execution.MultipleBuildFailures
import org.gradle.execution.TaskSelectionException
import org.gradle.execution.commandline.TaskConfigurationException
import org.gradle.internal.UncheckedException
Expand Down Expand Up @@ -126,6 +128,14 @@ class ThrowablePrinter {
{
it.message?.startsWith("The following files have format violations") == true
},
{
it is MultipleBuildFailures
},
{
it is InvalidUserDataException &&
it.message?.startsWith("Cannot perform signing task") == true &&
it.message?.endsWith("because it has no configured signatory") == true
},
{
it.javaClass.name == "org.opentest4j.MultipleFailuresError"
},
Expand Down
Loading