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