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