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      * @since 3.0.0
112      */
113     @Parameter(property = "preparationProfiles")
114     private String preparationProfiles;
115 
116     /**
117      * Goals to run as part of the preparation step, after transformation but before committing. Space delimited.
118      */
119     @Parameter(defaultValue = "clean verify", property = "preparationGoals")
120     private String preparationGoals;
121 
122     /**
123      * Goals to run on completion of the preparation step, after transformation back to the next development version but
124      * before committing. Space delimited.
125      *
126      * @since 2.2
127      */
128     @Parameter(defaultValue = "", property = "completionGoals")
129     private String completionGoals;
130 
131     /**
132      * Commits to do are atomic or by project.
133      *
134      * @since 2.0-beta-5
135      */
136     @Parameter(defaultValue = "false", property = "commitByProject")
137     private boolean commitByProject;
138 
139     /**
140      * Whether to allow timestamped SNAPSHOT dependencies. Default is to fail when finding any SNAPSHOT.
141      *
142      * @since 2.0-beta-7
143      */
144     @Parameter(defaultValue = "false", property = "ignoreSnapshots")
145     private boolean allowTimestampedSnapshots;
146 
147     /**
148      * Whether to allow usage of a SNAPSHOT version of the Release Plugin. This in an internal property used to support
149      * testing of the plugin itself in batch mode.
150      *
151      * @since 2.0-beta-9
152      */
153     @Parameter(defaultValue = "false", property = "allowReleasePluginSnapshot", readonly = true)
154     private boolean allowReleasePluginSnapshot;
155 
156     /**
157      * A list of additional exclude filters that will be skipped when checking for modifications on the working copy. Is
158      * ignored, when checkModificationExcludes is set.
159      *
160      * @since 2.1
161      */
162     @Parameter
163     private String[] checkModificationExcludes;
164 
165     /**
166      * Command-line version of checkModificationExcludes.
167      *
168      * @since 2.1
169      */
170     @Parameter(property = "checkModificationExcludeList")
171     private String checkModificationExcludeList;
172 
173     /**
174      * Default version to use when preparing a release or a branch.
175      *
176      * @since 2.0-beta-8
177      */
178     @Parameter(property = "releaseVersion")
179     private String releaseVersion;
180 
181     /**
182      * Default version to use for new local working copy.
183      *
184      * @since 2.0-beta-8
185      */
186     @Parameter(property = "developmentVersion")
187     private String developmentVersion;
188 
189     /**
190      * Currently only implemented with svn scm.
191      * <ul>
192      * <li>Enables a workaround to prevent issue due to svn client > 1.5.0 (fixed in 1.6.5)
193      * (https://issues.apache.org/jira/browse/SCM-406)</li>
194      * <li>You may not want to use this in conjunction with <code>suppressCommitBeforeTag</code>, such that no poms with
195      * released versions are committed to the working copy ever.</li>
196      * </ul>
197      *
198      * @since 2.0-beta-9
199      */
200     @Parameter(defaultValue = "true", property = "remoteTagging")
201     private boolean remoteTagging;
202 
203     /**
204      * Signs SCM tag when possible, for example when using the git-exe the '--sign' argument is used.
205      *
206      * @since 3.0.0-M4
207      */
208     @Parameter(property = "signTag")
209     private boolean signTag = false;
210 
211     /**
212      * Whether to bump the working copy versions to <code>developmentVersion</code>.
213      *
214      * @since 2.1
215      */
216     @Parameter(defaultValue = "true", property = "updateWorkingCopyVersions")
217     private boolean updateWorkingCopyVersions;
218 
219     /**
220      * Whether to suppress a commit of changes to the working copy before the tag is created. <br/>
221      * <br/>
222      * This requires <code>remoteTagging</code> to be set to false. <br/>
223      * <br/>
224      * <code>suppressCommitBeforeTag</code> is useful when you want to avoid poms with released versions in all
225      * revisions of your trunk or development branch.
226      *
227      * @since 2.1
228      */
229     @Parameter(defaultValue = "false", property = "suppressCommitBeforeTag")
230     private boolean suppressCommitBeforeTag;
231 
232     /**
233      * Wait the specified number of seconds before creating the tag. <br/>
234      * <code>waitBeforeTagging</code> is useful when your source repository is synced between several instances and
235      * access to it is determined by geographical location, like the SVN repository at the Apache Software Foundation.
236      *
237      * @since 2.2
238      */
239     @Parameter(defaultValue = "0", property = "waitBeforeTagging")
240     private int waitBeforeTagging;
241 
242     /**
243      * The role-hint for the {@link org.apache.maven.shared.release.policy.version.VersionPolicy}
244      * implementation used to calculate the project versions.
245      *
246      * @since 2.5.1
247      * @see org.apache.maven.shared.release.policies.DefaultVersionPolicy
248      */
249     @Parameter(defaultValue = "default", property = "projectVersionPolicyId")
250     private String projectVersionPolicyId;
251 
252     /**
253      * Optional config for the VersionPolicy implementation used to calculate the project versions.
254      *
255      * @since 3.0.0
256      */
257     @Parameter(property = "projectVersionPolicyConfig")
258     private PlexusConfiguration projectVersionPolicyConfig;
259 
260     /**
261      * The role-hint for the {@link org.apache.maven.shared.release.policy.naming.NamingPolicy}
262      * implementation used to calculate the project branch and tag names.
263      *
264      * @since 3.0.0-M1
265      * @see org.apache.maven.shared.release.policies.DefaultNamingPolicy
266      */
267     @Parameter(property = "projectNamingPolicyId")
268     private String projectTagNamingPolicyId;
269 
270     /**
271      * The SCM commit comment when setting pom.xml to release.
272      * Defaults to "@{prefix} prepare release @{releaseLabel}".
273      * <p>
274      * Property interpolation is performed on the value, but in order to ensure that the interpolation occurs
275      * during release, you must use <code>@{...}</code> to reference the properties rather than <code>${...}</code>.
276      * The following properties are available:
277      * <ul>
278      *     <li><code>prefix</code> - The comment prefix.
279      *     <li><code>groupId</code> - The groupId of the root project.
280      *     <li><code>artifactId</code> - The artifactId of the root project.
281      *     <li><code>releaseLabel</code> - The release version of the root project.
282      * </ul>
283      *
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 when setting pom.xml back to development.
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 }