View Javadoc

1   package org.apache.maven.shared.release.phase;
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.io.File;
23  import java.io.IOException;
24  import java.io.Writer;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.ArtifactUtils;
33  import org.apache.maven.model.Build;
34  import org.apache.maven.model.Dependency;
35  import org.apache.maven.model.Extension;
36  import org.apache.maven.model.Model;
37  import org.apache.maven.model.Plugin;
38  import org.apache.maven.model.ReportPlugin;
39  import org.apache.maven.model.Reporting;
40  import org.apache.maven.model.Scm;
41  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
42  import org.apache.maven.project.MavenProject;
43  import org.apache.maven.project.path.PathTranslator;
44  import org.apache.maven.scm.ScmException;
45  import org.apache.maven.scm.ScmFileSet;
46  import org.apache.maven.scm.command.add.AddScmResult;
47  import org.apache.maven.scm.provider.ScmProvider;
48  import org.apache.maven.scm.repository.ScmRepository;
49  import org.apache.maven.shared.release.ReleaseExecutionException;
50  import org.apache.maven.shared.release.ReleaseFailureException;
51  import org.apache.maven.shared.release.ReleaseResult;
52  import org.apache.maven.shared.release.config.ReleaseDescriptor;
53  import org.apache.maven.shared.release.env.ReleaseEnvironment;
54  import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
55  import org.apache.maven.shared.release.scm.ScmTranslator;
56  import org.apache.maven.shared.release.util.ReleaseUtil;
57  import org.codehaus.plexus.util.IOUtil;
58  import org.codehaus.plexus.util.WriterFactory;
59  
60  /**
61   * Generate release POMs.
62   *
63   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
64   * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
65   * @plexus.component role="org.apache.maven.shared.release.phase.ReleasePhase" role-hint="generate-release-poms"
66   */
67  public class GenerateReleasePomsPhase
68      extends AbstractReleasePomsPhase
69  {
70      /**
71       *
72       *
73       * @plexus.requirement
74       */
75      private PathTranslator pathTranslator;
76  
77      /**
78       * SCM URL translators mapped by provider name.
79       *
80       * @plexus.requirement role="org.apache.maven.shared.release.scm.ScmTranslator"
81       */
82      private Map<String, ScmTranslator> scmTranslators;
83  
84      /*
85       * @see org.apache.maven.shared.release.phase.ReleasePhase#execute(org.apache.maven.shared.release.config.ReleaseDescriptor,
86       *      org.apache.maven.settings.Settings, java.util.List)
87       */
88      public ReleaseResult execute( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
89                                    List<MavenProject> reactorProjects )
90          throws ReleaseExecutionException, ReleaseFailureException
91      {
92          return execute( releaseDescriptor, releaseEnvironment, reactorProjects, false );
93      }
94  
95      private ReleaseResult execute( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
96                                     List<MavenProject> reactorProjects, boolean simulate )
97          throws ReleaseExecutionException, ReleaseFailureException
98      {
99          ReleaseResult result = new ReleaseResult();
100 
101         if ( releaseDescriptor.isGenerateReleasePoms() )
102         {
103             logInfo( result, "Generating release POMs..." );
104 
105             generateReleasePoms( releaseDescriptor, releaseEnvironment, reactorProjects, simulate, result );
106         }
107         else
108         {
109             logInfo( result, "Not generating release POMs" );
110         }
111 
112         result.setResultCode( ReleaseResult.SUCCESS );
113 
114         return result;
115     }
116 
117     private void generateReleasePoms( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
118                                       List<MavenProject> reactorProjects, boolean simulate, ReleaseResult result )
119         throws ReleaseExecutionException, ReleaseFailureException
120     {
121         List<File> releasePoms = new ArrayList<File>();
122 
123         for ( MavenProject project : reactorProjects )
124         {
125             logInfo( result, "Generating release POM for '" + project.getName() + "'..." );
126 
127             releasePoms.add( generateReleasePom( project, releaseDescriptor, releaseEnvironment, reactorProjects,
128                                                  simulate, result ) );
129         }
130 
131         addReleasePomsToScm( releaseDescriptor, releaseEnvironment, reactorProjects, simulate, result, releasePoms );
132     }
133 
134     private File generateReleasePom( MavenProject project, ReleaseDescriptor releaseDescriptor,
135                                      ReleaseEnvironment releaseEnvironment, List<MavenProject> reactorProjects,
136                                      boolean simulate, ReleaseResult result )
137         throws ReleaseExecutionException, ReleaseFailureException
138     {
139         // create release pom
140 
141         Model releasePom = createReleaseModel( project, releaseDescriptor, releaseEnvironment, reactorProjects, result );
142 
143         // write release pom to file
144 
145         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
146 
147         File releasePomFile = ReleaseUtil.getReleasePom( project );
148 
149         // MRELEASE-273 : A release pom can be null
150         if ( releasePomFile == null )
151         {
152             throw new ReleaseExecutionException( "Cannot generate release POM : pom file is null" );
153         }
154 
155         Writer fileWriter = null;
156 
157         try
158         {
159             fileWriter = WriterFactory.newXmlWriter( releasePomFile );
160 
161             pomWriter.write( fileWriter, releasePom );
162         }
163         catch ( IOException exception )
164         {
165             throw new ReleaseExecutionException( "Cannot generate release POM", exception );
166         }
167         finally
168         {
169             IOUtil.close( fileWriter );
170         }
171 
172         return releasePomFile;
173     }
174 
175     private void addReleasePomsToScm( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
176                                       List<MavenProject> reactorProjects, boolean simulate, ReleaseResult result,
177                                       List<File> releasePoms )
178         throws ReleaseFailureException, ReleaseExecutionException
179     {
180         if ( simulate )
181         {
182             logInfo( result, "Full run would be adding " + releasePoms );
183         }
184         else
185         {
186             ScmRepository scmRepository = getScmRepository( releaseDescriptor, releaseEnvironment );
187             ScmProvider scmProvider = getScmProvider( scmRepository );
188 
189             MavenProject rootProject = ReleaseUtil.getRootProject( reactorProjects );
190             ScmFileSet scmFileSet = new ScmFileSet( rootProject.getFile().getParentFile(), releasePoms );
191 
192             try
193             {
194                 AddScmResult scmResult = scmProvider.add( scmRepository, scmFileSet );
195 
196                 if ( !scmResult.isSuccess() )
197                 {
198                     throw new ReleaseScmCommandException( "Cannot add release POM to SCM", scmResult );
199                 }
200             }
201             catch ( ScmException exception )
202             {
203                 throw new ReleaseExecutionException( "Cannot add release POM to SCM: " + exception.getMessage(),
204                                                      exception );
205             }
206         }
207     }
208 
209     private Model createReleaseModel( MavenProject project, ReleaseDescriptor releaseDescriptor,
210                                       ReleaseEnvironment releaseEnvironment, List<MavenProject> reactorProjects,
211                                       ReleaseResult result )
212         throws ReleaseFailureException, ReleaseExecutionException
213     {
214         Map<String, String> originalVersions = getOriginalVersionMap( releaseDescriptor, reactorProjects );
215         Map<String, String> mappedVersions = getNextVersionMap( releaseDescriptor );
216 
217         MavenProject releaseProject = new MavenProject( project );
218         Model releaseModel = releaseProject.getModel();
219 
220         // the release POM should reflect bits of these which were injected at build time...
221         // we don't need these polluting the POM.
222         releaseModel.setParent( null );
223         releaseModel.setProfiles( Collections.EMPTY_LIST );
224         releaseModel.setDependencyManagement( null );
225         releaseProject.getBuild().setPluginManagement( null );
226 
227         // update project version
228         String projectVersion = releaseModel.getVersion();
229         String releaseVersion =
230             getNextVersion( mappedVersions, project.getGroupId(), project.getArtifactId(), projectVersion );
231         releaseModel.setVersion( releaseVersion );
232 
233         // update final name if implicit
234         String finalName = releaseModel.getBuild().getFinalName();
235 
236         if ( finalName.equals( releaseModel.getArtifactId() + "-" + projectVersion ) )
237         {
238             releaseModel.getBuild().setFinalName( null );
239         }
240         else if ( finalName.indexOf( Artifact.SNAPSHOT_VERSION ) != -1 )
241         {
242             throw new ReleaseFailureException( "Cannot reliably adjust the finalName of project: "
243                             + releaseProject.getId() );
244         }
245 
246         // update scm
247         Scm scm = releaseModel.getScm();
248 
249         if ( scm != null )
250         {
251             ScmRepository scmRepository = getScmRepository( releaseDescriptor, releaseEnvironment );
252             ScmTranslator scmTranslator = getScmTranslator( scmRepository );
253 
254             if ( scmTranslator != null )
255             {
256                 releaseModel.setScm( createReleaseScm( releaseModel.getScm(), scmTranslator, releaseDescriptor ) );
257             }
258             else
259             {
260                 String message = "No SCM translator found - skipping rewrite";
261 
262                 result.appendDebug( message );
263 
264                 getLogger().debug( message );
265             }
266         }
267 
268         // rewrite dependencies
269         releaseModel.setDependencies( createReleaseDependencies( originalVersions, mappedVersions, releaseProject ) );
270 
271         // rewrite plugins
272         releaseModel.getBuild().setPlugins( createReleasePlugins( originalVersions, mappedVersions, releaseProject ) );
273 
274         // rewrite reports
275         releaseModel.getReporting().setPlugins( createReleaseReportPlugins( originalVersions, mappedVersions,
276                                                                             releaseProject ) );
277 
278         // rewrite extensions
279         releaseModel.getBuild().setExtensions( createReleaseExtensions( originalVersions, mappedVersions,
280                                                                         releaseProject ) );
281 
282         pathTranslator.unalignFromBaseDirectory( releaseProject.getModel(), project.getFile().getParentFile() );
283 
284         return releaseModel;
285     }
286 
287     public ReleaseResult simulate( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
288                                    List<MavenProject> reactorProjects )
289         throws ReleaseExecutionException, ReleaseFailureException
290     {
291         return execute( releaseDescriptor, releaseEnvironment, reactorProjects, true );
292     }
293 
294     protected Map<String, String> getOriginalVersionMap( ReleaseDescriptor releaseDescriptor,
295                                                          List<MavenProject> reactorProjects )
296     {
297         return releaseDescriptor.getOriginalVersions( reactorProjects );
298     }
299 
300     @SuppressWarnings( "unchecked" )
301     protected Map<String, String> getNextVersionMap( ReleaseDescriptor releaseDescriptor )
302     {
303         return releaseDescriptor.getReleaseVersions();
304     }
305 
306     private String getNextVersion( Map<String, String> mappedVersions, String groupId, String artifactId, String version )
307         throws ReleaseFailureException
308     {
309         // TODO: share with RewritePomsForReleasePhase.rewriteVersion
310 
311         String id = ArtifactUtils.versionlessKey( groupId, artifactId );
312 
313         String nextVersion = mappedVersions.get( id );
314 
315         if ( nextVersion == null )
316         {
317             throw new ReleaseFailureException( "Version for '" + id + "' was not mapped" );
318         }
319 
320         return nextVersion;
321     }
322 
323     private ScmTranslator getScmTranslator( ScmRepository scmRepository )
324     {
325         return scmTranslators.get( scmRepository.getProvider() );
326     }
327 
328     private Scm createReleaseScm( Scm scm, ScmTranslator scmTranslator, ReleaseDescriptor releaseDescriptor )
329     {
330         // TODO: share with RewritePomsForReleasePhase.translateScm
331 
332         String tag = releaseDescriptor.getScmReleaseLabel();
333         String tagBase = releaseDescriptor.getScmTagBase();
334 
335         Scm releaseScm = new Scm();
336 
337         if ( scm.getConnection() != null )
338         {
339             String value = scmTranslator.translateTagUrl( scm.getConnection(), tag, tagBase );
340             releaseScm.setConnection( value );
341         }
342 
343         if ( scm.getDeveloperConnection() != null )
344         {
345             String value = scmTranslator.translateTagUrl( scm.getDeveloperConnection(), tag, tagBase );
346             releaseScm.setDeveloperConnection( value );
347         }
348 
349         if ( scm.getUrl() != null )
350         {
351             String value = scmTranslator.translateTagUrl( scm.getUrl(), tag, tagBase );
352             releaseScm.setUrl( value );
353         }
354 
355         if ( scm.getTag() != null )
356         {
357             String value = scmTranslator.resolveTag( scm.getTag() );
358             releaseScm.setTag( value );
359         }
360 
361         return releaseScm;
362     }
363 
364     private List<Dependency> createReleaseDependencies( Map<String, String> originalVersions,
365                                                         Map<String, String> mappedVersions, MavenProject project )
366         throws ReleaseFailureException
367     {
368         @SuppressWarnings( "unchecked" )
369         Set<Artifact> artifacts = project.getArtifacts();
370 
371         List<Dependency> releaseDependencies = null;
372 
373         if ( artifacts != null )
374         {
375             // make dependency order deterministic for tests (related to MNG-1412)
376             List<Artifact> orderedArtifacts = new ArrayList<Artifact>();
377             orderedArtifacts.addAll( artifacts );
378             Collections.sort( orderedArtifacts );
379 
380             releaseDependencies = new ArrayList<Dependency>();
381 
382             for ( Artifact artifact : orderedArtifacts )
383             {
384                 Dependency releaseDependency = new Dependency();
385 
386                 releaseDependency.setGroupId( artifact.getGroupId() );
387                 releaseDependency.setArtifactId( artifact.getArtifactId() );
388 
389                 String version = getReleaseVersion( originalVersions, mappedVersions, artifact );
390 
391                 releaseDependency.setVersion( version );
392                 releaseDependency.setType( artifact.getType() );
393                 releaseDependency.setScope( artifact.getScope() );
394                 releaseDependency.setClassifier( artifact.getClassifier() );
395 
396                 releaseDependencies.add( releaseDependency );
397             }
398         }
399 
400         return releaseDependencies;
401     }
402 
403     private String getReleaseVersion( Map<String, String> originalVersions, Map<String, String> mappedVersions, Artifact artifact )
404         throws ReleaseFailureException
405     {
406         String key = ArtifactUtils.versionlessKey( artifact );
407 
408         String originalVersion = originalVersions.get( key );
409         String mappedVersion = mappedVersions.get( key );
410 
411         String version = artifact.getVersion();
412 
413         if ( version.equals( originalVersion ) )
414         {
415             if ( mappedVersion != null )
416             {
417                 version = mappedVersion;
418             }
419             else
420             {
421                 throw new ReleaseFailureException( "Version '" + version + "' for '" + key + "' was not mapped" );
422             }
423         }
424         else
425         {
426             if ( !ArtifactUtils.isSnapshot( version ) )
427             {
428                 version = artifact.getBaseVersion();
429             }
430         }
431 
432         return version;
433     }
434 
435     private List<Plugin> createReleasePlugins( Map<String, String> originalVersions, Map<String, String> mappedVersions, MavenProject project )
436         throws ReleaseFailureException
437     {
438         List<Plugin> releasePlugins = null;
439 
440         // Use original - don't want the lifecycle introduced ones
441         Build build = project.getOriginalModel().getBuild();
442 
443         if ( build != null )
444         {
445             List<Plugin> plugins = build.getPlugins();
446 
447             if ( plugins != null )
448             {
449                 @SuppressWarnings( "unchecked" )
450                 Map<String, Artifact> artifactsById = project.getPluginArtifactMap();
451 
452                 releasePlugins = new ArrayList<Plugin>();
453 
454                 for ( Plugin plugin : plugins )
455                 {
456                     String id = ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() );
457                     Artifact artifact = artifactsById.get( id );
458                     String version = getReleaseVersion( originalVersions, mappedVersions, artifact );
459 
460                     Plugin releasePlugin = new Plugin();
461                     releasePlugin.setGroupId( plugin.getGroupId() );
462                     releasePlugin.setArtifactId( plugin.getArtifactId() );
463                     releasePlugin.setVersion( version );
464                     releasePlugin.setExtensions( plugin.isExtensions() );
465                     releasePlugin.setExecutions( plugin.getExecutions() );
466                     releasePlugin.setDependencies( plugin.getDependencies() );
467                     releasePlugin.setGoals( plugin.getGoals() );
468                     releasePlugin.setInherited( plugin.getInherited() );
469                     releasePlugin.setConfiguration( plugin.getConfiguration() );
470 
471                     releasePlugins.add( releasePlugin );
472                 }
473             }
474         }
475 
476         return releasePlugins;
477     }
478 
479     private List<ReportPlugin> createReleaseReportPlugins( Map<String, String> originalVersions, Map<String, String> mappedVersions,
480                                                            MavenProject project )
481         throws ReleaseFailureException
482     {
483         List<ReportPlugin> releaseReportPlugins = null;
484 
485         Reporting reporting = project.getModel().getReporting();
486 
487         if ( reporting != null )
488         {
489             List<ReportPlugin> reportPlugins = reporting.getPlugins();
490 
491             if ( reportPlugins != null )
492             {
493                 @SuppressWarnings( "unchecked" )
494                 Map<String, Artifact> artifactsById = project.getReportArtifactMap();
495 
496                 releaseReportPlugins = new ArrayList<ReportPlugin>();
497 
498                 for ( ReportPlugin reportPlugin : reportPlugins )
499                 {
500                     String id = ArtifactUtils.versionlessKey( reportPlugin.getGroupId(), reportPlugin.getArtifactId() );
501                     Artifact artifact = artifactsById.get( id );
502                     String version = getReleaseVersion( originalVersions, mappedVersions, artifact );
503 
504                     ReportPlugin releaseReportPlugin = new ReportPlugin();
505                     releaseReportPlugin.setGroupId( reportPlugin.getGroupId() );
506                     releaseReportPlugin.setArtifactId( reportPlugin.getArtifactId() );
507                     releaseReportPlugin.setVersion( version );
508                     releaseReportPlugin.setInherited( reportPlugin.getInherited() );
509                     releaseReportPlugin.setConfiguration( reportPlugin.getConfiguration() );
510                     releaseReportPlugin.setReportSets( reportPlugin.getReportSets() );
511 
512                     releaseReportPlugins.add( releaseReportPlugin );
513                 }
514             }
515         }
516 
517         return releaseReportPlugins;
518     }
519 
520     private List<Extension> createReleaseExtensions( Map<String, String> originalVersions, Map<String, String> mappedVersions, MavenProject project )
521         throws ReleaseFailureException
522     {
523         List<Extension> releaseExtensions = null;
524 
525         // Use original - don't want the lifecycle introduced ones
526         Build build = project.getOriginalModel().getBuild();
527 
528         if ( build != null )
529         {
530             List<Extension> extensions = build.getExtensions();
531 
532             if ( extensions != null )
533             {
534                 releaseExtensions = new ArrayList<Extension>();
535 
536                 for ( Extension extension : extensions )
537                 {
538                     String id = ArtifactUtils.versionlessKey( extension.getGroupId(), extension.getArtifactId() );
539                     Artifact artifact = (Artifact) project.getExtensionArtifactMap().get( id );
540                     String version = getReleaseVersion( originalVersions, mappedVersions, artifact );
541 
542                     Extension releaseExtension = new Extension();
543                     releaseExtension.setGroupId( extension.getGroupId() );
544                     releaseExtension.setArtifactId( extension.getArtifactId() );
545                     releaseExtension.setVersion( version );
546 
547                     releaseExtensions.add( releaseExtension );
548                 }
549             }
550         }
551 
552         return releaseExtensions;
553     }
554 
555     /*
556      * @see org.apache.maven.shared.release.phase.AbstractReleasePhase#clean(java.util.List)
557      */
558     public ReleaseResult clean( List<MavenProject> reactorProjects )
559     {
560         ReleaseResult result = new ReleaseResult();
561 
562         for ( MavenProject project : reactorProjects )
563         {
564             File releasePom = ReleaseUtil.getReleasePom( project );
565 
566             // MRELEASE-273 : A release pom can be null
567             if ( releasePom != null && releasePom.exists() )
568             {
569                 logInfo( result, "Deleting release POM for '" + project.getName() + "'..." );
570 
571                 if ( !releasePom.delete() )
572                 {
573                     logWarn( result, "Cannot delete release POM: " + releasePom );
574                 }
575             }
576         }
577 
578         result.setResultCode( ReleaseResult.SUCCESS );
579 
580         return result;
581     }
582 }