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