From 5d645086fdd03e6f1462298517134cf7766230bc Mon Sep 17 00:00:00 2001 From: Lukas Lieb Date: Wed, 18 Dec 2024 13:44:52 +0100 Subject: [PATCH] XIVY-10541 Detect different plugin versions --- .../ivy/maven/validate/ValidateMojo.java | 71 +++++++++++++++++ .../resources/META-INF/plexus/components.xml | 2 + .../ivy/maven/validate/TestValidateMojo.java | 77 +++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 src/main/java/ch/ivyteam/ivy/maven/validate/ValidateMojo.java create mode 100644 src/test/java/ch/ivyteam/ivy/maven/validate/TestValidateMojo.java diff --git a/src/main/java/ch/ivyteam/ivy/maven/validate/ValidateMojo.java b/src/main/java/ch/ivyteam/ivy/maven/validate/ValidateMojo.java new file mode 100644 index 00000000..225c2c14 --- /dev/null +++ b/src/main/java/ch/ivyteam/ivy/maven/validate/ValidateMojo.java @@ -0,0 +1,71 @@ +package ch.ivyteam.ivy.maven.validate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +@Mojo(name = ValidateMojo.GOAL, requiresProject = true) +public class ValidateMojo extends AbstractMojo { + + public static final String GOAL = "validate"; + protected static final String PLUGIN_GROUPID = "com.axonivy.ivy.ci"; + protected static final String PLUGIN_ARTIFACTID = "project-build-plugin"; + + @Parameter(defaultValue = "${session}", readonly = true, required = true) + private MavenSession session; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + validateConsistentPluginVersion(session.getAllProjects()); + } + + void validateConsistentPluginVersion(List projects) throws MojoExecutionException { + var versionToProjectsMap = new HashMap>(); + for (var project : projects) { + findProjectBuildPlugin(project.getBuild().getPlugins()).ifPresent(plugin -> { + var version = plugin.getVersion(); + getLog().debug(PLUGIN_GROUPID + ":" + plugin.getArtifactId() + ":" + version + " configured in " + project); + var projectSet = versionToProjectsMap.computeIfAbsent(version, v -> new LinkedHashSet<>()); + projectSet.add(project); + }); + } + if (versionToProjectsMap.size() > 1) { + var versions = new ArrayList<>(versionToProjectsMap.keySet()); + Collections.sort(versions); + var error = "Several versions of project-build-plugins are configured " + versions + ":\n"; + error += versions.stream().map(v -> versionProjects(versionToProjectsMap, v)).collect(Collectors.joining("\n")); + getLog().error(error); + throw new MojoExecutionException("All project-build-plugins configured in one reactor must use the same version"); + } + } + + private Optional findProjectBuildPlugin(List plugins) { + return plugins.stream() + .filter(p -> PLUGIN_GROUPID.equals(p.getGroupId()) && PLUGIN_ARTIFACTID.equals(p.getArtifactId())) + .filter(p -> p.getVersion() != null) // Skip plug-ins that do not have a version + .findFirst(); + } + + private String versionProjects(Map> versionToProjectsMap, String version) { + return version + " -> [" + + versionToProjectsMap.get(version).stream() + .map(p -> p.getArtifactId()) + .collect(Collectors.joining(", ")) + + "]"; + } +} diff --git a/src/main/resources/META-INF/plexus/components.xml b/src/main/resources/META-INF/plexus/components.xml index 4090b4ee..fea06809 100644 --- a/src/main/resources/META-INF/plexus/components.xml +++ b/src/main/resources/META-INF/plexus/components.xml @@ -10,6 +10,7 @@ com.axonivy.ivy.ci:project-build-plugin:maven-dependency-cleanup + com.axonivy.ivy.ci:project-build-plugin:validate com.axonivy.ivy.ci:project-build-plugin:installEngine com.axonivy.ivy.ci:project-build-plugin:ivy-resources-properties, @@ -38,6 +39,7 @@ + com.axonivy.ivy.ci:project-build-plugin:validate com.axonivy.ivy.ci:project-build-plugin:installEngine com.axonivy.ivy.ci:project-build-plugin:ivy-resources-properties, diff --git a/src/test/java/ch/ivyteam/ivy/maven/validate/TestValidateMojo.java b/src/test/java/ch/ivyteam/ivy/maven/validate/TestValidateMojo.java new file mode 100644 index 00000000..fa7fe966 --- /dev/null +++ b/src/test/java/ch/ivyteam/ivy/maven/validate/TestValidateMojo.java @@ -0,0 +1,77 @@ +package ch.ivyteam.ivy.maven.validate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; + +import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.junit.Rule; +import org.junit.Test; + +import ch.ivyteam.ivy.maven.ProjectMojoRule; +import ch.ivyteam.ivy.maven.log.LogCollector; + + +public class TestValidateMojo { + private ValidateMojo mojo; + + @Rule + public ProjectMojoRule rule = new ProjectMojoRule( + Path.of("src/test/resources/base"), ValidateMojo.GOAL) { + @Override + protected void before() throws Throwable { + super.before(); + TestValidateMojo.this.mojo = getMojo(); + } + }; + + @Test + public void samePluginVersions() throws Exception { + var log = new LogCollector(); + rule.getMojo().setLog(log); + var p1 = createMavenProject("project1", "12.0.0"); + var p2 = createMavenProject("project2", "12.0.0"); + mojo.validateConsistentPluginVersion(List.of(p1, p2)); + assertThat(log.getDebug()).hasSize(2); + assertThat(log.getDebug().get(0).toString()) + .contains("com.axonivy.ivy.ci:project-build-plugin:12.0.0 configured in MavenProject: group:project1:12.0.0-SNAPSHOT"); + assertThat(log.getDebug().get(1).toString()) + .contains("com.axonivy.ivy.ci:project-build-plugin:12.0.0 configured in MavenProject: group:project2:12.0.0-SNAPSHOT"); + assertThat(log.getErrors()).isEmpty(); + } + + @Test + public void differentPluginVersions() throws Exception { + var log = new LogCollector(); + rule.getMojo().setLog(log); + var p1 = createMavenProject("project1", "12.0.0"); + var p2 = createMavenProject("project2", "12.0.1"); + assertThatThrownBy(() -> mojo.validateConsistentPluginVersion(List.of(p1, p2))) + .isInstanceOf(MojoExecutionException.class); + assertThat(log.getErrors()).hasSize(1); + assertThat(log.getErrors().get(0).toString()) + .isEqualTo(""" + Several versions of project-build-plugins are configured [12.0.0, 12.0.1]: + 12.0.0 -> [project1] + 12.0.1 -> [project2]"""); + } + + private MavenProject createMavenProject(String projectId, String version) { + var project = new MavenProject(); + project.setGroupId("group"); + project.setArtifactId(projectId); + project.setVersion("12.0.0-SNAPSHOT"); + project.setFile(new File("src/test/resources/" + projectId)); + var plugin = new Plugin(); + plugin.setGroupId(ValidateMojo.PLUGIN_GROUPID); + plugin.setArtifactId(ValidateMojo.PLUGIN_ARTIFACTID); + plugin.setVersion(version); + project.getBuild().getPlugins().add(plugin); + return project; + } +}