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.text.MessageFormat;
23  import java.util.List;
24  import java.util.ResourceBundle;
25  
26  import org.apache.maven.artifact.ArtifactUtils;
27  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
28  import org.apache.maven.project.MavenProject;
29  import org.apache.maven.shared.release.ReleaseExecutionException;
30  import org.apache.maven.shared.release.ReleaseResult;
31  import org.apache.maven.shared.release.config.ReleaseDescriptor;
32  import org.apache.maven.shared.release.env.ReleaseEnvironment;
33  import org.apache.maven.shared.release.util.ReleaseUtil;
34  import org.apache.maven.shared.release.versions.DefaultVersionInfo;
35  import org.apache.maven.shared.release.versions.VersionParseException;
36  import org.codehaus.plexus.components.interactivity.Prompter;
37  import org.codehaus.plexus.components.interactivity.PrompterException;
38  import org.codehaus.plexus.util.StringUtils;
39  
40  /**
41   * Map projects to their new versions after release / into the next development cycle.
42   * 
43   * The map-phases per goal are:
44   * <dl>
45   *  <dt>release:prepare</dt><dd>map-release-versions + map-development-versions; RD.isBranchCreation() = false</dd>
46   *  <dt>release:branch</dt><dd>map-branch-versions + map-development-versions; RD.isBranchCreation() = true</dd>
47   *  <dt>release:update-versions</dt><dd>map-development-versions; RD.isBranchCreation() = false</dd>
48   * </dl>
49   * 
50   * <p>
51   * <table>
52   *   <tr>
53   *     <th>MapVersionsPhase field</th><th>map-release-versions</th><th>map-branch-versions</th><th>map-development-versions</th>
54   *   </tr>
55   *   <tr>
56   *     <td>convertToSnapshot</td>     <td>false</td>               <td>true</td>               <td>true</td>
57   *   </tr>
58   *   <tr>
59   *     <td>convertToBranch</td>       <td>false</td>               <td>true</td>               <td>false</td>
60   *   </tr>
61   * </table>
62   *
63   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
64   * @author Robert Scholte
65   */
66  public class MapVersionsPhase
67      extends AbstractReleasePhase
68  {
69      private ResourceBundle resourceBundle;
70      
71      /**
72       * Whether to convert to a snapshot or a release.
73       */
74      private boolean convertToSnapshot;
75  
76      /**
77       * Whether to convert to a snapshot or a release.
78       */
79      private boolean convertToBranch;
80  
81      /**
82       * Component used to prompt for input.
83       */
84      private Prompter prompter;
85  
86      void setPrompter( Prompter prompter )
87      {
88          this.prompter = prompter;
89      }
90  
91      public ReleaseResult execute( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
92                                    List<MavenProject> reactorProjects )
93          throws ReleaseExecutionException
94      {
95          ReleaseResult result = new ReleaseResult();
96          
97          resourceBundle = getResourceBundle( releaseEnvironment.getLocale() );
98  
99          MavenProject rootProject = ReleaseUtil.getRootProject( reactorProjects );
100 
101         if ( releaseDescriptor.isAutoVersionSubmodules() && ArtifactUtils.isSnapshot( rootProject.getVersion() ) )
102         {
103             // get the root project
104             MavenProject project = rootProject;
105 
106             String projectId = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
107 
108             String nextVersion = resolveNextVersion( project, projectId, releaseDescriptor, result );
109 
110             if ( convertToSnapshot )
111             {
112                 if ( releaseDescriptor.isBranchCreation() && convertToBranch )
113                 {
114                     releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
115                 }
116                 else
117                 {
118                     releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
119                 }
120             }
121             else
122             {
123                 releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
124             }
125 
126             for ( MavenProject subProject : reactorProjects )
127             {
128                 String subProjectId =
129                     ArtifactUtils.versionlessKey( subProject.getGroupId(), subProject.getArtifactId() );
130 
131                 if ( convertToSnapshot )
132                 {
133                     String v;
134                     if ( ArtifactUtils.isSnapshot( subProject.getVersion() ) )
135                     {
136                         v = nextVersion;
137                     }
138                     else
139                     {
140                         v = subProject.getVersion();
141                     }
142 
143                     if ( releaseDescriptor.isBranchCreation() && convertToBranch )
144                     {
145                         releaseDescriptor.mapReleaseVersion( subProjectId, v );
146                     }
147                     else
148                     {
149                         releaseDescriptor.mapDevelopmentVersion( subProjectId, v );
150                     }
151                 }
152                 else
153                 {
154                     releaseDescriptor.mapReleaseVersion( subProjectId, nextVersion );
155                 }
156             }
157         }
158         else
159         {
160             for ( MavenProject project : reactorProjects )
161             {
162                 String projectId = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
163 
164                 String nextVersion = resolveNextVersion( project, projectId, releaseDescriptor, result );
165 
166                 if ( convertToSnapshot )
167                 {
168                     if ( releaseDescriptor.isBranchCreation() && convertToBranch )
169                     {
170                         releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
171                     }
172                     else
173                     {
174                         releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
175                     }
176                 }
177                 else
178                 {
179                     releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
180                 }
181             }
182         }
183 
184         result.setResultCode( ReleaseResult.SUCCESS );
185 
186         return result;
187     }
188 
189     private String resolveNextVersion( MavenProject project, 
190                                    String projectId, 
191                                    ReleaseDescriptor releaseDescriptor,
192                                    ReleaseResult result )
193         throws ReleaseExecutionException
194     {
195         String defaultVersion;
196         if ( convertToBranch )
197         {
198             // no branch modification
199             if( !( releaseDescriptor.isUpdateBranchVersions()
200                           && ( ArtifactUtils.isSnapshot( project.getVersion() ) || releaseDescriptor.isUpdateVersionsToSnapshot() ) ) )
201             {
202                 return project.getVersion();
203             }
204             
205             defaultVersion = getReleaseVersion( projectId, releaseDescriptor );
206         }
207         else if ( !convertToSnapshot ) // map-release-version
208         {
209             defaultVersion = getReleaseVersion( projectId, releaseDescriptor );
210         }
211         else if ( releaseDescriptor.isBranchCreation() )
212         {
213             // no working copy modification
214             if( !( ArtifactUtils.isSnapshot( project.getVersion() )
215                           && releaseDescriptor.isUpdateWorkingCopyVersions() ) )
216             {
217                 return project.getVersion();
218             }
219             
220             defaultVersion = getDevelopmentVersion( projectId, releaseDescriptor );
221         }
222         else
223         {
224             // no working copy modification
225             if( !( releaseDescriptor.isUpdateWorkingCopyVersions() ) )
226             {
227                 return project.getVersion();
228             }
229             
230             defaultVersion = getDevelopmentVersion( projectId, releaseDescriptor );
231         }
232         //@todo validate default version, maybe with DefaultArtifactVersion
233         
234         String suggestedVersion = null;
235         String nextVersion = defaultVersion;
236         String messageKey = null;
237         try
238         {
239             while( nextVersion == null || ArtifactUtils.isSnapshot( nextVersion ) != convertToSnapshot )
240             {
241                 if ( suggestedVersion == null )
242                 {
243                     DefaultVersionInfo versionInfo;
244                     try
245                     {
246                         String baseVersion = null;
247                         if( convertToSnapshot )
248                         {
249                             baseVersion = getReleaseVersion( projectId, releaseDescriptor );
250                         }
251                         // unspecified and unmapped version, so use project version 
252                         if( baseVersion == null )
253                         {
254                             baseVersion = project.getVersion();
255                         }
256                         versionInfo = new DefaultVersionInfo( baseVersion );
257                     }
258                     catch ( VersionParseException e )
259                     {
260                         if( releaseDescriptor.isInteractive() )
261                         {
262                             try
263                             {
264                                 versionInfo = new DefaultVersionInfo( "1.0" );
265                             }
266                             catch ( VersionParseException e1 )
267                             {
268                                 // if that happens we are in serious trouble!
269                                 throw new ReleaseExecutionException( "Version 1.0 could not be parsed!", e1 );
270                             }
271                         }
272                         else
273                         {
274                             throw new ReleaseExecutionException( "Error parsing version, cannot determine next version: " + e.getMessage(), e );
275                         }
276                     }
277                     suggestedVersion =
278                         convertToSnapshot ? versionInfo.getNextVersion().getSnapshotVersionString()
279                                         : versionInfo.getReleaseVersionString(); 
280                 }
281                 
282                 if( releaseDescriptor.isInteractive() )
283                 {
284                     if( messageKey == null )
285                     {
286                         messageKey = getMapversionPromptKey( releaseDescriptor );
287                     }
288                     String message =
289                         MessageFormat.format( resourceBundle.getString( messageKey ),
290                                               project.getName(), projectId );
291                     nextVersion = prompter.prompt( message, suggestedVersion );
292                     
293                   //@todo validate next version, maybe with DefaultArtifactVersion
294                 }
295                 else
296                 {
297                     nextVersion = suggestedVersion;
298                 }
299             }
300         }
301         catch ( PrompterException e )
302         {
303             throw new ReleaseExecutionException( "Error reading version from input handler: " + e.getMessage(), e );
304         }
305         return nextVersion;
306     }
307 
308     private String getDevelopmentVersion( String projectId, ReleaseDescriptor releaseDescriptor )
309     {
310         String defaultVersion;
311         defaultVersion = releaseDescriptor.getDefaultDevelopmentVersion();
312         if ( StringUtils.isEmpty( defaultVersion ) )
313         {
314             defaultVersion = ( String ) releaseDescriptor.getDevelopmentVersions().get( projectId );
315         }
316         return defaultVersion;
317     }
318 
319     private String getReleaseVersion( String projectId, ReleaseDescriptor releaseDescriptor )
320     {
321         String nextVersion = releaseDescriptor.getDefaultReleaseVersion();
322         if ( StringUtils.isEmpty( nextVersion ) )
323         {
324             nextVersion = ( String ) releaseDescriptor.getReleaseVersions().get( projectId );
325         }
326         return nextVersion;
327     }
328     
329 
330     private String getMapversionPromptKey( ReleaseDescriptor releaseDescriptor )
331     {
332         String messageKey;
333         if ( convertToBranch )
334         {
335             messageKey = "mapversion.branch.prompt";
336         }
337         else if ( convertToSnapshot )
338         {
339             if ( releaseDescriptor.isBranchCreation() )
340             {
341                 messageKey = "mapversion.workingcopy.prompt";
342             }
343             else
344             {
345                 messageKey = "mapversion.development.prompt";
346             }
347         }
348         else
349         {
350             messageKey = "mapversion.release.prompt";
351         }
352         return messageKey;
353     }
354 
355     public ReleaseResult simulate( ReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
356                                    List<MavenProject> reactorProjects )
357         throws ReleaseExecutionException
358     {
359         ReleaseResult result = new ReleaseResult();
360 
361         // It makes no modifications, so simulate is the same as execute
362         execute( releaseDescriptor, releaseEnvironment, reactorProjects );
363 
364         result.setResultCode( ReleaseResult.SUCCESS );
365 
366         return result;
367     }
368 }