From dab778a33e951c7de739aad027b23811c8d2dd4f Mon Sep 17 00:00:00 2001 From: slandelle Date: Fri, 12 Jan 2024 17:58:37 +0100 Subject: [PATCH] feat: enterprise package generation rework --- pom.xml | 13 +- .../io/gatling/mojo/AbstractGatlingMojo.java | 24 +- .../gatling/mojo/DeprecatedFrontLineMojo.java | 41 --- .../gatling/mojo/EnterprisePackageMojo.java | 265 ++++-------------- .../io/gatling/mojo/EnterpriseStartMojo.java | 5 +- .../io/gatling/mojo/EnterpriseUploadMojo.java | 5 +- .../java/io/gatling/mojo/GatlingMojo.java | 2 - .../java/io/gatling/mojo/MojoConstants.java | 12 +- src/main/java/io/gatling/mojo/MojoUtils.java | 27 +- 9 files changed, 73 insertions(+), 321 deletions(-) delete mode 100644 src/main/java/io/gatling/mojo/DeprecatedFrontLineMojo.java diff --git a/pom.xml b/pom.xml index 04249ed3..53553257 100644 --- a/pom.xml +++ b/pom.xml @@ -44,10 +44,9 @@ UTF-8 11 3.0 - 3.4.2 ${project.basedir} 5.10.1 - 1.16 + 1.9.0-M4 1.6.13 3.11.0 @@ -80,16 +79,6 @@ ${maven3.version} provided - - org.codehaus.plexus - plexus-utils - ${plexus-utils.version} - - - org.zeroturnaround - zt-zip - ${zt-zip.version} - io.gatling gatling-enterprise-plugin-commons diff --git a/src/main/java/io/gatling/mojo/AbstractGatlingMojo.java b/src/main/java/io/gatling/mojo/AbstractGatlingMojo.java index fd0cd674..0bfdf25a 100644 --- a/src/main/java/io/gatling/mojo/AbstractGatlingMojo.java +++ b/src/main/java/io/gatling/mojo/AbstractGatlingMojo.java @@ -25,10 +25,8 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; @@ -38,9 +36,6 @@ public abstract class AbstractGatlingMojo extends AbstractMojo { - private static final String FRONTLINE_MAVEN_PLUGIN_GROUP_ID = "io.gatling.frontline"; - private static final String FRONTLINE_MAVEN_PLUGIN_ARTIFACT_ID = "frontline-maven-plugin"; - /** Use this folder as the configuration directory. */ @Parameter( property = "gatling.configFolder", @@ -66,23 +61,6 @@ public abstract class AbstractGatlingMojo extends AbstractMojo { /** Maven's repository. */ @Component protected RepositorySystem repository; - protected void checkPluginPreConditions() throws MojoFailureException { - final boolean obsoletePluginFound = - mavenProject.getPluginArtifacts().stream().anyMatch(AbstractGatlingMojo::isFrontLinePlugin); - if (obsoletePluginFound) { - throw new MojoFailureException( - "Plugin `frontline-maven-plugin` is no longer needed, its functionality is now included in `gatling-maven-plugin`.\n" - + "Please remove `frontline-maven-plugin` from your pom.xml plugins configuration.\n" - + "Please use gatling:enterprisePackage instead of configuring it on package phase.\n" - + "See https://gatling.io/docs/gatling/reference/current/extensions/maven_plugin/ for more information "); - } - } - - private static boolean isFrontLinePlugin(Artifact artifact) { - return artifact.getGroupId().equals(FRONTLINE_MAVEN_PLUGIN_GROUP_ID) - && artifact.getArtifactId().equals(FRONTLINE_MAVEN_PLUGIN_ARTIFACT_ID); - } - protected List buildTestClasspath() throws Exception { List testClasspathElements = new ArrayList<>(); testClasspathElements.addAll(mavenProject.getTestClasspathElements()); @@ -100,7 +78,7 @@ protected void addArg(List args, String flag, Object value) { } } - private PluginLogger newPluginLogger() { + protected PluginLogger newPluginLogger() { return new PluginLogger() { @Override public void info(String message) { diff --git a/src/main/java/io/gatling/mojo/DeprecatedFrontLineMojo.java b/src/main/java/io/gatling/mojo/DeprecatedFrontLineMojo.java deleted file mode 100644 index 0e803df3..00000000 --- a/src/main/java/io/gatling/mojo/DeprecatedFrontLineMojo.java +++ /dev/null @@ -1,41 +0,0 @@ - -/* - * Copyright 2011-2022 GatlingCorp (https://gatling.io) - * - * 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 io.gatling.mojo; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.ResolutionScope; - -/** Deprecated, see gatling:enterprisePackage instead. */ -@Deprecated -@Mojo( - name = "package", - defaultPhase = LifecyclePhase.PACKAGE, - requiresDependencyResolution = ResolutionScope.TEST) -public class DeprecatedFrontLineMojo extends EnterprisePackageMojo { - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - getLog() - .warn( - "Deprecated configuration. Use 'mvn gatling:enterprisePackage' instead.\n" - + "See https://gatling.io/docs/gatling/reference/current/extensions/maven_plugin/ for more informations."); - super.execute(); - } -} diff --git a/src/main/java/io/gatling/mojo/EnterprisePackageMojo.java b/src/main/java/io/gatling/mojo/EnterprisePackageMojo.java index d9a7a58f..78f1ff76 100644 --- a/src/main/java/io/gatling/mojo/EnterprisePackageMojo.java +++ b/src/main/java/io/gatling/mojo/EnterprisePackageMojo.java @@ -18,22 +18,18 @@ import static io.gatling.mojo.MojoConstants.*; +import io.gatling.plugin.io.PluginLogger; +import io.gatling.plugin.pkg.Dependency; +import io.gatling.plugin.pkg.EnterprisePackager; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.*; import org.apache.maven.project.MavenProjectHelper; -import org.codehaus.plexus.util.SelectorUtils; -import org.zeroturnaround.zip.ZipUtil; -import org.zeroturnaround.zip.commons.FileUtilsV2_2; /** Mojo to package Gatling simulations to run on Gatling Enterprise (Cloud or Self-Hosted). */ @Execute(phase = LifecyclePhase.TEST_COMPILE) @@ -42,228 +38,77 @@ defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.TEST) public class EnterprisePackageMojo extends AbstractEnterpriseMojo { + private static final String MAVEN_PACKAGER_NAME = "maven"; + private static final Set GATLING_GROUP_IDS = + Set.of(GATLING_GROUP_ID, GATLING_HIGHCHARTS_GROUP_ID); - private static final List ALWAYS_EXCLUDES = - toChars( - new String[] { - "module-info.class", - "LICENSE", - "META-INF/LICENSE", - "META-INF/MANIFEST.MF", - "META-INF/versions/**", - "META-INF/maven/**", - "*.SF", - "*.DSA", - "*.RSA" - }); - - private static final Set EXCLUDED_NETTY_ARTIFACTS; - - static { - Set excludedNettyArtifacts = new HashSet<>(); - excludedNettyArtifacts.add("netty-all"); - excludedNettyArtifacts.add("netty-resolver-dns-classes-macos"); - excludedNettyArtifacts.add("netty-resolver-dns-native-macos"); - EXCLUDED_NETTY_ARTIFACTS = Collections.unmodifiableSet(excludedNettyArtifacts); - } - + private final PluginLogger pluginLogger = newPluginLogger(); @Component private MavenProjectHelper projectHelper; - /** - * List of exclude patterns to use when scanning for simulation classes. Excludes none by default. - */ - @Parameter(property = "gatling.excludes") - private String[] excludes; - - private Set nonGatlingDependencies(List artifacts) { - return artifacts.stream() - .flatMap( - artifact -> - resolveTransitively(artifact).stream() - .filter(art -> !GATLING_GROUP_IDS.contains(art.getGroupId()))) - .collect(Collectors.toSet()); - } - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - checkPluginPreConditions(); - - Set allDeps = mavenProject.getArtifacts(); + public void execute() throws MojoExecutionException { + Set allArtifacts = getAllArtifacts(); - List depsWithFrontLineGroupId = - MojoUtils.findByGroupId(allDeps, GATLING_FRONTLINE_GROUP_ID); - if (!depsWithFrontLineGroupId.isEmpty()) { - throw new MojoExecutionException( - "Found a dependency with group id " - + GATLING_FRONTLINE_GROUP_ID - + " in projects dependencies"); - } - - List depsWithGatlingGroupId = MojoUtils.findByGroupId(allDeps, GATLING_GROUP_ID); - List depsWithGatlingHighchartsGroupId = - MojoUtils.findByGroupId(allDeps, GATLING_HIGHCHARTS_GROUP_ID); - if (depsWithGatlingGroupId.isEmpty()) { - throw new MojoExecutionException( - "Couldn't find any dependencies with group id " - + GATLING_GROUP_ID - + " in project dependencies"); - } + List gatlingArtifacts = + allArtifacts.stream() + .filter(artifact -> GATLING_GROUP_IDS.contains(artifact.getGroupId())) + .collect(Collectors.toList()); - Set gatlingDependencies = new HashSet<>(); - gatlingDependencies.addAll(nonGatlingDependencies(depsWithGatlingGroupId)); - gatlingDependencies.addAll(nonGatlingDependencies(depsWithGatlingHighchartsGroupId)); - - Set filteredDeps = - allDeps.stream() - .filter( - artifact -> - !artifact.getType().equals("pom") - && !GATLING_GROUP_IDS.contains(artifact.getGroupId()) - && !(artifact.getGroupId().equals("io.netty") - && EXCLUDED_NETTY_ARTIFACTS.contains(artifact.getArtifactId())) - && MojoUtils.artifactNotIn(artifact, gatlingDependencies)) + Set gatlingDependencies = + gatlingArtifacts.stream() + .map(EnterprisePackageMojo::artifactToDependency) .collect(Collectors.toSet()); - File workingDir; - try { - workingDir = Files.createTempDirectory("gatling-maven").toFile(); - } catch (IOException e) { - throw new MojoExecutionException("Failed to create temp dir", e); - } - - List compiledExcludes = compileExcludes(); + Set extraDependencies = getExtraDependencies(allArtifacts, gatlingArtifacts); - // extract dep jars - for (Artifact artifact : filteredDeps) { - ZipUtil.unpack( - artifact.getFile(), workingDir, name -> exclude(name, compiledExcludes) ? null : name); - } + List classDirectories = + List.of( + new File(mavenProject.getBuild().getOutputDirectory()), + new File(mavenProject.getBuild().getTestOutputDirectory())); - // copy compiled classes - File outputDirectory = new File(mavenProject.getBuild().getOutputDirectory()); - Path outputDirectoryPath = outputDirectory.toPath(); - File testOutputDirectory = new File(mavenProject.getBuild().getTestOutputDirectory()); - Path testOutputDirectoryPath = testOutputDirectory.toPath(); + File enterprisePackage = enterprisePackage(); try { - if (outputDirectory.exists()) { - FileUtilsV2_2.copyDirectory( - outputDirectory, - workingDir, - pathname -> - !exclude( - outputDirectoryPath.relativize(pathname.toPath()).toString(), compiledExcludes), - false); - } - if (testOutputDirectory.exists()) { - FileUtilsV2_2.copyDirectory( - testOutputDirectory, - workingDir, - pathname -> - !exclude( - testOutputDirectoryPath.relativize(pathname.toPath()).toString(), - compiledExcludes), - false); - } + new EnterprisePackager(pluginLogger) + .createEnterprisePackage( + classDirectories, + gatlingDependencies, + extraDependencies, + mavenProject.getGroupId(), + mavenProject.getArtifactId(), + mavenProject.getVersion(), + MAVEN_PACKAGER_NAME, + getClass().getPackage().getImplementationVersion(), + enterprisePackage); } catch (IOException e) { - throw new MojoExecutionException("Failed to copy compiled classes", e); + throw new MojoExecutionException("Failed to generate Enterprise package", e); } - // generate META-INF directory - File metaInfDir = new File(workingDir, "META-INF"); - metaInfDir.mkdirs(); - - // generate maven files directory - File mavenDir = - new File( - new File(new File(metaInfDir, "maven"), mavenProject.getGroupId()), - mavenProject.getArtifactId()); - mavenDir.mkdirs(); - - // generate pom.properties - try (FileWriter fw = new FileWriter(new File(mavenDir, "pom.properties"))) { - fw.write("groupId=" + mavenProject.getGroupId() + "\n"); - fw.write("artifactId=" + mavenProject.getArtifactId() + "\n"); - fw.write("version=" + mavenProject.getVersion() + "\n"); - } catch (IOException e) { - throw new MojoExecutionException("Failed to generate pom.properties", e); - } - - // generate pom.xml - try (FileWriter fw = new FileWriter(new File(mavenDir, "pom.xml"))) { - fw.write("" + "\n"); - fw.write( - "" - + "\n"); - fw.write(" 4.0.0" + "\n"); - fw.write(" " + mavenProject.getGroupId() + "" + "\n"); - fw.write(" " + mavenProject.getArtifactId() + "" + "\n"); - fw.write(" " + mavenProject.getVersion() + "" + "\n"); - fw.write(""); - } catch (IOException e) { - throw new MojoExecutionException("Failed to generate pom.properties", e); - } - - // generate fake manifest - File manifest = new File(metaInfDir, "MANIFEST.MF"); - - String gatlingVersion = - MojoUtils.findByGroupIdAndArtifactId(allDeps, GATLING_GROUP_ID, GATLING_MODULE_APP) - .getVersion(); - - try (FileWriter fw = new FileWriter(manifest)) { - fw.write("Manifest-Version: 1.0\n"); - fw.write("Implementation-Title: " + mavenProject.getArtifactId() + "\n"); - fw.write("Implementation-Version: " + mavenProject.getVersion() + "\n"); - fw.write("Implementation-Vendor: " + mavenProject.getGroupId() + "\n"); - fw.write("Specification-Vendor: GatlingCorp\n"); - fw.write("Gatling-Version: " + gatlingVersion + "\n"); - fw.write("Gatling-Packager: maven" + "\n"); - } catch (IOException e) { - throw new MojoExecutionException("Failed to generate manifest", e); - } - - File shaded = enterprisePackage(); - - // generate jar - getLog().info("Generating Gatling Enterprise package " + shaded); - ZipUtil.pack(workingDir, shaded); - // attach jar so it can be deployed - projectHelper.attachArtifact(mavenProject, "jar", SHADED_CLASSIFIER, shaded); - - try { - FileUtilsV2_2.deleteDirectory(workingDir); - } catch (IOException e) { - throw new MojoExecutionException("Failed to delete working directory " + workingDir, e); - } + projectHelper.attachArtifact(mavenProject, "jar", SHADED_CLASSIFIER, enterprisePackage); } - private static List toChars(String[] patterns) { - return Arrays.stream(patterns).map(String::toCharArray).collect(Collectors.toList()); - } + private Set getExtraDependencies( + Set allDeps, List gatlingArtifacts) { + Set gatlingAndTransitiveDependencies = + gatlingAndTransitiveDependencies(gatlingArtifacts); - private List compileExcludes() { - if (excludes == null) { - return ALWAYS_EXCLUDES; - } + return allDeps.stream() + .filter(artifact -> MojoUtils.artifactNotIn(artifact, gatlingAndTransitiveDependencies)) + .map(EnterprisePackageMojo::artifactToDependency) + .collect(Collectors.toSet()); + } - List compiledUserExcludes = toChars(excludes); - compiledUserExcludes.addAll(ALWAYS_EXCLUDES); - return compiledUserExcludes; + private Set getAllArtifacts() { + return mavenProject.getArtifacts().stream() + .filter(artifact -> !artifact.getType().equals("pom")) + .collect(Collectors.toSet()); } - private boolean exclude(String name, List excludes) { - for (char[] pattern : excludes) { - if (SelectorUtils.match(pattern, name.toCharArray(), false)) { - getLog().info("Excluding file " + name); - return true; - } - } - return false; + private Set gatlingAndTransitiveDependencies(List artifacts) { + return artifacts.stream() + .flatMap(artifact -> resolveTransitively(artifact).stream()) + .collect(Collectors.toSet()); } private Set resolveTransitively(Artifact artifact) { @@ -277,6 +122,12 @@ private Set resolveTransitively(Artifact artifact) { .setProxies(session.getRequest().getProxies()) .setLocalRepository(session.getLocalRepository()) .setRemoteRepositories(session.getCurrentProject().getRemoteArtifactRepositories()); + return repository.resolve(request).getArtifacts(); } + + private static Dependency artifactToDependency(Artifact artifact) { + return new Dependency( + artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getFile()); + } } diff --git a/src/main/java/io/gatling/mojo/EnterpriseStartMojo.java b/src/main/java/io/gatling/mojo/EnterpriseStartMojo.java index 8707d474..06518b78 100644 --- a/src/main/java/io/gatling/mojo/EnterpriseStartMojo.java +++ b/src/main/java/io/gatling/mojo/EnterpriseStartMojo.java @@ -26,7 +26,6 @@ import java.util.Collections; import java.util.Map; import java.util.UUID; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.Mojo; @@ -119,9 +118,7 @@ public final class EnterpriseStartMojo extends AbstractEnterprisePluginMojo { private boolean waitForRunEnd; @Override - public void execute() throws MojoExecutionException, MojoFailureException { - checkPluginPreConditions(); - + public void execute() throws MojoFailureException { final UUID teamIdUuid = teamId != null ? UUID.fromString(teamId) : null; final UUID packageIdUuid = packageId != null ? UUID.fromString(packageId) : null; if (simulationSystemProperties == null) { diff --git a/src/main/java/io/gatling/mojo/EnterpriseUploadMojo.java b/src/main/java/io/gatling/mojo/EnterpriseUploadMojo.java index f7ba92af..18199eb7 100644 --- a/src/main/java/io/gatling/mojo/EnterpriseUploadMojo.java +++ b/src/main/java/io/gatling/mojo/EnterpriseUploadMojo.java @@ -19,7 +19,6 @@ import io.gatling.plugin.BatchEnterprisePlugin; import java.io.File; import java.util.UUID; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.Mojo; @@ -51,9 +50,7 @@ public final class EnterpriseUploadMojo extends AbstractEnterprisePluginMojo { private String simulationId; @Override - public void execute() throws MojoExecutionException, MojoFailureException { - checkPluginPreConditions(); - + public void execute() throws MojoFailureException { if (packageId == null && simulationId == null) { final String msg = "Missing packageID\n" diff --git a/src/main/java/io/gatling/mojo/GatlingMojo.java b/src/main/java/io/gatling/mojo/GatlingMojo.java index 88f9fd81..b557faac 100644 --- a/src/main/java/io/gatling/mojo/GatlingMojo.java +++ b/src/main/java/io/gatling/mojo/GatlingMojo.java @@ -139,8 +139,6 @@ public final class GatlingMojo extends AbstractGatlingExecutionMojo { /** Executes Gatling simulations. */ @Override public void execute() throws MojoExecutionException, MojoFailureException { - checkPluginPreConditions(); - if (skip) { getLog().info("Skipping gatling-maven-plugin"); return; diff --git a/src/main/java/io/gatling/mojo/MojoConstants.java b/src/main/java/io/gatling/mojo/MojoConstants.java index 25de90d7..91e01b73 100644 --- a/src/main/java/io/gatling/mojo/MojoConstants.java +++ b/src/main/java/io/gatling/mojo/MojoConstants.java @@ -30,14 +30,6 @@ private MojoConstants() {} static final String GATLING_GROUP_ID = "io.gatling"; static final String GATLING_MODULE_APP = "gatling-app"; static final String GATLING_HIGHCHARTS_GROUP_ID = "io.gatling.highcharts"; - static final String GATLING_FRONTLINE_GROUP_ID = "io.gatling.frontline"; - static final Set GATLING_GROUP_IDS; - - static { - HashSet groupIds = new HashSet<>(); - groupIds.add(GATLING_GROUP_ID); - groupIds.add(GATLING_HIGHCHARTS_GROUP_ID); - groupIds.add(GATLING_FRONTLINE_GROUP_ID); - GATLING_GROUP_IDS = Collections.unmodifiableSet(groupIds); - } + static final Set GATLING_GROUP_IDS = + Set.of(GATLING_GROUP_ID, GATLING_HIGHCHARTS_GROUP_ID); } diff --git a/src/main/java/io/gatling/mojo/MojoUtils.java b/src/main/java/io/gatling/mojo/MojoUtils.java index 57e14a4e..4f92ed49 100644 --- a/src/main/java/io/gatling/mojo/MojoUtils.java +++ b/src/main/java/io/gatling/mojo/MojoUtils.java @@ -22,17 +22,13 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.apache.maven.artifact.Artifact; public final class MojoUtils { @@ -116,24 +112,19 @@ public static URL getURL(File file) throws MalformedURLException { return new URL(file.toURI().toASCIIString()); } - static boolean artifactNotIn(Artifact target, Set artifacts) { + static boolean artifactNotIn(Artifact target, Collection artifacts) { return findByGroupIdAndArtifactId(artifacts, target.getGroupId(), target.getArtifactId()) == null; } static Artifact findByGroupIdAndArtifactId( - Set artifacts, String groupId, String artifactId) { - for (Artifact artifact : artifacts) { - if (artifact.getGroupId().equals(groupId) && artifact.getArtifactId().equals(artifactId)) { - return artifact; - } - } - return null; - } - - static List findByGroupId(Set artifacts, String groupId) { + Collection artifacts, String groupId, String artifactId) { return artifacts.stream() - .filter(artifact -> artifact.getGroupId().equals(groupId)) - .collect(Collectors.toList()); + .filter( + artifact -> + artifact.getGroupId().equals(groupId) + && artifact.getArtifactId().equals(artifactId)) + .findFirst() + .orElse(null); } }