Skip to content

Commit

Permalink
Add problem collection to org.gradle.internal.enterprise.GradleEnterp…
Browse files Browse the repository at this point in the history
…risePluginEndOfBuildListener.BuildResult
  • Loading branch information
reinsch82 committed Apr 18, 2024
1 parent 4233411 commit da1ba3f
Show file tree
Hide file tree
Showing 19 changed files with 115 additions and 30 deletions.
3 changes: 1 addition & 2 deletions gradle.properties
@@ -1,4 +1,3 @@
# Reduce Xmx after https://github.com/gradle/gradle-private/issues/4168 is resolved
org.gradle.jvmargs=-Xmx3000m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
Expand Down Expand Up @@ -29,5 +28,5 @@ systemProp.dependency.analysis.test.analysis=false
unmigratedProjects=\
enterprise,enterprise-logging,enterprise-plugin-performance,ide,ide-native,installation-beacon,internal-integ-testing,internal-performance-testing,internal-testing,kotlin-dsl,kotlin-dsl-plugins,\
kotlin-dsl-provider-plugins,kotlin-dsl-tooling-models,language-native,launcher,performance,platform-native,plugin-development,\
plugin-use,problems,problems-api,\
plugin-use,problems,\
testing-native,test-kit,tooling-api,tooling-api-builders,tooling-native,worker-services,workers,wrapper,smoke-ide-test
1 change: 1 addition & 0 deletions platforms/enterprise/enterprise/build.gradle.kts
Expand Up @@ -51,6 +51,7 @@ dependencies {
integTestImplementation(project(":messaging"))
integTestImplementation(project(":persistent-cache"))
integTestImplementation(project(":native"))
integTestImplementation(testFixtures(project(":problems-api")))
integTestImplementation(libs.guava)

integTestDistributionRuntimeOnly(project(":distributions-full"))
Expand Down
Expand Up @@ -164,6 +164,7 @@ abstract class BaseBuildScanPluginCheckInFixture {
$GradleEnterprisePluginEndOfBuildListener.name getEndOfBuildListener() {
return { $GradleEnterprisePluginEndOfBuildListener.BuildResult.name buildResult ->
println "${propertyPrefix}.endOfBuild.buildResult.failure = \$buildResult.failure"
println "${propertyPrefix}.endOfBuild.buildResult.problems = \${buildResult.problems.size()}"
if (System.getProperty("build-listener-failure") != null) {
throw new RuntimeException("broken")
}
Expand Down
Expand Up @@ -16,44 +16,55 @@

package org.gradle.internal.enterprise


import org.gradle.integtests.fixtures.AbstractIntegrationSpec

import static org.gradle.api.problems.ReportingScript.getProblemReportingScript

class DevelocityPluginEndOfBuildCallbackIntegrationTest extends AbstractIntegrationSpec {

def plugin = new DevelocityPluginCheckInFixture(testDirectory, mavenRepo, createExecuter())
def failingTaskName = "reportProblem"
def succeedingTaskName = "succeedingTask"

def setup() {
settingsFile << plugin.pluginManagement() << plugin.plugins()
plugin.publishDummyPlugin(executer)
buildFile << """
task t
task f { doLast { throw new RuntimeException("failed") } }

buildFile """
${getProblemReportingScript """
problems.forNamespace('org.example.plugin').throwing {
it.id('type', 'label')
.withException(new RuntimeException('failed'))
}"""}
task $succeedingTaskName
"""
}

def "end of build listener is notified on success"() {
when:
succeeds "t"
succeeds succeedingTaskName

then:
plugin.assertEndOfBuildWithFailure(output, null)

when:
succeeds "t"
succeeds succeedingTaskName

then:
plugin.assertEndOfBuildWithFailure(output, null)
}

def "end of build listener is notified on failure"() {
when:
fails "f"
fails failingTaskName

then:
plugin.assertEndOfBuildWithFailure(output, "org.gradle.internal.exceptions.LocationAwareException: Build file")

when:
fails "f"
fails failingTaskName

then:
// Note: we test less of the exception here because it's different in a build where configuration came from cache
Expand All @@ -63,14 +74,14 @@ class DevelocityPluginEndOfBuildCallbackIntegrationTest extends AbstractIntegrat

def "end of build listener may fail with an exception"() {
when:
fails "t", "-Dbuild-listener-failure"
fails succeedingTaskName, "-Dbuild-listener-failure"

then:
plugin.assertEndOfBuildWithFailure(output, null)
failure.assertHasDescription("broken")

when:
fails "t", "-Dbuild-listener-failure"
fails succeedingTaskName, "-Dbuild-listener-failure"

then:
plugin.assertEndOfBuildWithFailure(output, null)
Expand Down
Expand Up @@ -16,7 +16,10 @@

package org.gradle.internal.enterprise;

import org.gradle.api.problems.internal.Problem;

import javax.annotation.Nullable;
import java.util.Collection;

/**
* Used to signal the end of build to the plugin.
Expand All @@ -31,6 +34,8 @@ public interface GradleEnterprisePluginEndOfBuildListener {
interface BuildResult {
@Nullable
Throwable getFailure();

Collection<Problem> getProblems();
}

void buildFinished(BuildResult buildResult);
Expand Down
Expand Up @@ -16,6 +16,9 @@

package org.gradle.internal.enterprise.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import org.gradle.api.problems.internal.Problem;
import org.gradle.internal.enterprise.GradleEnterprisePluginBuildState;
import org.gradle.internal.enterprise.GradleEnterprisePluginConfig;
import org.gradle.internal.enterprise.GradleEnterprisePluginEndOfBuildListener;
Expand All @@ -25,7 +28,9 @@
import org.gradle.internal.enterprise.core.GradleEnterprisePluginAdapter;
import org.gradle.internal.operations.notify.BuildOperationNotificationListenerRegistrar;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;

/**
* Captures the state to recreate the {@link GradleEnterprisePluginService} instance.
Expand All @@ -48,6 +53,7 @@ public class DefaultGradleEnterprisePluginAdapter implements GradleEnterprisePlu
private final DefaultGradleEnterprisePluginServiceRef pluginServiceRef;

private final BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar;
private final Multimap<Throwable, Problem> problemsMapping;

private transient GradleEnterprisePluginService pluginService;

Expand All @@ -57,14 +63,16 @@ public DefaultGradleEnterprisePluginAdapter(
DefaultGradleEnterprisePluginRequiredServices requiredServices,
GradleEnterprisePluginBuildState buildState,
DefaultGradleEnterprisePluginServiceRef pluginServiceRef,
BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar
BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar,
Multimap<Throwable, Problem> problemsMapping
) {
this.pluginServiceFactory = pluginServiceFactory;
this.config = config;
this.requiredServices = requiredServices;
this.buildState = buildState;
this.pluginServiceRef = pluginServiceRef;
this.buildOperationNotificationListenerRegistrar = buildOperationNotificationListenerRegistrar;
this.problemsMapping = problemsMapping;

createPluginService();
}
Expand Down Expand Up @@ -95,14 +103,28 @@ public void buildFinished(@Nullable Throwable buildFailure) {
public Throwable getFailure() {
return buildFailure;
}

@Override
public Collection<Problem> getProblems() {
return DefaultGradleEnterprisePluginAdapter.this.getProblems(buildFailure);
}
});
}
}

private @Nonnull Collection<Problem> getProblems(@Nullable Throwable buildFailure) {
ImmutableList.Builder<Problem> builder = ImmutableList.builder();
while(buildFailure != null) {
Collection<Problem> problems = problemsMapping.get(buildFailure);
builder.addAll(problems);
buildFailure = buildFailure.getCause();
}
return builder.build();
}

private void createPluginService() {
pluginService = pluginServiceFactory.create(config, requiredServices, buildState);
pluginServiceRef.set(pluginService);
buildOperationNotificationListenerRegistrar.register(pluginService.getBuildOperationNotificationListener());
}

}
Expand Up @@ -16,6 +16,9 @@

package org.gradle.internal.enterprise.impl;

import com.google.common.collect.Multimap;
import org.gradle.api.problems.internal.InternalProblems;
import org.gradle.api.problems.internal.Problem;
import org.gradle.internal.enterprise.GradleEnterprisePluginBuildState;
import org.gradle.internal.enterprise.GradleEnterprisePluginConfig;
import org.gradle.internal.enterprise.GradleEnterprisePluginServiceFactory;
Expand All @@ -31,19 +34,22 @@ public class DefaultGradleEnterprisePluginAdapterFactory {
private final GradleEnterprisePluginBuildState buildState;
private final DefaultGradleEnterprisePluginServiceRef pluginServiceRef;
private final BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar;
private final Multimap<Throwable, Problem> problemsMapping;

public DefaultGradleEnterprisePluginAdapterFactory(
GradleEnterprisePluginConfig config,
DefaultGradleEnterprisePluginRequiredServices requiredServices,
GradleEnterprisePluginBuildState buildState,
DefaultGradleEnterprisePluginServiceRef pluginServiceRef,
BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar
BuildOperationNotificationListenerRegistrar buildOperationNotificationListenerRegistrar,
InternalProblems problems
) {
this.config = config;
this.requiredServices = requiredServices;
this.buildState = buildState;
this.pluginServiceRef = pluginServiceRef;
this.buildOperationNotificationListenerRegistrar = buildOperationNotificationListenerRegistrar;
this.problemsMapping = problems.getProblems();
}

public DefaultGradleEnterprisePluginAdapter create(GradleEnterprisePluginServiceFactory pluginServiceFactory) {
Expand All @@ -53,7 +59,8 @@ public DefaultGradleEnterprisePluginAdapter create(GradleEnterprisePluginService
requiredServices,
buildState,
pluginServiceRef,
buildOperationNotificationListenerRegistrar
buildOperationNotificationListenerRegistrar,
problemsMapping
);
}
}
Expand Up @@ -16,6 +16,7 @@

package org.gradle.plugin.devel.tasks.internal

import com.google.common.collect.HashMultimap
import com.google.gson.Gson
import org.gradle.api.problems.Severity
import org.gradle.api.problems.internal.DefaultProblemReporter
Expand All @@ -28,7 +29,7 @@ import spock.lang.Specification
class ValidationProblemSerializationTest extends Specification {

Gson gson = ValidationProblemSerialization.createGsonBuilder().create()
InternalProblemReporter problemReporter = new DefaultProblemReporter(Stub(ProblemEmitter), [], org.gradle.internal.operations.CurrentBuildOperationRef.instance())
InternalProblemReporter problemReporter = new DefaultProblemReporter(Stub(ProblemEmitter), [], org.gradle.internal.operations.CurrentBuildOperationRef.instance(), HashMultimap.create())

def "can serialize and deserialize a validation problem"() {
given:
Expand Down
1 change: 1 addition & 0 deletions platforms/ide/problems-api/build.gradle.kts
Expand Up @@ -45,4 +45,5 @@ dependencies {

testFixturesImplementation(project(":enterprise-operations"))
testFixturesImplementation(project(":base-services"))
testFixturesImplementation(project(":internal-integ-testing"))
}
Expand Up @@ -16,6 +16,7 @@

package org.gradle.api.problems.internal;

import com.google.common.collect.Multimap;
import org.gradle.api.Action;
import org.gradle.api.problems.ProblemSpec;
import org.gradle.internal.operations.CurrentBuildOperationRef;
Expand All @@ -28,11 +29,18 @@ public class DefaultProblemReporter implements InternalProblemReporter {
private final ProblemEmitter emitter;
private final List<ProblemTransformer> transformers;
private final CurrentBuildOperationRef currentBuildOperationRef;
private final Multimap<Throwable, Problem> problems;

public DefaultProblemReporter(ProblemEmitter emitter, List<ProblemTransformer> transformers, CurrentBuildOperationRef currentBuildOperationRef) {
public DefaultProblemReporter(
ProblemEmitter emitter,
List<ProblemTransformer> transformers,
CurrentBuildOperationRef currentBuildOperationRef,
Multimap<Throwable, Problem> problems
) {
this.emitter = emitter;
this.transformers = transformers;
this.currentBuildOperationRef = currentBuildOperationRef;
this.problems = problems;
}

@Override
Expand All @@ -57,6 +65,7 @@ public RuntimeException throwing(Action<ProblemSpec> spec) {

public RuntimeException throwError(RuntimeException exception, Problem problem) {
report(problem);
problems.put(exception, problem);
throw exception;
}

Expand Down
Expand Up @@ -16,6 +16,9 @@

package org.gradle.api.problems.internal;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import org.gradle.api.problems.ProblemReporter;
import org.gradle.internal.operations.CurrentBuildOperationRef;
import org.gradle.internal.service.scopes.Scope;
Expand All @@ -24,13 +27,16 @@
import java.util.Collections;
import java.util.List;

import static org.gradle.api.problems.internal.DefaultProblemCategory.GRADLE_CORE_NAMESPACE;

@ServiceScope(Scope.BuildTree.class)
public class DefaultProblems implements InternalProblems {

private final CurrentBuildOperationRef currentBuildOperationRef;
private final ProblemEmitter emitter;
private final List<ProblemTransformer> transformers;
private final InternalProblemReporter internalReporter;
private final Multimap<Throwable, Problem> problems = Multimaps.synchronizedMultimap(HashMultimap.<Throwable, Problem>create());

public DefaultProblems(ProblemEmitter emitter, CurrentBuildOperationRef currentBuildOperationRef) {
this(emitter, Collections.<ProblemTransformer>emptyList(), currentBuildOperationRef);
Expand All @@ -43,23 +49,28 @@ public DefaultProblems(ProblemEmitter emitter, List<ProblemTransformer> transfor
this.emitter = emitter;
this.transformers = transformers;
this.currentBuildOperationRef = currentBuildOperationRef;
internalReporter = createReporter(emitter, transformers);
internalReporter = createReporter(emitter, transformers, problems);
}

@Override
public ProblemReporter forNamespace(String namespace) {
if (DefaultProblemCategory.GRADLE_CORE_NAMESPACE.equals(namespace)) {
throw new IllegalStateException("Cannot use " + DefaultProblemCategory.GRADLE_CORE_NAMESPACE + " namespace.");
if (GRADLE_CORE_NAMESPACE.equals(namespace)) {
throw new IllegalStateException("Cannot use " + GRADLE_CORE_NAMESPACE + " namespace. Reserved for internal use.");
}
return createReporter(emitter, transformers);
return createReporter(emitter, transformers, problems);
}

private DefaultProblemReporter createReporter(ProblemEmitter emitter, List<ProblemTransformer> transformers) {
return new DefaultProblemReporter(emitter, transformers, currentBuildOperationRef);
private DefaultProblemReporter createReporter(ProblemEmitter emitter, List<ProblemTransformer> transformers, Multimap<Throwable, Problem> problems) {
return new DefaultProblemReporter(emitter, transformers, currentBuildOperationRef, problems);
}

@Override
public InternalProblemReporter getInternalReporter() {
return internalReporter;
}

@Override
public Multimap<Throwable, Problem> getProblems() {
return problems;
}
}
Expand Up @@ -16,6 +16,7 @@

package org.gradle.api.problems.internal;

import com.google.common.collect.Multimap;
import org.gradle.api.problems.Problems;

public interface InternalProblems extends Problems {
Expand All @@ -27,4 +28,6 @@ public interface InternalProblems extends Problems {
* @return The reporter.
*/
InternalProblemReporter getInternalReporter();

Multimap<Throwable, Problem> getProblems();
}

0 comments on commit da1ba3f

Please sign in to comment.