Skip to content

Commit

Permalink
Feature: Allow other plugins to register tasks to produce junit repor…
Browse files Browse the repository at this point in the history
…ts (#1764)

Allow other plugins to register tasks to produce junit reports
  • Loading branch information
ferozco authored May 21, 2021
1 parent 98a7fd4 commit 2806578
Show file tree
Hide file tree
Showing 27 changed files with 458 additions and 279 deletions.
5 changes: 5 additions & 0 deletions changelog/@unreleased/pr-1764.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: improvement
improvement:
description: Allow other plugins to register tasks to produce junit reports
links:
- https://github.com/palantir/gradle-baseline/pull/1764
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.palantir.gradle.junit.JunitReportsExtension;
import com.palantir.gradle.junit.JunitReportsPlugin;
import com.palantir.gradle.junit.JunitReportsRootPlugin;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
Expand All @@ -39,7 +39,7 @@ public final class BaselineCircleCi implements Plugin<Project> {

@Override
public void apply(Project project) {
project.getPluginManager().apply(JunitReportsPlugin.class);
project.getPluginManager().apply(JunitReportsRootPlugin.class);

configurePluginsForReports(project);
configurePluginsForArtifacts(project);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void javacIntegrationTest() throws IOException {
.contains("b = 2")
.contains("uses unchecked or unsafe operations");

File report = new File(reportsDir, "javac/foobar-compileJava.xml");
File report = new File(reportsDir, "/foobar-compileJava.xml");
assertThat(report).exists();
String reportXml = Files.asCharSource(report, StandardCharsets.UTF_8).read();
assertThat(reportXml)
Expand Down Expand Up @@ -134,7 +134,7 @@ public void checkstyleIntegrationTest() throws IOException {
.buildAndFail();
assertThat(result.getOutput()).contains("Checkstyle rule violations were found");

File report = new File(reportsDir, "checkstyle/foobar-checkstyleMain.xml");
File report = new File(reportsDir, "foobar-checkstyleMain.xml");
assertThat(report).exists();
String reportXml = Files.asCharSource(report, StandardCharsets.UTF_8).read();
assertThat(reportXml).contains("Name 'a_constant' must match pattern");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ class BaselineIntegrationTest extends AbstractPluginTest {
with().withArguments('-s').withGradleVersion(gradleVersion).build()

where:
gradleVersion << ['5.4', '6.2']
gradleVersion << ['6.1', '6.2']
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import spock.lang.Unroll
@Unroll
@IgnoreIf({ Integer.parseInt(jvm.javaSpecificationVersion) >= 14 })
class JunitReportsPluginSpec extends IntegrationSpec {
private static final List<String> GRADLE_TEST_VERSIONS = ['5.6.4', '6.1']
private static final List<String> GRADLE_TEST_VERSIONS = ['6.1']

def '#gradleVersionNumber: configures the checkstlye plugin correctly'() {
setup:
Expand Down
14 changes: 10 additions & 4 deletions gradle-junit-reports/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ dependencies {
compile gradleApi()
compile 'com.google.guava:guava'

annotationProcessor 'org.immutables:value'
annotationProcessor 'org.inferred:freebuilder'

compileOnly 'org.immutables:value::annotations'
compileOnly 'org.inferred:freebuilder'

testCompile 'com.google.guava:guava'
testCompile 'junit:junit'
testCompile 'org.assertj:assertj-core'
testCompile 'org.mockito:mockito-core'
testImplementation 'com.google.guava:guava'
testImplementation 'com.netflix.nebula:nebula-test'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.mockito:mockito-junit-jupiter'

testRuntimeOnly 'org.junit.vintage:junit-vintage-engine'
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,32 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import org.gradle.api.Task;
import org.gradle.api.execution.TaskExecutionListener;
import org.gradle.api.tasks.TaskExecutionException;
import org.gradle.api.tasks.TaskState;
import org.gradle.api.tasks.testing.Test;

public final class BuildFailureListener implements TaskExecutionListener {

private final List<Report.TestCase> testCases = new ArrayList<>();
private final Predicate<Task> isTracked;

public BuildFailureListener(Predicate<Task> isTracked) {
this.isTracked = isTracked;
}

@Override
@SuppressWarnings("StrictUnusedVariable")
public void beforeExecute(Task task) {}
public void beforeExecute(Task _task) {}

@Override
public synchronized void afterExecute(Task task, TaskState state) {
if (isUntracked(task)) {
if (!isTracked.test(task)) {
Report.TestCase.Builder testCase =
new Report.TestCase.Builder().name(":" + task.getProject().getName() + ":" + task.getName());

Throwable failure = state.getFailure();
if (failure != null && isUntracked(task)) {
if (failure != null) {
if (failure instanceof TaskExecutionException && failure.getCause() != null) {
failure = failure.getCause();
}
Expand All @@ -67,8 +71,4 @@ private static String getMessage(Throwable throwable) {
return throwable.getClass().getSimpleName() + ": " + throwable.getMessage();
}
}

private static boolean isUntracked(Task task) {
return !(task instanceof Test) && !StyleTaskTimer.isStyleTask(task);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void startElement(String uri, String localName, String qName, Attributes
break;

case "error":
failures.add(new Failure.Builder()
failures.add(Failure.builder()
.source(attributes.getValue("source"))
.severity(attributes.getValue("severity").toUpperCase())
.file(file)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* (c) Copyright 2017 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.gradle.junit;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.function.Predicate;
import org.gradle.api.Task;
import org.gradle.api.execution.TaskExecutionListener;
import org.gradle.api.tasks.TaskState;

public final class DefaultTaskTimer implements TaskTimer, TaskExecutionListener {

private final Map<Task, Timer> taskTimers = new LinkedHashMap<>();
private final Predicate<Task> isTrackedTask;

public DefaultTaskTimer(Predicate<Task> isTrackedTask) {
this.isTrackedTask = isTrackedTask;
}

@Override
public long getTaskTimeNanos(Task task) {
return Optional.ofNullable(taskTimers.get(task))
.map(Timer::getElapsed)
.orElseThrow(() -> new IllegalArgumentException("No time available for task " + task.getName()));
}

@Override
public void beforeExecute(Task task) {
if (isTrackedTask.test(task)) {
taskTimers.put(task, new Timer());
}
}

@Override
public void afterExecute(Task task, TaskState _taskState) {
Optional.ofNullable(taskTimers.get(task)).ifPresent(Timer::stop);
}

static final class Timer {
private final long startTime;
private OptionalLong endTime;

Timer() {
this.startTime = System.nanoTime();
this.endTime = OptionalLong.empty();
}

void stop() {
endTime = OptionalLong.of(System.nanoTime());
}

long getElapsed() {
if (endTime.isPresent()) {
return endTime.getAsLong() - startTime;
}
return 0L;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@
package com.palantir.gradle.junit;

import java.io.File;
import org.inferred.freebuilder.FreeBuilder;
import org.immutables.value.Value.Default;
import org.immutables.value.Value.Immutable;

@FreeBuilder
interface Failure {
@Immutable
public interface Failure {

String source();
@Default
default String source() {
return "";
}

File file();

Expand All @@ -31,12 +35,14 @@ interface Failure {

String message();

String details();
@Default
default String details() {
return "";
}

class Builder extends ImmutableFailure.Builder {}

class Builder extends Failure_Builder {
Builder() {
source("");
details("");
}
static Builder builder() {
return new Builder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.nio.file.Path;
import java.util.List;

interface FailuresSupplier {
public interface FailuresSupplier {
List<Failure> getFailures() throws IOException;

RuntimeException handleInternalFailure(Path reportDir, RuntimeException ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public List<Failure> getFailures() {
}
Matcher matcher = ERROR_LINE.matcher(line);
if (matcher.matches()) {
failureBuilder = new Failure.Builder()
failureBuilder = Failure.builder()
.file(new File(matcher.group(1)))
.line(Integer.parseInt(matcher.group(2)))
.severity("ERROR")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,35 @@

package com.palantir.gradle.junit;

import java.util.function.Predicate;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;

public class JunitReportsExtension {
private static final String EXT_JUNIT_REPORTS = "junitReports";

private final DirectoryProperty reportsDirectory;
private final TaskTimer taskTimer;

public JunitReportsExtension(Project project) {
this.reportsDirectory = project.getObjects().directoryProperty();
reportsDirectory.set(project.getLayout().getBuildDirectory().dir("junit-reports"));
static JunitReportsExtension register(Project project, Predicate<Task> isTaskRegistered) {
DefaultTaskTimer timer = new DefaultTaskTimer(isTaskRegistered);
project.getGradle().addListener(timer);
return project.getExtensions().create(EXT_JUNIT_REPORTS, JunitReportsExtension.class, project, timer);
}

public JunitReportsExtension(Project project, TaskTimer taskTimer) {
this.reportsDirectory = project.getObjects()
.directoryProperty()
.value(project.getLayout().getBuildDirectory().dir("junit-reports"));
this.taskTimer = taskTimer;
}

public final DirectoryProperty getReportsDirectory() {
return reportsDirectory;
}

public final TaskTimer getTaskTimer() {
return taskTimer;
}
}
Loading

0 comments on commit 2806578

Please sign in to comment.