diff --git a/pom.xml b/pom.xml index c6ec6c28..de5f87b5 100644 --- a/pom.xml +++ b/pom.xml @@ -229,6 +229,12 @@ under the License. verify ${project.build.directory}/local-repo src/it/settings.xml + + ${project.build.directory}/remote-repo + + + ${project.build.directory}/remote-repo + deploy diff --git a/src/it/deploy-at-end-pass/module2/pom.xml b/src/it/deploy-at-end-pass/module2/pom.xml new file mode 100644 index 00000000..827396fe --- /dev/null +++ b/src/it/deploy-at-end-pass/module2/pom.xml @@ -0,0 +1,39 @@ + + + + + + 4.0.0 + + + org.apache.maven.its.deploy.dae.pass + dae + 1.0 + + module2 + + + + + org.apache.maven.plugins + maven-deploy-plugin + + + default-deploy + none + + + + + + diff --git a/src/it/deploy-at-end-pass/module3/pom.xml b/src/it/deploy-at-end-pass/module3/pom.xml new file mode 100644 index 00000000..48c9caa0 --- /dev/null +++ b/src/it/deploy-at-end-pass/module3/pom.xml @@ -0,0 +1,25 @@ + + + + + + 4.0.0 + + + org.apache.maven.its.deploy.dae.pass + dae + 1.0 + + module3 + + diff --git a/src/it/deploy-at-end-pass/module4/pom.xml b/src/it/deploy-at-end-pass/module4/pom.xml new file mode 100644 index 00000000..05f07629 --- /dev/null +++ b/src/it/deploy-at-end-pass/module4/pom.xml @@ -0,0 +1,38 @@ + + + + + + 4.0.0 + + + org.apache.maven.its.deploy.dae.pass + dae + 1.0 + + module4 + + + without-deploy + + + + + org.apache.maven.its.deploy.mock + mock-phase-maven-plugin + 1.0 + true + + + + diff --git a/src/it/deploy-at-end-pass/pom.xml b/src/it/deploy-at-end-pass/pom.xml index 04250d5a..90ed655c 100644 --- a/src/it/deploy-at-end-pass/pom.xml +++ b/src/it/deploy-at-end-pass/pom.xml @@ -38,7 +38,7 @@ under the License. it - file:///${basedir}/target/repo + file:///@remoteRepo@/deploy-at-end-pass @@ -95,5 +95,8 @@ under the License. module1 + module2 + module3 + module4 diff --git a/src/it/deploy-at-end-pass/verify.groovy b/src/it/deploy-at-end-pass/verify.groovy index 634808a5..6aedbb57 100644 --- a/src/it/deploy-at-end-pass/verify.groovy +++ b/src/it/deploy-at-end-pass/verify.groovy @@ -17,10 +17,15 @@ * under the License. */ -assert new File( basedir, "target/repo/org/apache/maven/its/deploy/dae/pass/dae/1.0/dae-1.0.pom" ).exists() -assert new File( basedir, "module1/target/repo/org/apache/maven/its/deploy/dae/pass/module1/1.0/module1-1.0.pom" ).exists() +assert new File( remoteRepo, "deploy-at-end-pass/org/apache/maven/its/deploy/dae/pass/dae/1.0/dae-1.0.pom" ).exists() +assert new File( remoteRepo, "deploy-at-end-pass/org/apache/maven/its/deploy/dae/pass/module1/1.0/module1-1.0.pom" ).exists() +assert new File( remoteRepo, "deploy-at-end-pass/org/apache/maven/its/deploy/dae/pass/module1/1.0/module1-1.0.jar" ).exists() +assert new File( remoteRepo, "deploy-at-end-pass/org/apache/maven/its/deploy/dae/pass/module3/1.0/module3-1.0.pom" ).exists() +assert new File( remoteRepo, "deploy-at-end-pass/org/apache/maven/its/deploy/dae/pass/module3/1.0/module3-1.0.jar" ).exists() File buildLog = new File( basedir, 'build.log' ) assert buildLog.exists() assert buildLog.text.contains( "[INFO] Deferring deploy for org.apache.maven.its.deploy.dae.pass:dae:1.0 at end" ) +assert buildLog.text.contains( "[INFO] Deferring deploy for org.apache.maven.its.deploy.dae.pass:module1:1.0 at end" ) +assert buildLog.text.contains( "[INFO] Deferring deploy for org.apache.maven.its.deploy.dae.pass:module3:1.0 at end" ) diff --git a/src/it/setup-mock-phase-maven-plugin/invoker.properties b/src/it/setup-mock-phase-maven-plugin/invoker.properties new file mode 100644 index 00000000..d5d6ca5d --- /dev/null +++ b/src/it/setup-mock-phase-maven-plugin/invoker.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +invoker.goals = install diff --git a/src/it/setup-mock-phase-maven-plugin/pom.xml b/src/it/setup-mock-phase-maven-plugin/pom.xml new file mode 100644 index 00000000..4ebb8af5 --- /dev/null +++ b/src/it/setup-mock-phase-maven-plugin/pom.xml @@ -0,0 +1,57 @@ + + + + + + 4.0.0 + + org.apache.maven.its.deploy.mock + mock-phase-maven-plugin + 1.0 + maven-plugin + + + @mavenVersion@ + + + plugin with Maven phase without m-deploy-p + + + + + + org.apache.maven.plugins + maven-install-plugin + @mavenInstallPluginVersion@ + + + org.apache.maven.plugins + maven-plugin-plugin + @mavenPluginToolsVersion@ + + true + + + + + + + diff --git a/src/it/setup-mock-phase-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/src/it/setup-mock-phase-maven-plugin/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 00000000..93e017ca --- /dev/null +++ b/src/it/setup-mock-phase-maven-plugin/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,40 @@ + + + + + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + without-deploy + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + default + + org.apache.maven.plugins:maven-resources-plugin:resources + + + + + + + diff --git a/src/main/java/org/apache/maven/plugins/deploy/AbstractDeployMojo.java b/src/main/java/org/apache/maven/plugins/deploy/AbstractDeployMojo.java index 33ecad0b..2c5c1d9c 100644 --- a/src/main/java/org/apache/maven/plugins/deploy/AbstractDeployMojo.java +++ b/src/main/java/org/apache/maven/plugins/deploy/AbstractDeployMojo.java @@ -26,7 +26,6 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.rtinfo.RuntimeInformation; import org.eclipse.aether.RepositorySystem; -import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.deployment.DeployRequest; import org.eclipse.aether.deployment.DeploymentException; import org.eclipse.aether.repository.RemoteRepository; @@ -122,10 +121,13 @@ protected RemoteRepository getRemoteRepository(final String repositoryId, final return result; } - /** - * Handles high level retries (this was buried into MAT). - */ - protected void deploy(RepositorySystemSession session, DeployRequest deployRequest) throws MojoExecutionException { + // I'm not sure if retries will work with deploying on client level ... + // Most repository managers block a duplicate artifacts. + + // Eg, when we have an artifact list, even simple pom and jar in one request with released version, + // next try can fail due to duplicate. + + protected void deploy(DeployRequest deployRequest) throws MojoExecutionException { int retryFailedDeploymentCounter = Math.max(1, Math.min(10, retryFailedDeploymentCount)); DeploymentException exception = null; for (int count = 0; count < retryFailedDeploymentCounter; count++) { @@ -134,7 +136,7 @@ protected void deploy(RepositorySystemSession session, DeployRequest deployReque getLog().info("Retrying deployment attempt " + (count + 1) + " of " + retryFailedDeploymentCounter); } - repositorySystem.deploy(session, deployRequest); + repositorySystem.deploy(session.getRepositorySession(), deployRequest); exception = null; break; } catch (DeploymentException e) { diff --git a/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java b/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java index 09214174..806b3f33 100644 --- a/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java +++ b/src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java @@ -19,6 +19,8 @@ package org.apache.maven.plugins.deploy; import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -26,6 +28,8 @@ import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.descriptor.PluginDescriptor; @@ -34,10 +38,8 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.apache.maven.project.artifact.ProjectArtifact; -import org.apache.maven.project.artifact.ProjectArtifactMetadata; import org.eclipse.aether.deployment.DeployRequest; import org.eclipse.aether.repository.RemoteRepository; -import org.eclipse.aether.util.artifact.SubArtifact; /** * Deploys an artifact to remote repository. @@ -63,7 +65,6 @@ public class DeployMojo extends AbstractDeployMojo { /** * Whether every project should be deployed during its own deploy-phase or at the end of the multimodule build. If * set to {@code true} and the build fails, none of the reactor projects is deployed. - * (experimental) * * @since 2.8 */ @@ -176,17 +177,21 @@ public void execute() throws MojoExecutionException, MojoFailureException { warnIfAffectedPackagingAndMaven(project.getPackaging()); if (!deployAtEnd) { - deploy( - session.getRepositorySession(), - processProject( - project, - altSnapshotDeploymentRepository, - altReleaseDeploymentRepository, - altDeploymentRepository)); + + RemoteRepository deploymentRepository = getDeploymentRepository( + project, + altSnapshotDeploymentRepository, + altReleaseDeploymentRepository, + altDeploymentRepository); + + DeployRequest request = new DeployRequest(); + request.setRepository(deploymentRepository); + processProject(project, request); + deploy(request); putState(State.DEPLOYED); } else { - putPluginContextValue(DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY, altReleaseDeploymentRepository); putPluginContextValue(DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY, altSnapshotDeploymentRepository); + putPluginContextValue(DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY, altReleaseDeploymentRepository); putPluginContextValue(DEPLOY_ALT_DEPLOYMENT_REPOSITORY, altDeploymentRepository); putState(State.TO_BE_DEPLOYED); getLog().info("Deferring deploy for " + project.getGroupId() + ":" + project.getArtifactId() + ":" @@ -194,32 +199,41 @@ public void execute() throws MojoExecutionException, MojoFailureException { } } - if (allProjectsMarked()) { - for (MavenProject reactorProject : reactorProjects) { + List allProjectsUsingPlugin = getAllProjectsUsingPlugin(); + + if (allProjectsMarked(allProjectsUsingPlugin)) { + Map requests = new LinkedHashMap<>(); + + // collect all arifacts from all modules to deploy + // requests are grouped by used remote repository + for (MavenProject reactorProject : allProjectsUsingPlugin) { Map pluginContext = session.getPluginContext(pluginDescriptor, reactorProject); State state = getState(pluginContext); if (state == State.TO_BE_DEPLOYED) { - String altReleaseDeploymentRepository = - getPluginContextValue(pluginContext, DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY); - String altSnapshotDeploymentRepository = - getPluginContextValue(pluginContext, DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY); - String altDeploymentRepository = - getPluginContextValue(pluginContext, DEPLOY_ALT_DEPLOYMENT_REPOSITORY); - - deploy( - session.getRepositorySession(), - processProject( - reactorProject, - altSnapshotDeploymentRepository, - altReleaseDeploymentRepository, - altDeploymentRepository)); + + RemoteRepository deploymentRepository = getDeploymentRepository( + reactorProject, + getPluginContextValue(pluginContext, DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY), + getPluginContextValue(pluginContext, DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY), + getPluginContextValue(pluginContext, DEPLOY_ALT_DEPLOYMENT_REPOSITORY)); + + DeployRequest request = requests.computeIfAbsent(deploymentRepository, repo -> { + DeployRequest newRequest = new DeployRequest(); + newRequest.setRepository(repo); + return newRequest; + }); + processProject(reactorProject, request); } } + // finally execute all deployments request, lets resolver to optimize deployment + for (DeployRequest request : requests.values()) { + deploy(request); + } } } - private boolean allProjectsMarked() { - for (MavenProject reactorProject : reactorProjects) { + private boolean allProjectsMarked(List allProjectsUsingPlugin) { + for (MavenProject reactorProject : allProjectsUsingPlugin) { if (!hasState(reactorProject)) { return false; } @@ -227,61 +241,58 @@ private boolean allProjectsMarked() { return true; } - private DeployRequest processProject( - final MavenProject project, - final String altSnapshotDeploymentRepository, - final String altReleaseDeploymentRepository, - final String altDeploymentRepository) - throws MojoExecutionException, MojoFailureException { - DeployRequest request = new DeployRequest(); - request.setRepository(getDeploymentRepository( - project, altSnapshotDeploymentRepository, altReleaseDeploymentRepository, altDeploymentRepository)); + private List getAllProjectsUsingPlugin() { + ArrayList result = new ArrayList<>(); + for (MavenProject reactorProject : reactorProjects) { + if (hasExecution(reactorProject.getPlugin("org.apache.maven.plugins:maven-deploy-plugin"))) { + result.add(reactorProject); + } + } + return result; + } + + private boolean hasExecution(Plugin plugin) { + if (plugin == null) { + return false; + } + + for (PluginExecution execution : plugin.getExecutions()) { + if (!execution.getGoals().isEmpty() && !"none".equalsIgnoreCase(execution.getPhase())) { + return true; + } + } + return false; + } - org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact(); - String packaging = project.getPackaging(); - File pomFile = project.getFile(); - boolean isPomArtifact = "pom".equals(packaging); - boolean pomArtifactAttached = false; + private void processProject(final MavenProject project, DeployRequest request) throws MojoExecutionException { - if (pomFile != null) { + if (isFile(project.getFile())) { request.addArtifact(RepositoryUtils.toArtifact(new ProjectArtifact(project))); - pomArtifactAttached = true; + } else { + throw new MojoExecutionException("The project POM could not be attached"); } - if (!isPomArtifact) { - File file = mavenMainArtifact.getFile(); - if (file != null && file.isFile()) { - org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact(mavenMainArtifact); - request.addArtifact(mainArtifact); - - if (!pomArtifactAttached) { - for (Object metadata : mavenMainArtifact.getMetadataList()) { - if (metadata instanceof ProjectArtifactMetadata) { - request.addArtifact(new SubArtifact(mainArtifact, "", "pom") - .setFile(((ProjectArtifactMetadata) metadata).getFile())); - pomArtifactAttached = true; - } - } - } + if (!"pom".equals(project.getPackaging())) { + org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact(); + if (isFile(mavenMainArtifact.getFile())) { + request.addArtifact(RepositoryUtils.toArtifact(mavenMainArtifact)); } else if (!project.getAttachedArtifacts().isEmpty()) { throw new MojoExecutionException("The packaging plugin for this project did not assign " + "a main file to the project but it has attachments. Change packaging to 'pom'."); } else { throw new MojoExecutionException( - "The packaging for this project did not assign " + "a file to the build artifact"); + "The packaging for this project did not assign a file to the build artifact"); } } - if (!pomArtifactAttached) { - throw new MojoExecutionException("The POM could not be attached"); - } - for (org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts()) { - getLog().debug("Attaching for install: " + attached.getId()); + getLog().debug("Attaching for deploy: " + attached.getId()); request.addArtifact(RepositoryUtils.toArtifact(attached)); } + } - return request; + private boolean isFile(File file) { + return file != null && file.isFile(); } /** diff --git a/src/test/java/org/apache/maven/plugins/deploy/stubs/MavenProjectStub.java b/src/test/java/org/apache/maven/plugins/deploy/stubs/MavenProjectStub.java index ff97f913..646e09ad 100644 --- a/src/test/java/org/apache/maven/plugins/deploy/stubs/MavenProjectStub.java +++ b/src/test/java/org/apache/maven/plugins/deploy/stubs/MavenProjectStub.java @@ -18,7 +18,11 @@ */ package org.apache.maven.plugins.deploy.stubs; +import java.util.Collections; + import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.model.Build; +import org.apache.maven.model.Plugin; public class MavenProjectStub extends org.apache.maven.plugin.testing.stubs.MavenProjectStub { @@ -27,4 +31,12 @@ public class MavenProjectStub extends org.apache.maven.plugin.testing.stubs.Mave public ArtifactRepository getDistributionManagementArtifactRepository() { return deploymentRepository; } + + @Override + public Build getBuild() { + Plugin plugin = new Plugin(); + Build build = new Build(); + build.setPlugins(Collections.singletonList(plugin)); + return build; + } }