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