View Javadoc
1   package org.apache.maven.plugins.deploy;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.concurrent.atomic.AtomicInteger;
26  import java.util.regex.Matcher;
27  import java.util.regex.Pattern;
28  
29  import org.apache.maven.artifact.ArtifactUtils;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.plugins.annotations.Component;
34  import org.apache.maven.plugins.annotations.LifecyclePhase;
35  import org.apache.maven.plugins.annotations.Mojo;
36  import org.apache.maven.plugins.annotations.Parameter;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuildingRequest;
39  import org.apache.maven.shared.transfer.artifact.deploy.ArtifactDeployerException;
40  import org.apache.maven.shared.transfer.project.NoFileAssignedException;
41  import org.apache.maven.shared.transfer.project.deploy.ProjectDeployer;
42  import org.apache.maven.shared.transfer.project.deploy.ProjectDeployerRequest;
43  
44  /**
45   * Deploys an artifact to remote repository.
46   * 
47   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
48   * @author <a href="mailto:jdcasey@apache.org">John Casey (refactoring only)</a>
49   */
50  @Mojo( name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, threadSafe = true )
51  public class DeployMojo
52      extends AbstractDeployMojo
53  {
54      private static final Pattern ALT_LEGACY_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+?)::(.+?)::(.+)" );
55  
56      private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+?)::(.+)" );
57  
58      /**
59       * When building with multiple threads, reaching the last project doesn't have to mean that all projects are ready
60       * to be deployed
61       */
62      private static final AtomicInteger READYPROJECTSCOUNTER = new AtomicInteger();
63  
64      private static final List<ProjectDeployerRequest> DEPLOYREQUESTS =
65          Collections.synchronizedList( new ArrayList<ProjectDeployerRequest>() );
66  
67      /**
68       */
69      @Parameter( defaultValue = "${project}", readonly = true, required = true )
70      private MavenProject project;
71  
72      @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
73      private List<MavenProject> reactorProjects;
74  
75      /**
76       * Whether every project should be deployed during its own deploy-phase or at the end of the multimodule build. If
77       * set to {@code true} and the build fails, none of the reactor projects is deployed.
78       * <strong>(experimental)</strong>
79       * 
80       * @since 2.8
81       */
82      @Parameter( defaultValue = "false", property = "deployAtEnd" )
83      private boolean deployAtEnd;
84  
85      /**
86       * Specifies an alternative repository to which the project artifacts should be deployed (other than those specified
87       * in &lt;distributionManagement&gt;). <br/>
88       * Format: <code>id::url</code>
89       * <dl>
90       * <dt>id</dt>
91       * <dd>The id can be used to pick up the correct credentials from the settings.xml</dd>
92       * <dt>url</dt>
93       * <dd>The location of the repository</dd>
94       * </dl>
95       * <b>Note:</b> In version 2.x, the format was <code>id::<i>layout</i>::url</code> where <code><i>layout</i></code>
96       * could be <code>default</code> (ie. Maven 2) or <code>legacy</code> (ie. Maven 1), but since 3.0.0 the layout part
97       * has been removed because Maven 3 only supports Maven 2 repository layout.
98       */
99      @Parameter( property = "altDeploymentRepository" )
100     private String altDeploymentRepository;
101 
102     /**
103      * The alternative repository to use when the project has a snapshot version.
104      *
105      * <b>Note:</b> In version 2.x, the format was <code>id::<i>layout</i>::url</code> where <code><i>layout</i></code>
106      * could be <code>default</code> (ie. Maven 2) or <code>legacy</code> (ie. Maven 1), but since 3.0.0 the layout part
107      * has been removed because Maven 3 only supports Maven 2 repository layout.
108      * @since 2.8
109      * @see DeployMojo#altDeploymentRepository
110      */
111     @Parameter( property = "altSnapshotDeploymentRepository" )
112     private String altSnapshotDeploymentRepository;
113 
114     /**
115      * The alternative repository to use when the project has a final version.
116      *
117      * <b>Note:</b> In version 2.x, the format was <code>id::<i>layout</i>::url</code> where <code><i>layout</i></code>
118      * could be <code>default</code> (ie. Maven 2) or <code>legacy</code> (ie. Maven 1), but since 3.0.0 the layout part
119      * has been removed because Maven 3 only supports Maven 2 repository layout.
120      * @since 2.8
121      * @see DeployMojo#altDeploymentRepository
122      */
123     @Parameter( property = "altReleaseDeploymentRepository" )
124     private String altReleaseDeploymentRepository;
125 
126     /**
127      * Set this to 'true' to bypass artifact deploy
128      * Since since 3.0.0-M2 it's not anymore a real boolean as it can have more than 2 values:
129      * <ul>
130      *     <li><code>true</code>: will skip as usual</li>
131      *     <li><code>releases</code>: will skip if current version of the project is a release</li>
132      *     <li><code>snapshots</code>: will skip if current version of the project is a snapshot</li>
133      *     <li>any other values will be considered as <code>false</code></li>
134      * </ul>
135      * @since 2.4
136      */
137     @Parameter( property = "maven.deploy.skip", defaultValue = "false" )
138     private String skip = Boolean.FALSE.toString();
139 
140     /**
141      * Component used to deploy project.
142      */
143     @Component
144     private ProjectDeployer projectDeployer;
145 
146     public void execute()
147         throws MojoExecutionException, MojoFailureException
148     {
149         boolean addedDeployRequest = false;
150         if ( Boolean.parseBoolean( skip )
151             || ( "releases".equals( skip ) && !ArtifactUtils.isSnapshot( project.getVersion() ) )
152             || ( "snapshots".equals( skip ) && ArtifactUtils.isSnapshot( project.getVersion() ) )
153         )
154         {
155             getLog().info( "Skipping artifact deployment" );
156         }
157         else
158         {
159             failIfOffline();
160 
161             // CHECKSTYLE_OFF: LineLength
162             // @formatter:off
163             ProjectDeployerRequest pdr = new ProjectDeployerRequest()
164                 .setProject( project )
165                 .setRetryFailedDeploymentCount( getRetryFailedDeploymentCount() )
166                 .setAltReleaseDeploymentRepository( altReleaseDeploymentRepository )
167                 .setAltSnapshotDeploymentRepository( altSnapshotDeploymentRepository )
168                 .setAltDeploymentRepository( altDeploymentRepository );
169             // @formatter:on
170             // CHECKSTYLE_ON: LineLength
171 
172             ArtifactRepository repo = getDeploymentRepository( pdr );
173 
174             if ( !deployAtEnd )
175             {
176                 deployProject( getSession().getProjectBuildingRequest(), pdr, repo );
177             }
178             else
179             {
180                 DEPLOYREQUESTS.add( pdr );
181                 addedDeployRequest = true;
182             }
183         }
184 
185         boolean projectsReady = READYPROJECTSCOUNTER.incrementAndGet() == reactorProjects.size();
186         if ( projectsReady )
187         {
188             synchronized ( DEPLOYREQUESTS )
189             {
190                 while ( !DEPLOYREQUESTS.isEmpty() )
191                 {
192                     ArtifactRepository repo = getDeploymentRepository( DEPLOYREQUESTS.get( 0 ) );
193 
194                     deployProject( getSession().getProjectBuildingRequest(), DEPLOYREQUESTS.remove( 0 ), repo );
195                 }
196             }
197         }
198         else if ( addedDeployRequest )
199         {
200             getLog().info( "Deploying " + project.getGroupId() + ":" + project.getArtifactId() + ":"
201                 + project.getVersion() + " at end" );
202         }
203     }
204 
205     private void deployProject( ProjectBuildingRequest pbr, ProjectDeployerRequest pir, ArtifactRepository repo )
206         throws MojoFailureException, MojoExecutionException
207     {
208         try
209         {
210             projectDeployer.deploy( pbr, pir, repo );
211         }
212         catch ( NoFileAssignedException e )
213         {
214             throw new MojoExecutionException( "NoFileAssignedException", e );
215         }
216         catch ( ArtifactDeployerException e )
217         {
218             throw new MojoExecutionException( "ArtifactDeployerException", e );
219         }
220 
221     }
222 
223     ArtifactRepository getDeploymentRepository( ProjectDeployerRequest pdr )
224 
225         throws MojoExecutionException, MojoFailureException
226     {
227         MavenProject project = pdr.getProject();
228         String altDeploymentRepository = pdr.getAltDeploymentRepository();
229         String altReleaseDeploymentRepository = pdr.getAltReleaseDeploymentRepository();
230         String altSnapshotDeploymentRepository = pdr.getAltSnapshotDeploymentRepository();
231 
232         ArtifactRepository repo = null;
233 
234         String altDeploymentRepo;
235         if ( ArtifactUtils.isSnapshot( project.getVersion() ) && altSnapshotDeploymentRepository != null )
236         {
237             altDeploymentRepo = altSnapshotDeploymentRepository;
238         }
239         else if ( !ArtifactUtils.isSnapshot( project.getVersion() ) && altReleaseDeploymentRepository != null )
240         {
241             altDeploymentRepo = altReleaseDeploymentRepository;
242         }
243         else
244         {
245             altDeploymentRepo = altDeploymentRepository;
246         }
247 
248         if ( altDeploymentRepo != null )
249         {
250             getLog().info( "Using alternate deployment repository " + altDeploymentRepo );
251 
252             Matcher matcher = ALT_LEGACY_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
253 
254             if ( matcher.matches() )
255             {
256                 String id = matcher.group( 1 ).trim();
257                 String layout = matcher.group( 2 ).trim();
258                 String url = matcher.group( 3 ).trim();
259 
260                 if ( "default".equals( layout ) )
261                 {
262                     getLog().warn( "Using legacy syntax for alternative repository. "
263                             + "Use \"" + id + "::" + url + "\" instead." );
264                     repo = createDeploymentArtifactRepository( id, url );
265                 }
266                 else
267                 {
268                     throw new MojoFailureException( altDeploymentRepo,
269                             "Invalid legacy syntax and layout for repository.",
270                             "Invalid legacy syntax and layout for alternative repository. Use \""
271                                     + id + "::" + url + "\" instead, and only default layout is supported."
272                     );
273                 }
274             }
275             else
276             {
277                 matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepo );
278 
279                 if ( !matcher.matches() )
280                 {
281                     throw new MojoFailureException( altDeploymentRepo,
282                             "Invalid syntax for repository.",
283                             "Invalid syntax for alternative repository. Use \"id::url\"."
284                     );
285                 }
286                 else
287                 {
288                     String id = matcher.group( 1 ).trim();
289                     String url = matcher.group( 2 ).trim();
290 
291                     repo = createDeploymentArtifactRepository( id, url );
292                 }
293             }
294         }
295 
296         if ( repo == null )
297         {
298             repo = project.getDistributionManagementArtifactRepository();
299         }
300 
301         if ( repo == null )
302         {
303             String msg = "Deployment failed: repository element was not specified in the POM inside"
304                 + " distributionManagement element or in -DaltDeploymentRepository=id::url parameter";
305 
306             throw new MojoExecutionException( msg );
307         }
308 
309         return repo;
310     }
311 
312 }