View Javadoc
1   package org.apache.maven.plugins.release;
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.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.Arrays;
26  
27  import org.apache.maven.plugin.MojoExecutionException;
28  import org.apache.maven.plugin.MojoFailureException;
29  import org.apache.maven.plugins.annotations.Mojo;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.plugins.annotations.ResolutionScope;
32  import org.apache.maven.shared.release.DefaultReleaseManagerListener;
33  import org.apache.maven.shared.release.ReleaseExecutionException;
34  import org.apache.maven.shared.release.ReleaseFailureException;
35  import org.apache.maven.shared.release.ReleasePrepareRequest;
36  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
37  
38  /**
39   * Prepare for a release in SCM. Steps through several phases to ensure the POM is ready to be released and then
40   * prepares SCM to eventually contain a tagged version of the release and a record in the local copy of the parameters
41   * used. This can be followed by a call to <code>release:perform</code>. For more info see <a
42   * href="https://maven.apache.org/plugins/maven-release-plugin/examples/prepare-release.html"
43   * >https://maven.apache.org/plugins/maven-release-plugin/examples/prepare-release.html</a>.
44   *
45   * @author <a href="mailto:jdcasey@apache.org">John Casey</a>
46   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
47   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
48   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
49   */
50  // TODO [!] check how this works with version ranges
51  @Mojo( name = "prepare", aggregator = true, requiresDependencyCollection = ResolutionScope.TEST )
52  public class PrepareReleaseMojo
53      extends AbstractScmReleaseMojo
54  {
55  
56      /**
57       * Resume a previous release attempt from the point where it was stopped.
58       */
59      @Parameter( defaultValue = "true", property = "resume" )
60      private boolean resume;
61  
62      /**
63       * @deprecated Please use release:prepare-with-pom instead.
64       */
65      @Deprecated
66      @Parameter( defaultValue = "false", property = "generateReleasePoms" )
67      private boolean generateReleasePoms;
68  
69      /**
70       * Whether to use "edit" mode on the SCM, to lock the file for editing during SCM operations.
71       */
72      @Parameter( defaultValue = "false", property = "useEditMode" )
73      private boolean useEditMode;
74  
75      /**
76       * Whether to update dependencies version to the next development version.
77       *
78       * @since 2.0-beta-5
79       */
80      @Parameter( defaultValue = "true", property = "updateDependencies" )
81      private boolean updateDependencies;
82  
83      /**
84       * Whether to automatically assign submodules the parent version. If set to false, the user will be prompted for the
85       * version of each submodules.
86       *
87       * @since 2.0-beta-5
88       */
89      @Parameter( defaultValue = "false", property = "autoVersionSubmodules" )
90      private boolean autoVersionSubmodules;
91  
92      /**
93       * Dry run: don't checkin or tag anything in the scm repository, or modify the checkout. Running
94       * <code>mvn -DdryRun=true release:prepare</code> is useful in order to check that modifications to poms and scm
95       * operations (only listed on the console) are working as expected. Modified POMs are written alongside the
96       * originals without modifying them.
97       */
98      @Parameter( defaultValue = "false", property = "dryRun" )
99      private boolean dryRun;
100 
101     /**
102      * Whether to add a schema to the POM if it was previously missing on release.
103      */
104     @Parameter( defaultValue = "true", property = "addSchema" )
105     private boolean addSchema;
106 
107     /**
108      * Goals to run as part of the preparation step, after transformation but before committing. Space delimited.
109      */
110     @Parameter( defaultValue = "clean verify", property = "preparationGoals" )
111     private String preparationGoals;
112 
113     /**
114      * Goals to run on completion of the preparation step, after transformation back to the next development version but
115      * before committing. Space delimited.
116      *
117      * @since 2.2
118      */
119     @Parameter( defaultValue = "", property = "completionGoals" )
120     private String completionGoals;
121 
122     /**
123      * Commits to do are atomic or by project.
124      *
125      * @since 2.0-beta-5
126      */
127     @Parameter( defaultValue = "false", property = "commitByProject" )
128     private boolean commitByProject;
129 
130     /**
131      * Whether to allow timestamped SNAPSHOT dependencies. Default is to fail when finding any SNAPSHOT.
132      *
133      * @since 2.0-beta-7
134      */
135     @Parameter( defaultValue = "false", property = "ignoreSnapshots" )
136     private boolean allowTimestampedSnapshots;
137 
138     /**
139      * Whether to allow usage of a SNAPSHOT version of the Release Plugin. This in an internal property used to support
140      * testing of the plugin itself in batch mode.
141      *
142      * @since 2.0-beta-9
143      */
144     @Parameter( defaultValue = "false", property = "allowReleasePluginSnapshot", readonly = true )
145     private boolean allowReleasePluginSnapshot;
146 
147     /**
148      * A list of additional exclude filters that will be skipped when checking for modifications on the working copy. Is
149      * ignored, when checkModificationExcludes is set.
150      *
151      * @since 2.1
152      */
153     @Parameter
154     private String[] checkModificationExcludes;
155 
156     /**
157      * Command-line version of checkModificationExcludes.
158      *
159      * @since 2.1
160      */
161     @Parameter( property = "checkModificationExcludeList" )
162     private String checkModificationExcludeList;
163 
164     /**
165      * Default version to use when preparing a release or a branch.
166      *
167      * @since 2.0-beta-8
168      */
169     @Parameter( property = "releaseVersion" )
170     private String releaseVersion;
171 
172     /**
173      * Default version to use for new local working copy.
174      *
175      * @since 2.0-beta-8
176      */
177     @Parameter( property = "developmentVersion" )
178     private String developmentVersion;
179 
180     /**
181      * Currently only implemented with svn scm.
182      * <ul>
183      * <li>Enables a workaround to prevent issue due to svn client > 1.5.0 (fixed in 1.6.5)
184      * (https://issues.apache.org/jira/browse/SCM-406)</li>
185      * <li>You may not want to use this in conjunction with <code>suppressCommitBeforeTag</code>, such that no poms with
186      * released versions are committed to the working copy ever.</li>
187      * </ul>
188      *
189      * @since 2.0-beta-9
190      */
191     @Parameter( defaultValue = "true", property = "remoteTagging" )
192     private boolean remoteTagging;
193 
194     /**
195      * Signs SCM tag when possible, for example when using the git-exe the '--sign' argument is used.
196      *
197      * @since 3.0.0-M4
198      */
199     @Parameter( property = "signTag" )
200     private boolean signTag = false;
201 
202     /**
203      * Whether to bump the working copy versions to <code>developmentVersion</code>.
204      *
205      * @since 2.1
206      */
207     @Parameter( defaultValue = "true", property = "updateWorkingCopyVersions" )
208     private boolean updateWorkingCopyVersions;
209 
210     /**
211      * Whether to suppress a commit of changes to the working copy before the tag is created. <br/>
212      * <br/>
213      * This requires <code>remoteTagging</code> to be set to false. <br/>
214      * <br/>
215      * <code>suppressCommitBeforeTag</code> is useful when you want to avoid poms with released versions in all
216      * revisions of your trunk or development branch.
217      *
218      * @since 2.1
219      */
220     @Parameter( defaultValue = "false", property = "suppressCommitBeforeTag" )
221     private boolean suppressCommitBeforeTag;
222 
223     /**
224      * Wait the specified number of seconds before creating the tag. <br/>
225      * <code>waitBeforeTagging</code> is useful when your source repository is synced between several instances and
226      * access to it is determined by geographical location, like the SVN repository at the Apache Software Foundation.
227      *
228      * @since 2.2
229      */
230     @Parameter( defaultValue = "0", property = "waitBeforeTagging" )
231     private int waitBeforeTagging;
232 
233     /**
234      * The role-hint for the {@link org.apache.maven.shared.release.policy.version.VersionPolicy}
235      * implementation used to calculate the project versions.
236      *
237      * @since 2.5.1
238      * @see org.apache.maven.shared.release.policies.DefaultVersionPolicy
239      */
240     @Parameter( defaultValue = "default", property = "projectVersionPolicyId" )
241     private String projectVersionPolicyId;
242 
243     /**
244      * The role-hint for the {@link org.apache.maven.shared.release.policy.naming.NamingPolicy}
245      * implementation used to calculate the project branch and tag names.
246      *
247      * @since 3.0.0-M1
248      * @see org.apache.maven.shared.release.policies.DefaultNamingPolicy
249      */
250     @Parameter( property = "projectNamingPolicyId" )
251     private String projectTagNamingPolicyId;
252 
253     /**
254      * The SCM commit comment when setting pom.xml to release.
255      * Defaults to "@{prefix} prepare release @{releaseLabel}".
256      * <p>
257      * Property interpolation is performed on the value, but in order to ensure that the interpolation occurs
258      * during release, you must use <code>@{...}</code> to reference the properties rather than <code>${...}</code>.
259      * The following properties are available:
260      * <ul>
261      *     <li><code>prefix</code> - The comment prefix.
262      *     <li><code>groupId</code> - The groupId of the root project.
263      *     <li><code>artifactId</code> - The artifactId of the root project.
264      *     <li><code>releaseLabel</code> - The release version of the root project.
265      * </ul>
266      *
267      * @since 3.0.0-M1
268      */
269     @Parameter( defaultValue = "@{prefix} prepare release @{releaseLabel}", property = "scmReleaseCommitComment" )
270     private String scmReleaseCommitComment = "@{prefix} prepare release @{releaseLabel}";
271 
272     /**
273      * The SCM commit comment when setting pom.xml back to development.
274      * Defaults to "@{prefix} prepare for next development iteration".
275      * <p>
276      * Property interpolation is performed on the value, but in order to ensure that the interpolation occurs
277      * during release, you must use <code>@{...}</code> to reference the properties rather than <code>${...}</code>.
278      * The following properties are available:
279      * <ul>
280      *     <li><code>prefix</code> - The comment prefix.
281      *     <li><code>groupId</code> - The groupId of the root project.
282      *     <li><code>artifactId</code> - The artifactId of the root project.
283      *     <li><code>releaseLabel</code> - The release version of the root project.
284      * </ul>
285      *
286      * @since 3.0.0-M1
287      */
288     @Parameter(
289             defaultValue = "@{prefix} prepare for next development iteration",
290             property = "scmDevelopmentCommitComment" )
291     private String scmDevelopmentCommitComment = "@{prefix} prepare for next development iteration";
292 
293     /**
294      * Specifies whether unresolved SNAPSHOT dependencies should automatically be resolved.
295      * If this is set, then this specifies the default answer to be used when unresolved SNAPSHOT
296      * dependencies should automatically be resolved ( 0:All 1:Project Dependencies 2:Plugins
297      * 3:Reports 4:Extensions ). Possible values are:
298      * <ul>
299      * <li>"all" or "0": resolve all kinds of snapshots, ie. project, plugin, report and extension dependencies </li>
300      * <li>"dependencies" or "1": resolve project dependencies</li>
301      * <li>"plugins" or "2": resolve plugin dependencis</li>
302      * <li>"reports" or "3": resolve report dependencies</li>
303      * <li>"extensions" or "4": resolve extension dependencies</li>
304      * </ul>
305      *
306      * @since 3.0.0-M4
307      */
308     @Parameter( property = "autoResolveSnapshots" )
309     private String autoResolveSnapshots;
310 
311     /**
312      * Currently only implemented with svn scm. Enable the {@code --pin-externals} option in
313      * {@code svn copy} command which is new in Subversion 1.9.
314      *
315      * @since 3.0.0-M4
316      */
317     @Parameter( defaultValue = "false", property = "pinExternals" )
318     private boolean pinExternals;
319 
320     /**
321      * Specifies the line separator to format pom.xml. The following properties are
322      * available:
323      * <ul>
324      * <li><code>system</code> - Use the system line separator.</li>
325      * <li><code>lf</code> - Use \n as line separator.</li>
326      * <li><code>cr</code> - Use \r as line separator.</li>
327      * <li><code>crlf</code> - Use \r\n as line separator.</li>
328      * <li><code>source</code> - Use the same line separator as it is specified in the current pom.xml.</li>
329      * </ul>
330      *
331      * @since 3.0.0-M6
332      */
333     @Parameter( defaultValue = "source", property = "lineSeparator" )
334     private String lineSeparator;
335 
336     /**
337      * {@inheritDoc}
338      */
339     @Override
340     public void execute()
341         throws MojoExecutionException, MojoFailureException
342     {
343         if ( generateReleasePoms )
344         {
345             throw new MojoFailureException( "Generating release POMs is no longer supported in release:prepare. "
346                 + "Please run release:prepare-with-pom instead." );
347         }
348 
349         prepareRelease( generateReleasePoms );
350     }
351 
352     /**
353      * <p>prepareRelease.</p>
354      *
355      * @param generateReleasePoms a boolean
356      * @throws org.apache.maven.plugin.MojoExecutionException if any.
357      * @throws org.apache.maven.plugin.MojoFailureException if any.
358      */
359     protected void prepareRelease( boolean generateReleasePoms )
360         throws MojoExecutionException, MojoFailureException
361     {
362         // this is here so the subclass can call it without getting the extra generateReleasePoms check in execute()
363         // above
364         super.execute();
365 
366         final ReleaseDescriptorBuilder config = createReleaseDescriptor();
367         config.setAddSchema( addSchema );
368         config.setGenerateReleasePoms( generateReleasePoms );
369         config.setScmUseEditMode( useEditMode );
370         config.setPreparationGoals( preparationGoals );
371         config.setCompletionGoals( completionGoals );
372         config.setCommitByProject( commitByProject );
373         config.setUpdateDependencies( updateDependencies );
374         config.setAutoVersionSubmodules( autoVersionSubmodules );
375         config.setAllowTimestampedSnapshots( allowTimestampedSnapshots );
376         config.setSnapshotReleasePluginAllowed( allowReleasePluginSnapshot );
377         config.setDefaultReleaseVersion( releaseVersion );
378         config.setDefaultDevelopmentVersion( developmentVersion );
379         config.setRemoteTagging( remoteTagging );
380         config.setScmSignTags( signTag );
381         config.setUpdateWorkingCopyVersions( updateWorkingCopyVersions );
382         config.setSuppressCommitBeforeTagOrBranch( suppressCommitBeforeTag );
383         config.setWaitBeforeTagging( waitBeforeTagging );
384         config.setProjectVersionPolicyId( projectVersionPolicyId );
385         config.setProjectNamingPolicyId( projectTagNamingPolicyId );
386         config.setScmDevelopmentCommitComment( scmDevelopmentCommitComment );
387         config.setScmReleaseCommitComment( scmReleaseCommitComment );
388         config.setAutoResolveSnapshots( autoResolveSnapshots );
389         config.setPinExternals( pinExternals );
390         config.setLineSeparator( resolveLineSeparator() );
391 
392         if ( checkModificationExcludeList != null )
393         {
394             checkModificationExcludes = checkModificationExcludeList.replaceAll( "\\s", "" ).split( "," );
395         }
396 
397         if ( checkModificationExcludes != null )
398         {
399             config.setCheckModificationExcludes( Arrays.asList( checkModificationExcludes ) );
400         }
401 
402         ReleasePrepareRequest prepareRequest = new ReleasePrepareRequest();
403         prepareRequest.setReleaseDescriptorBuilder( config );
404         prepareRequest.setReleaseEnvironment( getReleaseEnvironment() );
405         prepareRequest.setReactorProjects( getReactorProjects() );
406         prepareRequest.setReleaseManagerListener( new DefaultReleaseManagerListener( getLog(), dryRun ) );
407         prepareRequest.setResume( resume );
408         prepareRequest.setDryRun( dryRun );
409         prepareRequest.setUserProperties( session.getUserProperties() );
410 
411         try
412         {
413             releaseManager.prepare( prepareRequest );
414         }
415         catch ( ReleaseExecutionException e )
416         {
417             throw new MojoExecutionException( e.getMessage(), e );
418         }
419         catch ( ReleaseFailureException e )
420         {
421             throw new MojoFailureException( e.getMessage(), e );
422         }
423     }
424 
425     private String resolveLineSeparator() throws MojoExecutionException
426     {
427         if ( lineSeparator  == null )
428         {
429             return getLineSeparatorFromPom();
430         }
431 
432         switch ( lineSeparator )
433         {
434             case "lf":
435                 return "\n";
436             case "cr":
437                 return "\r";
438             case "crlf":
439                 return "\r\n";
440             case "system":
441                 return System.lineSeparator();
442             case "source":
443                 return getLineSeparatorFromPom();
444             default:
445                 throw new IllegalArgumentException( String.format( "Unknown property lineSeparator: '%s'. Use one of"
446                   + " the following: 'source', 'system', 'lf', 'cr', 'crlf'.", lineSeparator ) );
447         }
448     }
449 
450     private String getLineSeparatorFromPom()
451       throws MojoExecutionException
452     {
453         char current;
454         String lineSeparator = "";
455         try ( InputStream is = new FileInputStream( this.project.getFile() ) )
456         {
457             while ( is.available() > 0 )
458             {
459                 current = ( char ) is.read();
460                 if ( ( current == '\n' ) || ( current == '\r' ) )
461                 {
462                     lineSeparator += current;
463                     if ( is.available() > 0 )
464                     {
465                         char next = ( char ) is.read();
466                         if ( ( next != current )
467                           && ( ( next == '\r' ) || ( next == '\n' ) ) )
468                         {
469                             lineSeparator += next;
470                         }
471                     }
472                     return lineSeparator;
473                 }
474             }
475         }
476         catch ( IOException e )
477         {
478             throw new MojoExecutionException( "Failed to detect line separator of " + this.project.getFile(), e );
479         }
480 
481         return lineSeparator;
482     }
483 
484 }