Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto add junit-platform-launcher to classpath #1212

Merged
merged 1 commit into from
May 18, 2023
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
30 changes: 26 additions & 4 deletions pitest-maven/src/main/java/org/pitest/maven/AbstractPitMojo.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.pitest.maven;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystem;
import org.pitest.coverage.CoverageSummary;
import org.pitest.mutationtest.config.PluginServices;
import org.pitest.mutationtest.config.ReportOptions;
Expand All @@ -16,6 +18,7 @@
import org.slf4j.bridge.SLF4JBridgeHandler;
import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J;

import javax.inject.Inject;
import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
Expand All @@ -37,6 +40,13 @@ public class AbstractPitMojo extends AbstractMojo {

private final PluginServices plugins;

/**
* The current build session instance.
*/
@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;


// Concrete List types declared for all fields to work around maven 2 bug

/**
Expand Down Expand Up @@ -385,18 +395,22 @@ public class AbstractPitMojo extends AbstractMojo {

private final GoalStrategy goalStrategy;

public AbstractPitMojo() {
private final RepositorySystem repositorySystem;

@Inject
public AbstractPitMojo(RepositorySystem repositorySystem) {
this(new RunPitStrategy(), new DependencyFilter(PluginServices.makeForLoader(
AbstractPitMojo.class.getClassLoader())), PluginServices.makeForLoader(
AbstractPitMojo.class.getClassLoader()), new NonEmptyProjectCheck());
AbstractPitMojo.class.getClassLoader()), new NonEmptyProjectCheck(), repositorySystem);
}

public AbstractPitMojo(final GoalStrategy strategy, final Predicate<Artifact> filter,
final PluginServices plugins, final Predicate<MavenProject> emptyProjectCheck) {
public AbstractPitMojo(GoalStrategy strategy, Predicate<Artifact> filter,
PluginServices plugins, Predicate<MavenProject> emptyProjectCheck, RepositorySystem repositorySystem) {
this.goalStrategy = strategy;
this.filter = filter;
this.plugins = plugins;
this.notEmptyProject = emptyProjectCheck;
this.repositorySystem = repositorySystem;
}

@Override
Expand Down Expand Up @@ -740,6 +754,14 @@ public String getProjectBase() {
return projectBase;
}

public MavenSession session() {
return session;
}

public RepositorySystem repositorySystem() {
return repositorySystem;
}

static class RunDecision {
private List<String> reasons = new ArrayList<>(4);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.pitest.classinfo.ClassName;
import org.pitest.classpath.DirectoryClassPathRoot;
import org.pitest.functional.FCollection;
Expand All @@ -40,6 +44,7 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
Expand Down Expand Up @@ -77,18 +82,84 @@ public ReportOptions convert() {

classPath.addAll(this.mojo.getAdditionalClasspathElements());

autoAddJUnitPlatform(classPath);
removeExcludedDependencies(classPath);

ReportOptions option = parseReportOptions(classPath);
return updateFromSurefire(option);

}

/**
* The junit 5 plugin needs junit-platform-launcher to run, but this will not be on the classpath
* of the project. We want to use the same version that surefire (and therefore the SUT) uses, not
* the one the plugin was built against.
* <p>
* It is not declared as a normal dependency, instead surefire picks the version to use based on
* other junit jars on the classpath. We're forced to do something similar here.
*
* @param classPath classpath to modify
*/
private void autoAddJUnitPlatform(List<String> classPath) {
List<Artifact> junitDependencies = this.mojo.getProject().getArtifacts().stream()
.filter(a -> a.getGroupId().equals("org.junit.platform"))
.collect(Collectors.toList());

// If the launcher has been manually added to the dependencies, there is nothing to do
if (junitDependencies.stream().anyMatch(a -> a.getArtifactId().equals("junit-platform-launcher"))) {
return;
}

Optional<Artifact> maybeJUnitPlatform = findJUnitArtifact(junitDependencies);
if (!maybeJUnitPlatform.isPresent()) {
this.log.debug("JUnit 5 not on classpath");
return;
}

// Look for platform engine or platform commons on classpath
Artifact toMatch = maybeJUnitPlatform.get();

// Assume that platform launcher has been released with same version number as engine and commons
DefaultArtifact platformLauncher = new DefaultArtifact(toMatch.getGroupId(), "junit-platform-launcher", "jar",
toMatch.getVersion());

try {
ArtifactRequest r = new ArtifactRequest();
r.setArtifact(platformLauncher);

r.setRepositories(this.mojo.getProject().getRemotePluginRepositories());
ArtifactResult resolved = this.mojo.repositorySystem().resolveArtifact(mojo.session().getRepositorySession(), r);

this.log.info("Auto adding " + resolved + " to classpath.");
classPath.add(resolved.getArtifact().getFile().getAbsolutePath());
} catch (ArtifactResolutionException e) {
this.log.error("Could not resolve " + platformLauncher);
throw new RuntimeException(e);
}

}

private static Optional<Artifact> findJUnitArtifact(List<Artifact> junitDependencies) {
Optional<Artifact> maybeEngine = junitDependencies.stream()
.filter(a -> a.getArtifactId().equals("junit-platform-engine"))
.findAny();
if (maybeEngine.isPresent()) {
return maybeEngine;
}

return junitDependencies.stream()
.filter(a -> a.getArtifactId().equals("junit-platform-commons"))
.findAny();
}

private void removeExcludedDependencies(List<String> classPath) {
for (Object artifact : this.mojo.getProject().getArtifacts()) {
final Artifact dependency = (Artifact) artifact;

if (this.mojo.getClasspathDependencyExcludes().contains(
dependency.getGroupId() + ":" + dependency.getArtifactId())) {
classPath.remove(dependency.getFile().getPath());
}
}

ReportOptions option = parseReportOptions(classPath);
return updateFromSurefire(option);

}

private ReportOptions parseReportOptions(final List<String> classPath) {
Expand Down Expand Up @@ -270,6 +341,11 @@ private void addOwnDependenciesToClassPath(final List<String> classPath) {
+ dependency.getArtifactId() + " to SUT classpath");
classPath.add(dependency.getFile().getAbsolutePath());
}

// If the user as explicitly added junit platform classes to the pitest classpath, trust that they
// know what they're doing and add them in
this.mojo.getPluginArtifactMap().values().stream().filter(a -> a.getGroupId().equals("org.junit.platform"))
.forEach(dependency -> classPath.add(dependency.getFile().getAbsolutePath()));
}

private Collection<Predicate<String>> globStringsToPredicates(
Expand Down
7 changes: 7 additions & 0 deletions pitest-maven/src/main/java/org/pitest/maven/PitMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.eclipse.aether.RepositorySystem;

import javax.inject.Inject;

/**
* Goal which runs a coverage mutation report
Expand All @@ -13,4 +16,8 @@
threadSafe = true)
public class PitMojo extends AbstractPitMojo {

@Inject
public PitMojo(RepositorySystem repositorySystem) {
super(repositorySystem);
}
}
19 changes: 13 additions & 6 deletions pitest-maven/src/main/java/org/pitest/maven/ScmMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@
import org.apache.maven.scm.manager.ScmManager;
import org.apache.maven.scm.repository.ScmRepository;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.aether.RepositorySystem;
import org.pitest.functional.FCollection;
import org.pitest.mutationtest.config.PluginServices;
import org.pitest.mutationtest.config.ReportOptions;
import org.pitest.mutationtest.tooling.CombinedStatistics;

import javax.inject.Inject;

/**
* Goal which runs a coverage mutation report only for files that have been
* modified or introduced locally based on the source control configured in
Expand Down Expand Up @@ -96,16 +99,20 @@ public class ScmMojo extends AbstractPitMojo {
@Parameter(property = "scmRootDir", defaultValue = "${project.parent.basedir}")
private File scmRootDir;

public ScmMojo(final RunPitStrategy executionStrategy,
final ScmManager manager, Predicate<Artifact> filter,
PluginServices plugins, boolean analyseLastCommit, Predicate<MavenProject> nonEmptyProjectCheck) {
super(executionStrategy, filter, plugins, nonEmptyProjectCheck);
public ScmMojo(RunPitStrategy executionStrategy,
ScmManager manager, Predicate<Artifact> filter,
PluginServices plugins,
boolean analyseLastCommit,
Predicate<MavenProject> nonEmptyProjectCheck,
RepositorySystem repositorySystem) {
super(executionStrategy, filter, plugins, nonEmptyProjectCheck, repositorySystem);
this.manager = manager;
this.analyseLastCommit = analyseLastCommit;
}

public ScmMojo() {

@Inject
public ScmMojo(RepositorySystem repositorySystem) {
super(repositorySystem);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected String createPomWithConfiguration(final String config) {

protected AbstractPitMojo createPITMojo(final String config) throws Exception {
final AbstractPitMojo pitMojo = new AbstractPitMojo(this.executionStrategy, this.filter,
this.plugins, p -> true);
this.plugins, p -> true, null);
configurePitMojo(pitMojo, config);
return pitMojo;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class ScmMojoTest extends BasePitMojoTest {
public void setUp() throws Exception {
super.setUp();
this.testee = new ScmMojo(this.executionStrategy, this.manager,
this.filter, this.plugins, false, i -> true);
this.filter, this.plugins, false, i -> true, null);
this.testee.setScmRootDir(new File("foo"));
when(this.project.getBuild()).thenReturn(this.build);
when(this.project.getParent()).thenReturn(null);
Expand Down