Skip to content

Commit

Permalink
Add progress event for problem api events (gradle#32328)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfs authored Feb 10, 2025
2 parents 0ea1baf + 1e5ab67 commit f021f82
Show file tree
Hide file tree
Showing 36 changed files with 1,151 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ public InternalProblemBuilder solution(@Nullable String solution) {
}

@Override
public InternalProblemBuilder taskPathLocation(String buildTreePath) {
return validateDelegate(delegate.taskPathLocation(buildTreePath));
public InternalProblemBuilder taskLocation(String buildTreePath) {
return validateDelegate(delegate.taskLocation(buildTreePath));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ public R execute(UnitOfWork work, C context) {
InternalProblems problemsService = validationContext.getProblemsService();
InternalProblemReporter reporter = problemsService.getInternalReporter();
List<InternalProblem> problems = validationContext.getProblems();
for (InternalProblem problem : problems) {
reporter.report(problem);
}

Map<Severity, ImmutableList<InternalProblem>> problemsMap = problems.stream()
.collect(
Expand All @@ -92,6 +89,9 @@ public R execute(UnitOfWork work, C context) {
List<InternalProblem> errors = problemsMap.getOrDefault(ERROR, ImmutableList.of());

if (!warnings.isEmpty()) {
for (InternalProblem warning : warnings) {
reporter.report(warning);
}
warningReporter.recordValidationWarnings(work, warnings);
}

Expand Down Expand Up @@ -169,9 +169,11 @@ protected void throwValidationException(UnitOfWork work, WorkValidationContext v
Set<String> uniqueErrors = validationErrors.stream()
.map(TypeValidationProblemRenderer::renderMinimalInformationAbout)
.collect(toImmutableSet());
throw WorkValidationException.forProblems(uniqueErrors)
WorkValidationException workValidationException = WorkValidationException.forProblems(uniqueErrors)
.withSummaryForContext(work.getDisplayName(), validationContext)
.get();
InternalProblemReporter reporter = validationContext.getProblemsService().getInternalReporter();
throw reporter.throwing(workValidationException, validationErrors);
}

@ServiceScope(Scope.Global.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package org.gradle.workers.internal

import org.gradle.api.problems.internal.TaskPathLocation
import com.google.common.collect.Iterables
import org.gradle.api.problems.Severity
import org.gradle.api.problems.internal.TaskLocation
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.BuildOperationsFixture
import org.gradle.internal.jvm.Jvm
import org.gradle.operations.problems.ProblemUsageProgressDetails
import org.gradle.workers.fixtures.WorkerExecutorFixture

class WorkerExecutorProblemsApiIntegrationTest extends AbstractIntegrationSpec {
Expand Down Expand Up @@ -134,11 +138,39 @@ class WorkerExecutorProblemsApiIntegrationTest extends AbstractIntegrationSpec {
exception.message == "Exception message"
exception.stacktrace.contains("Caused by: java.lang.Exception: Wrapped cause")
contextualLocations.size() == 1
(contextualLocations[0] as TaskPathLocation).buildTreePath == ":reportProblem"
(contextualLocations[0] as TaskLocation).buildTreePath == ":reportProblem"
}

def problem = Iterables.getOnlyElement(filteredProblemDetails(buildOperationsFixture))
with(problem) {
with(definition) {
name == 'type'
displayName == 'label'
with(group) {
displayName == 'Generic'
name == 'generic'
parent == null
}
documentationLink == null
}
severity == Severity.WARNING.name()
contextualLabel == null
solutions == []
details == null
// TODO: Should have the stack location
originLocations.empty
contextualLocations.empty
failure != null
}

where:
isolationMode << WorkerExecutorFixture.ISOLATION_MODES
}

static Collection<Map<String, ?>> filteredProblemDetails(BuildOperationsFixture buildOperations) {
List<Map<String, ?>> details = buildOperations.progress(ProblemUsageProgressDetails).details
details
.findAll { it.definition.name != 'executing-gradle-on-jvm-versions-and-lower'}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

/**
* A link to a documentation page.
*
* @since 8.14
*/
public interface DocumentationLink {

/**
* The URL of the documentation page.
*
* @since 8.14
*/
String getUrl();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

/**
* A file location.
*
* @since 8.14
*/
public interface FileLocation extends ProblemLocation {

// TODO: Add getFileType() - build logic file, software definition, application code

/**
* The absolute path of the file.
*
* @since 8.14
*/
String getPath();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

import javax.annotation.Nullable;

/**
* A basic location pointing to a specific part of a file using line number, column, and length for coordinates.
* <p>
* The line and column coordinates are one-indexed so that they can be easily matched to the content of a UI editor interface.
*
* @since 8.14
*/
public interface LineInFileLocation extends FileLocation {

/**
* The line number within the file.
* <p>
* The line is <b>one-indexed</b>, i.e. the first line in the file is line number 1.
*
* @since 8.14
*/
int getLine();

/**
* The starting column on the selected line.
* <p>
* The column is <b>one-indexed</b>, i.e. the first column in the file is line number 1.
* Null indicates that the column information is not available.
*
* @since 8.14
*/
@Nullable
Integer getColumn();

/**
* The length of the selected content starting from specified column.
* Null indicates that the column information is not available.
*
* @return the length
* @since 8.14
*/
@Nullable
Integer getLength();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

/**
* A basic location pointing to a specific part of a file using a global offset and length for coordinates.
* <p>
* The coordinates are expected to be zero indexed.
*
* @since 8.14
*/
public interface OffsetInFileLocation extends FileLocation {

/**
* The global offset from the beginning of the file.
*
* @return the zero-indexed the offset
* @since 8.14
*/
int getOffset();

/**
* The length of the content starting from {@link #getOffset()}.
*
* @since 8.14
*/
int getLength();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

/**
* Gradle Plugin ID location.
*
* @since 8.14
*/
public interface PluginIdLocation extends ProblemLocation {

/**
* The plugin ID.
*
* @since 8.14
*/
String getPluginId();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2025 the original author or authors.
*
* 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 org.gradle.operations.problems;

import javax.annotation.Nullable;

/**
* Describes a specific problem without a concrete usage.
* <p>
* For example, in the domain of Java compilation problems, an unused variable warning could be described as such:
* <ul>
* <li>group: compilation:java</li>
* <li>unused variable</li>
* <li>severity: WARNING</li>
* <li>...</li>
* </ul>
* <p>
* The group and the name uniquely identify the problem definition, the remaining fields only supply additional information.
*
* @since 8.14
*/
public interface ProblemDefinition {

/**
* The name of the problem.
* <p>
* The name should be used to categorize a set of problems.
* The name itself does not need to be unique, the uniqueness is determined the name and the group hierarchy.
*
* @since 8.14
*/
String getName();

/**
* A human-readable label describing the problem ID.
* <p>
* The display name should be used to present the problem to the user.
*
* @since 8.14
*/
String getDisplayName();

/**
* The group of the problem.
*
* @since 8.14
*/
ProblemGroup getGroup();

/**
* A link to the documentation for this problem.
*
* @since 8.14
*/
@Nullable
DocumentationLink getDocumentationLink();

}
Loading

0 comments on commit f021f82

Please sign in to comment.