View Javadoc
1   package org.apache.maven.plugin.cxx.utils.release;
2   
3   /*
4    * Copyright (C) 2011-2016, Neticoa SAS France - Tous droits réservés.
5    * Author(s) : Franck Bonin, Neticoa SAS France
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   *
19   */
20  
21  import java.text.MessageFormat;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.ResourceBundle;
25  
26  import org.apache.maven.artifact.ArtifactUtils;
27  import org.apache.maven.project.MavenProject;
28  import org.apache.maven.shared.release.ReleaseResult;
29  import org.apache.maven.shared.release.config.ReleaseDescriptor;
30  import org.apache.maven.shared.release.env.ReleaseEnvironment;
31  import org.apache.maven.shared.release.policy.PolicyException;
32  import org.apache.maven.shared.release.policy.version.VersionPolicyRequest;
33  import org.apache.maven.shared.release.util.ReleaseUtil;
34  import org.apache.maven.shared.release.versions.VersionParseException;
35  import org.codehaus.plexus.components.interactivity.Prompter;
36  import org.codehaus.plexus.components.interactivity.PrompterException;
37  import org.codehaus.plexus.util.StringUtils;
38  import org.apache.maven.plugin.MojoExecutionException;
39  import org.apache.maven.plugin.MojoFailureException;
40  
41  /**
42   * Map projects to their new versions after release / into the next development cycle.
43   *
44   * The map-phases per goal are:
45   * <dl>
46   *  <dt>release:prepare</dt><dd>map-release-versions + map-development-versions; RD.isBranchCreation() = false</dd>
47   *  <dt>release:branch</dt><dd>map-branch-versions + map-development-versions; RD.isBranchCreation() = true</dd>
48   *  <dt>release:update-versions</dt><dd>map-development-versions; RD.isBranchCreation() = false</dd>
49   * </dl>
50   *
51   * <p>
52   * <table>
53   *   <tr>
54   *     <th>MapVersionsPhase field</th><th>map-release-versions</th><th>map-branch-versions</th>
55   *     <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 Franck Bonin
66   */
67  public class MapVersionsPhase
68      extends CxxAbstractMavenReleasePluginPhase
69  {
70      private ResourceBundle resourceBundle;
71      
72      enum Mode
73      { 
74          release,
75          branch,
76          dev
77      };
78      
79      private Mode mode = Mode.release;
80      
81      
82      public void setMode( String mode )
83      {
84          this.mode = Mode.valueOf( mode );
85      }
86  
87      /**
88       * Component used to prompt for input.
89       */
90      private Prompter prompter;
91  
92      /**
93       * Component used for custom or default version policy
94       */
95      private Map<String, CxxVersionPolicy> versionPolicies;
96  
97      void setPrompter( Prompter prompter )
98      {
99          this.prompter = prompter;
100     }
101 
102     @Override
103     public ReleaseResult run( CxxReleaseDescriptor releaseDescriptor, ReleaseEnvironment releaseEnvironment,
104                            List<MavenProject> reactorProjects )
105         throws MojoExecutionException, MojoFailureException
106     {
107         ReleaseResult result = new ReleaseResult();
108         
109         logInfo( result, "Mode is " + mode.name() ) ;
110 
111         resourceBundle = getResourceBundle( releaseEnvironment.getLocale() );
112 
113         MavenProject rootProject = ReleaseUtil.getRootProject( reactorProjects );
114 
115         //if ( releaseDescriptor.isAutoVersionSubmodules() && ArtifactUtils.isSnapshot( rootProject.getVersion() ) )
116         if ( releaseDescriptor.isAutoVersionSubmodules() )
117         {
118             logInfo( result, "Sub-Module Auto Versionning mode" );
119             // get the root project
120             MavenProject project = rootProject;
121 
122             String projectId = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
123 
124             String nextVersion = resolveNextVersion( project, projectId, releaseDescriptor, result );
125 
126             /*if ( convertToSnapshot )
127             {
128                 if ( releaseDescriptor.isBranchCreation() && convertToBranch )
129                 {
130                     logInfo( result, "(branch & snapshot) " + projectId + " next version will be " + nextVersion );
131                     releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
132                 }
133                 else
134                 {
135                     logInfo( result, "(snapshot) " + projectId + " next development version will be " + nextVersion );
136                     releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
137                 }
138             }
139             else
140             {
141                 logInfo( result, projectId + " next version will be " + nextVersion );
142                 releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
143             }*/
144             if ( mode == Mode.dev )
145             {
146                 logInfo( result, projectId + " next development version will be " + nextVersion );
147                 releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
148             }
149             else
150             {
151                 logInfo( result, projectId + " next version will be " + nextVersion );
152                 releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
153             }
154 
155             for ( MavenProject subProject : reactorProjects )
156             {
157                 String subProjectId =
158                     ArtifactUtils.versionlessKey( subProject.getGroupId(), subProject.getArtifactId() );
159                     
160                 if ( subProjectId.equals( projectId ) ) 
161                 {
162                     logInfo( result, "skip re-versionning \"" + subProjectId 
163                         + "\" since it is the main root project :\"" + projectId + "\"" );
164                     continue;
165                 }
166 
167                 /*if ( convertToSnapshot )
168                 {
169                     String v;
170                     if ( ArtifactUtils.isSnapshot( subProject.getVersion() ) )
171                     {
172                         v = nextVersion;
173                     }
174                     else
175                     {
176                         v = subProject.getVersion();
177                     }
178 
179                     if ( releaseDescriptor.isBranchCreation() && convertToBranch )
180                     {
181                         logInfo( result, "(branch & snapshot) " + projectId + " next version will be " + v );
182                         releaseDescriptor.mapReleaseVersion( subProjectId, v );
183                     }
184                     else
185                     {
186                         logInfo( result, "(snapshot) " + projectId + " next development version will be " + v );
187                         releaseDescriptor.mapDevelopmentVersion( subProjectId, v );
188                     }
189                 }
190                 else
191                 {
192                     logInfo( result, "()" + projectId + " next version will be " + nextVersion );
193                     releaseDescriptor.mapReleaseVersion( subProjectId, nextVersion );
194                 }*/
195                 String v = nextVersion;
196                 if ( !ArtifactUtils.isSnapshot( subProject.getVersion() ) )
197                 // Todo : other reasons for subProjectId version to (not) be updated ?
198                 {
199                     v = subProject.getVersion();
200                 }
201                 if ( mode == Mode.dev )
202                 {
203                     logInfo( result, subProjectId + " next development version will be " + v );
204                     releaseDescriptor.mapDevelopmentVersion( subProjectId, v );
205                 }
206                 else 
207                 {
208                     logInfo( result, subProjectId + " next branch version will be " + v );
209                     releaseDescriptor.mapReleaseVersion( subProjectId, v );
210                 }
211             }
212         }
213         else
214         {
215             logInfo( result, "Sub-Module Normal Versionning mode" );
216             for ( MavenProject project : reactorProjects )
217             {
218                 String projectId = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
219 
220                 String nextVersion = resolveNextVersion( project, projectId, releaseDescriptor, result );
221 
222                 /*if ( convertToSnapshot )
223                 {
224                     if ( releaseDescriptor.isBranchCreation() && convertToBranch )
225                     {
226                         logInfo( result,  + projectId + " next version will be " + nextVersion );
227                         releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
228                     }
229                     else
230                     {
231                         logInfo( result, projectId + " next development version will be " + nextVersion );
232                         releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
233                     }
234                 }
235                 else
236                 {
237                     logInfo( result, projectId + " next version will be " + nextVersion );
238                     releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
239                 }*/
240                 if ( mode == Mode.dev )
241                 {
242                     logInfo( result, projectId + " next development version will be " + nextVersion );
243                     releaseDescriptor.mapDevelopmentVersion( projectId, nextVersion );
244                 }
245                 else
246                 {
247                     logInfo( result, projectId + " next version will be " + nextVersion );
248                     releaseDescriptor.mapReleaseVersion( projectId, nextVersion );
249                 }
250             }
251         }
252 
253         result.setResultCode( ReleaseResult.SUCCESS );
254 
255         return result;
256     }
257 
258     private String resolveNextVersion( MavenProject project,
259                                    String projectId,
260                                    CxxReleaseDescriptor releaseDescriptor,
261                                    ReleaseResult result )
262         throws MojoExecutionException
263     {
264         String nextVersion;
265         
266         /* flags to take care of are
267         * in release Mode :
268         *    none
269         * 
270         * in branch Mode :
271         *   P1 :updateBranchVersions
272         *   P2 :updateVersionsToSnapshot
273         * 
274         * in dev mode :
275         *   P1 : updateWorkingCopyVersions
276         *   P2 : snapshotDevelopmentVersion
277         *   P3 : branchCreation
278         *
279         * Not at this level : autoVersionSubmodules
280         */
281         
282         boolean snapshotNeeded = false;
283         boolean snapShotOfCurrentVersion = false;
284         if ( mode == Mode.release )
285         {
286             logInfo( result, "search for a previously provided release version for " + projectId );
287             nextVersion = getReleaseVersion( projectId, releaseDescriptor );
288         }
289         else if ( mode == Mode.branch )
290         {
291             // no branch version modification
292             if ( !releaseDescriptor.isUpdateBranchVersions() )
293             {
294                 logInfo( result, "next branch version for " + projectId
295                     + " shall stay current version : " + project.getVersion() );
296                 return project.getVersion();
297             }
298             logInfo( result, 
299                 "UpdateBranchVersion flag set, search for a previously provided branch version for "
300                 + projectId );
301             
302             snapshotNeeded = releaseDescriptor.isUpdateVersionsToSnapshot();
303 
304             nextVersion = getReleaseVersion( projectId, releaseDescriptor );
305             
306             snapShotOfCurrentVersion = nextVersion != null && releaseDescriptor.isUpdateVersionsToSnapshot();
307         }
308         else // if mode == Mode.dev
309         {
310             // no working copy modification
311             if ( !releaseDescriptor.isUpdateWorkingCopyVersions() )
312             {
313                 logInfo( result, "next dev version for " + projectId 
314                     + " shall stay current version : " + project.getVersion() );
315                 return project.getVersion();
316             }
317             logInfo( result,
318                 "UpdateWorkingCopyVersions flag set, search for a previously provided dev version for "
319                 + projectId );
320             
321             snapshotNeeded = releaseDescriptor.isSnapshotDevelopmentVersion();
322             
323             nextVersion = getDevelopmentVersion( projectId, releaseDescriptor );
324             
325             snapShotOfCurrentVersion = nextVersion != null && snapshotNeeded;
326             
327             // no working copy modification special case
328             if ( releaseDescriptor.isBranchCreation() && nextVersion != null
329                  && ArtifactUtils.isSnapshot( nextVersion ) == snapshotNeeded )
330             {
331                 logInfo( result, "next dev version for " + projectId + " is correctly provided : " + nextVersion );
332                 return nextVersion;
333             }
334         }
335         
336         String defaultNextVersion = nextVersion;
337         String suggestedVersion = null;
338         String messageKey = null;
339         logInfo( result, "next version candidate found for " + projectId + " : " + nextVersion );
340         
341         // shall suggestedVersion be just snapshot of current version ? (and not next version snapshot)
342         logInfo( result, "snapShotOfCurrentVersion ? " + snapShotOfCurrentVersion );
343         logInfo( result, "snapshotNeeded ? " + snapshotNeeded );
344         try
345         {
346             //while ( nextVersion == null || ArtifactUtils.isSnapshot( nextVersion ) != convertToSnapshot )
347             while ( nextVersion == null || ( ArtifactUtils.isSnapshot( nextVersion ) != snapshotNeeded ) )
348             {
349                 logInfo( result, "suggested nextVersion is : " + nextVersion );
350                 logInfo( result, "nextVersion is snapShot ? " + ArtifactUtils.isSnapshot( nextVersion ) );
351                 if ( suggestedVersion == null )
352                 {
353                     //String baseVersion = null;
354                     String baseVersion = defaultNextVersion;
355                     /*
356                     //if ( convertToSnapshot )
357                     if ( mode != Mode.release )
358                     {
359                         baseVersion = getReleaseVersion( projectId, releaseDescriptor );
360                     }
361                     */
362                     // unspecified and unmapped version, so use project version
363                     if ( baseVersion == null )
364                     {
365                         baseVersion = project.getVersion();
366                         logInfo( result, 
367                             "unspecified and unmapped version, so use project version as base for suggestion : "
368                             + baseVersion );
369                     }
370 
371                     try
372                     {
373                         try
374                         {
375                             suggestedVersion =
376                                 resolveSuggestedVersion( snapshotNeeded, snapShotOfCurrentVersion,
377                                     baseVersion, releaseDescriptor.getProjectVersionPolicyId() );
378                         }
379                         catch ( VersionParseException e )
380                         {
381                             if ( releaseDescriptor.isInteractive() )
382                             {
383                                 suggestedVersion =
384                                     resolveSuggestedVersion( snapshotNeeded, snapShotOfCurrentVersion,
385                                         "1.0", releaseDescriptor.getProjectVersionPolicyId() );
386                             }
387                             else
388                             {
389                                 throw new MojoExecutionException( "Error parsing version, cannot determine next "
390                                     + "version: " + e.getMessage(), e );
391                             }
392                         }
393                     }
394                     catch ( PolicyException e )
395                     {
396                         throw new MojoExecutionException( e.getMessage(), e );
397                     }
398                     catch ( VersionParseException e )
399                     {
400                         throw new MojoExecutionException( e.getMessage(), e );
401                     }
402                 }
403 
404                 if ( releaseDescriptor.isInteractive() )
405                 {
406                     if ( messageKey == null )
407                     {
408                         messageKey = getMapversionPromptKey( releaseDescriptor );
409                     }
410                     String message =
411                         MessageFormat.format( resourceBundle.getString( messageKey ), project.getName(), projectId );
412                     nextVersion = prompter.prompt( message, suggestedVersion );
413 
414                   //@todo validate next version, maybe with DefaultArtifactVersion
415                 }
416                 else
417                 {
418                     nextVersion = suggestedVersion;
419                 }
420             }
421         }
422         catch ( PrompterException e )
423         {
424             throw new MojoExecutionException( "Error reading version from input handler: " + e.getMessage(), e );
425         }
426         return nextVersion;
427     }
428 
429     private String resolveSuggestedVersion( boolean convertToSnapshot, boolean nextSnapShot,
430         String baseVersion, String policyId )
431         throws PolicyException, VersionParseException
432     {
433         CxxVersionPolicy policy = versionPolicies.get( policyId );
434         VersionPolicyRequest request = new VersionPolicyRequest().setVersion( baseVersion );
435 
436         //return convertToSnapshot ? policy.getDevelopmentVersion( request ).getVersion()
437         //                : policy.getReleaseVersion( request ).getVersion();
438         return nextSnapShot ? policy.getSnapshotVersion( request ).getVersion() // next snapshot version only
439             : convertToSnapshot ? policy.getDevelopmentVersion( request ).getVersion() // current snapshot version
440             : ( mode == Mode.dev ) ? policy.getBranchVersion( request ).getVersion() // no snapshot, just next version
441             : ( mode == Mode.branch ) ? policy.getBranchVersion( request ).getVersion()
442             : policy.getReleaseVersion( request ).getVersion(); // no snapshot, just cleaned-up current version
443     }
444 
445     private String getDevelopmentVersion( String projectId, ReleaseDescriptor releaseDescriptor )
446     {
447         String defaultVersion = releaseDescriptor.getDefaultDevelopmentVersion();
448         if ( StringUtils.isEmpty( defaultVersion ) )
449         {
450             defaultVersion = ( String ) releaseDescriptor.getDevelopmentVersions().get( projectId );
451         }
452         return defaultVersion;
453     }
454 
455     private String getReleaseVersion( String projectId, ReleaseDescriptor releaseDescriptor )
456     {
457         String nextVersion = releaseDescriptor.getDefaultReleaseVersion();
458         if ( StringUtils.isEmpty( nextVersion ) )
459         {
460             nextVersion = ( String ) releaseDescriptor.getReleaseVersions().get( projectId );
461         }
462         return nextVersion;
463     }
464 
465     private String getMapversionPromptKey( ReleaseDescriptor releaseDescriptor )
466     {
467         String messageKey;
468         if ( mode == Mode.branch )//( convertToBranch )
469         {
470             messageKey = "mapversion.branch.prompt";
471         }
472         else if ( mode == Mode.dev )//( convertToSnapshot )
473         {
474             if ( releaseDescriptor.isBranchCreation() )
475             {
476                 messageKey = "mapversion.workingcopy.prompt";
477             }
478             else
479             {
480                 messageKey = "mapversion.development.prompt";
481             }
482         }
483         else
484         {
485             messageKey = "mapversion.release.prompt";
486         }
487         return messageKey;
488     }
489 }