Skip to content

Commit

Permalink
Merge pull request #318 from imonteroperez/jep-229-support
Browse files Browse the repository at this point in the history
Support to JEP-229 / Fixing compilation on multimodule projects
  • Loading branch information
imonteroperez committed Nov 24, 2021
2 parents 04b7187 + 65f57b4 commit 5a9f15e
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ private TestExecutionResult testPluginAgainst(MavenCoordinates coreCoordinates,
System.out.println(String.format("%n%n%n%n%n"));

File pluginCheckoutDir = new File(config.workDirectory.getAbsolutePath() + File.separator + plugin.name + File.separator);
String parentFolder = StringUtils.EMPTY;

try {
// Run any precheckout hooks
Expand Down Expand Up @@ -486,6 +487,9 @@ private TestExecutionResult testPluginAgainst(MavenCoordinates coreCoordinates,
if (beforeCheckout.get("pluginDir") != null) {
pluginCheckoutDir = (File)beforeCheckout.get("checkoutDir");
}
if (beforeCheckout.get("parentFolder") != null) {
parentFolder = (String) beforeCheckout.get("parentFolder");
}
System.out.println("The plugin has already been checked out, likely due to a multimodule situation. Continue.");
}
} catch (ComponentLookupException e) {
Expand All @@ -508,6 +512,9 @@ private TestExecutionResult testPluginAgainst(MavenCoordinates coreCoordinates,
beforeCompile.put("pomData", pomData);
beforeCompile.put("config", config);
beforeCompile.put("core", coreCoordinates);
if (StringUtils.isNotEmpty(parentFolder)) {
beforeCompile.put("parentFolder", parentFolder);
}
Map<String, Object> hookInfo = pcth.runBeforeCompilation(beforeCompile);

boolean ranCompile = hookInfo.containsKey(PluginCompatTesterHookBeforeCompile.OVERRIDE_DEFAULT_COMPILE) && (boolean) hookInfo.get(PluginCompatTesterHookBeforeCompile.OVERRIDE_DEFAULT_COMPILE);
Expand All @@ -529,7 +536,7 @@ private TestExecutionResult testPluginAgainst(MavenCoordinates coreCoordinates,
// Much simpler to do use the parent POM to set up the test classpath.
MavenPom pom = new MavenPom(pluginCheckoutDir);
try {
addSplitPluginDependencies(plugin.name, mconfig, pluginCheckoutDir, pom, otherPlugins, pluginGroupIds, coreCoordinates.version, overridenPlugins);
addSplitPluginDependencies(plugin.name, mconfig, pluginCheckoutDir, pom, otherPlugins, pluginGroupIds, coreCoordinates.version, overridenPlugins, parentFolder);
} catch (Exception x) {
x.printStackTrace();
pomData.getWarningMessages().add(Functions.printThrowable(x));
Expand Down Expand Up @@ -892,14 +899,49 @@ private UpdateSite.Data newUpdateSiteData(UpdateSite us, JSONObject jsonO) throw
throw new RuntimeException("UpdateSite.Data instantiation problems", e);
}
}

/**
* Provides the Maven module used for a plugin on a {@code mvn [...] -pl} operation in the parent path
*/
public static String getMavenModule(String plugin, File pluginPath, MavenRunner runner, MavenRunner.Config mavenConfig) throws PomExecutionException, IOException {
String absolutePath = pluginPath.getAbsolutePath();
if (absolutePath.endsWith(plugin)) {
return plugin;
}
String module = absolutePath.substring(absolutePath.lastIndexOf(File.separatorChar) + 1, absolutePath.length());
File parentFile = pluginPath.getParentFile();
if (parentFile == null) {
return null;
}
File log = new File(parentFile.getAbsolutePath() + File.separatorChar + "modules.log");
runner.run(mavenConfig, parentFile, log, "-Dexpression=project.modules", "-q", "-DforceStdout", "help:evaluate");
for (String line : org.apache.commons.io.FileUtils.readLines(log)) {
if (!StringUtils.startsWith(line.trim(), "<string>")) {
continue;
}
String mvnModule = line.replace("<string>", "").replace("</string>", "").trim();
if (StringUtils.contains(mvnModule, module)) {
return mvnModule;
}
}
return null;
}

private void addSplitPluginDependencies(String thisPlugin, MavenRunner.Config mconfig, File pluginCheckoutDir, MavenPom pom, Map<String, Plugin> otherPlugins, Map<String, String> pluginGroupIds, String coreVersion, List<PCTPlugin> overridenPlugins) throws PomExecutionException, IOException {
private void addSplitPluginDependencies(String thisPlugin, MavenRunner.Config mconfig, File pluginCheckoutDir, MavenPom pom, Map<String, Plugin> otherPlugins, Map<String, String> pluginGroupIds, String coreVersion, List<PCTPlugin> overridenPlugins, String parentFolder) throws PomExecutionException, IOException {
File tmp = File.createTempFile("dependencies", ".log");
VersionNumber coreDep = null;
Map<String,VersionNumber> pluginDeps = new HashMap<>();
Map<String,VersionNumber> pluginDepsTest = new HashMap<>();
try {
runner.run(mconfig, pluginCheckoutDir, tmp, "dependency:resolve");
if (StringUtils.isBlank(parentFolder)) {
runner.run(mconfig, pluginCheckoutDir, tmp, "dependency:resolve");
} else {
String mavenModule = getMavenModule(thisPlugin, pluginCheckoutDir, runner, mconfig);
if (StringUtils.isBlank(mavenModule)) {
throw new IOException(String.format("Unable to retrieve the Maven module for plugin %s on %s", thisPlugin, pluginCheckoutDir));
}
runner.run(mconfig, pluginCheckoutDir.getParentFile(), tmp, "dependency:resolve", "-am", "-pl", mavenModule);
}
try (BufferedReader br =
Files.newBufferedReader(tmp.toPath(), Charset.defaultCharset())) {
Pattern p = Pattern.compile("\\[INFO\\]([^:]+):([^:]+):([a-z-]+):(([^:]+):)?([^:]+):(provided|compile|runtime|system)(\\(optional\\))?");
Expand Down Expand Up @@ -1028,7 +1070,6 @@ private void addSplitPluginDependencies(String thisPlugin, MavenRunner.Config mc
pom.removeDependency(pluginGroupIds.get(thisPlugin), thisPlugin);
}
}

private void checkDefinedDeps(Map<String,VersionNumber> pluginList, Map<String,VersionNumber> adding, Map<String,VersionNumber> replacing, Map<String,Plugin> otherPlugins) {
checkDefinedDeps(pluginList, adding, replacing, otherPlugins, new ArrayList<>(), null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public Map<String, Object> action(Map<String, Object> moreInfo) throws Exception
System.out.println("Child path for " + currentPlugin.getDisplayName() + " " + childPath);
moreInfo.put("checkoutDir", childPath);
moreInfo.put("pluginDir", childPath);
moreInfo.put("parentFolder", getParentFolder());
} else {
configureLocalCheckOut(currentPlugin, config.getLocalCheckoutDir(), moreInfo);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package org.jenkins.tools.test.hook;

import static org.jenkins.tools.test.PluginCompatTester.getMavenModule;
import static org.jenkins.tools.test.model.hook.PluginCompatTesterHooks.getHooksFromStage;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.jenkins.tools.test.exception.PomExecutionException;
import org.jenkins.tools.test.maven.ExternalMavenRunner;
import org.jenkins.tools.test.maven.MavenRunner;
Expand Down Expand Up @@ -43,8 +48,9 @@ public Map<String, Object> action(Map<String, Object> moreInfo) throws Exception
File pluginDir = (File) moreInfo.get("pluginDir");
System.out.println("Plugin dir is " + pluginDir);

if (config.getLocalCheckoutDir() != null) {
Path pluginSourcesDir = config.getLocalCheckoutDir().toPath();
File localCheckoutDir = config.getLocalCheckoutDir();
if (localCheckoutDir != null) {
Path pluginSourcesDir = localCheckoutDir.toPath();
boolean isMultipleLocalPlugins = config.getIncludePlugins() != null && config.getIncludePlugins().size() > 1;
// We are running for local changes, let's copy the .eslintrc file if we can
// If we are using localCheckoutDir with multiple plugins the .eslintrc must be located at the top level
Expand All @@ -62,7 +68,7 @@ public Map<String, Object> action(Map<String, Object> moreInfo) throws Exception
// only if the plugin is not already compiled
boolean ranCompile = moreInfo.containsKey(OVERRIDE_DEFAULT_COMPILE) && (boolean) moreInfo.get(OVERRIDE_DEFAULT_COMPILE);
if (!ranCompile) {
compile(mavenConfig, pluginDir);
compile(mavenConfig, pluginDir, localCheckoutDir, (String) moreInfo.get("parentFolder"), (String) moreInfo.get("pluginName"));
moreInfo.put(OVERRIDE_DEFAULT_COMPILE, true);
}

Expand Down Expand Up @@ -113,12 +119,53 @@ private MavenRunner.Config getMavenConfig(PluginCompatTesterConfig config) throw
return mconfig;
}

private void compile(MavenRunner.Config mavenConfig, File path) throws PomExecutionException, IOException {
private void compile(MavenRunner.Config mavenConfig, File path, File localCheckoutDir, String parentFolder, String pluginName) throws PomExecutionException, IOException {
if (isSnapshotMultiParentPlugin(parentFolder, path, localCheckoutDir)) {
// "process-test-classes" not working properly on multi-module plugin. See https://issues.jenkins.io/browse/JENKINS-62658
// installs dependencies into local repository
String mavenModule = getMavenModule(pluginName, path, runner, mavenConfig);
if (StringUtils.isBlank(mavenModule)) {
throw new IOException(String.format("Unable to retrieve the Maven module for plugin %s on %s", pluginName, path));
}
runner.run(mavenConfig, path.getParentFile(), setupCompileResources(path.getParentFile()), "clean", "install", "-DskipTests", "-Dinvoker.skip", "-Denforcer.skip", "-Dmaven.javadoc.skip", "-am", "-pl", mavenModule);
} else {
runner.run(mavenConfig, path, setupCompileResources(path), "clean", "process-test-classes", "-Dmaven.javadoc.skip");
}
}

/**
* Checks if a plugin is a multiparent plugin with a SNAPSHOT project.version and
* without local checkout directory overriden.
*/
private boolean isSnapshotMultiParentPlugin(String parentFolder, File path, File localCheckoutDir) throws PomExecutionException, IOException {
if (localCheckoutDir != null) {
return false;
}
if (StringUtils.isBlank(parentFolder)) {
return false;
}
if (!path.getAbsolutePath().contains(parentFolder)) {
System.out.println(String.format("Something is really wrong here! parentFolder:%s not present in path %s", parentFolder, path.getAbsolutePath()));
return false;
}
File parentFile = path.getParentFile();
if (!StringUtils.equals(parentFolder, parentFile.getName())) {
System.out.println(String.format("Something is really wrong here! %s is not the parent folder of %s", parentFolder, path.getAbsolutePath()));
return false;
}

File log = new File(parentFile.getAbsolutePath() + File.separatorChar + "version.log");
runner.run(mavenConfig, parentFile, log, "-Dexpression=project.version", "-q", "-DforceStdout", "help:evaluate");
List<String> output = FileUtils.readLines(log);
return output.get(output.size() - 1).endsWith("-SNAPSHOT");
}


private File setupCompileResources(File path) throws IOException {
System.out.println("Cleaning up node modules if necessary");
removeNodeFolders(path);
System.out.println("Compile plugin log in " + path);
File compilePomLogfile = new File(path + "/compilePluginLog.log");
runner.run(mavenConfig, path, compilePomLogfile, "clean", "process-test-classes", "-Dmaven.javadoc.skip");
return new File(path + "/compilePluginLog.log");
}

private void removeNodeFolders(File path) throws IOException {
Expand Down

0 comments on commit 5a9f15e

Please sign in to comment.