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.File;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.maven.execution.MavenSession;
28 import org.apache.maven.model.Profile;
29 import org.apache.maven.plugin.AbstractMojo;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.project.MavenProject;
33 import org.apache.maven.scm.manager.ScmManager;
34 import org.apache.maven.settings.Settings;
35 import org.apache.maven.shared.release.ReleaseManager;
36 import org.apache.maven.shared.release.config.ReleaseDescriptor;
37 import org.apache.maven.shared.release.env.DefaultReleaseEnvironment;
38 import org.apache.maven.shared.release.env.ReleaseEnvironment;
39 import org.codehaus.plexus.util.StringUtils;
40
41 /**
42 * Base class with shared configuration.
43 *
44 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
45 * @version $Id: AbstractReleaseMojo.java 1333174 2012-05-02 19:52:18Z rfscholte $
46 */
47 public abstract class AbstractReleaseMojo
48 extends AbstractMojo
49 {
50 /**
51 * The SCM username to use.
52 *
53 * @parameter expression="${username}"
54 */
55 private String username;
56
57 /**
58 * The SCM password to use.
59 *
60 * @parameter expression="${password}"
61 */
62 private String password;
63
64 /**
65 * The SCM tag to use.
66 *
67 * @parameter expression="${tag}" alias="releaseLabel"
68 */
69 private String tag;
70
71 /**
72 * Format to use when generating the tag name if none is specified. Property interpolation is performed on the
73 * tag, but in order to ensure that the interpolation occurs during release, you must use <code>@{...}</code>
74 * to reference the properties rather than <code>${...}</code>. The following properties are available:
75 * <ul>
76 * <li><code>groupId</code> or <code>project.groupId</code> - The groupId of the root project.
77 * <li><code>artifactId</code> or <code>project.artifactId</code> - The artifactId of the root project.
78 * <li><code>version</code> or <code>project.version</code> - The release version of the root project.
79 * </ul>
80 *
81 * @parameter expression="${tagNameFormat}" default-value="@{project.artifactId}-@{project.version}"
82 * @since 2.2.0
83 */
84 private String tagNameFormat;
85
86 /**
87 * The tag base directory in SVN, you must define it if you don't use the standard svn layout (trunk/tags/branches).
88 * For example, <code>http://svn.apache.org/repos/asf/maven/plugins/tags</code>. The URL is an SVN URL and does not
89 * include the SCM provider and protocol.
90 *
91 * @parameter expression="${tagBase}"
92 */
93 private String tagBase;
94
95 /**
96 * @parameter default-value="${basedir}"
97 * @required
98 * @readonly
99 */
100 private File basedir;
101
102 /**
103 * @parameter default-value="${settings}"
104 * @required
105 * @readonly
106 */
107 private Settings settings;
108
109 /**
110 * @parameter default-value="${project}"
111 * @required
112 * @readonly
113 */
114 protected MavenProject project;
115
116 /**
117 * @component
118 */
119 protected ReleaseManager releaseManager;
120
121 /**
122 * Additional arguments to pass to the Maven executions, separated by spaces.
123 *
124 * @parameter expression="${arguments}" alias="prepareVerifyArgs"
125 */
126 private String arguments;
127
128 /**
129 * The file name of the POM to execute any goals against.
130 *
131 * @parameter expression="${pomFileName}"
132 */
133 private String pomFileName;
134
135 /**
136 * The message prefix to use for all SCM changes.
137 *
138 * @parameter expression="${scmCommentPrefix}" default-value="[maven-release-plugin] "
139 * @since 2.0-beta-5
140 */
141 private String scmCommentPrefix;
142
143 /**
144 * @parameter default-value="${reactorProjects}"
145 * @required
146 * @readonly
147 */
148 private List<MavenProject> reactorProjects;
149
150 /**
151 * Add a new or overwrite the default implementation per provider.
152 * The key is the scm prefix and the value is the role hint of the {@link org.apache.maven.scm.provider.ScmProvider}.
153 *
154 * @parameter
155 * @since 2.0-beta-6
156 * @see ScmManager#setScmProviderImplementation(String, String)
157 */
158 private Map<String, String> providerImplementations;
159
160 /**
161 * The {@code M2_HOME} parameter to use for forked Maven invocations.
162 *
163 * @parameter default-value="${maven.home}"
164 * @since 2.0-beta-8
165 */
166 protected File mavenHome;
167
168 /**
169 * The {@code JAVA_HOME} parameter to use for forked Maven invocations.
170 *
171 * @parameter default-value="${java.home}"
172 * @since 2.0-beta-8
173 */
174 private File javaHome;
175
176 /**
177 * The command-line local repository directory in use for this build (if specified).
178 *
179 * @parameter default-value="${maven.repo.local}"
180 * @since 2.0-beta-8
181 */
182 private File localRepoDirectory;
183
184 /**
185 * Role hint of the {@link org.apache.maven.shared.release.exec.MavenExecutor} implementation to use.
186 *
187 * @parameter expression="${mavenExecutorId}" default-value="invoker"
188 * @since 2.0-beta-8
189 */
190 private String mavenExecutorId;
191
192 /**
193 * Use a local checkout instead of doing a checkout from the upstream repository.
194 * ATTENTION: This will only work with distributed SCMs which support the file:// protocol
195 * like e.g. git, jgit or hg!
196 *
197 * TODO: we should think about having the defaults for the various SCM providers provided via modello!
198 *
199 * @parameter expression="${localCheckout}" default-value="false"
200 * @since 2.0
201 */
202 private boolean localCheckout;
203
204 /**
205 * Implemented with git will or not push changes to the upstream repository.
206 * <code>true</code> by default to preserve backward compatibility.
207 * @parameter expression="${pushChanges}" default-value="true"
208 * @since 2.1
209 */
210 private boolean pushChanges = true;
211
212 /**
213 * The SCM manager.
214 *
215 * @component
216 */
217 private ScmManager scmManager;
218
219 /**
220 * @parameter default-value="${session}"
221 * @readonly
222 * @required
223 * @since 2.0
224 */
225 protected MavenSession session;
226
227
228 /**
229 * Gets the enviroment settings configured for this release.
230 *
231 * @return The release environment, never <code>null</code>.
232 */
233 protected ReleaseEnvironment getReleaseEnvironment()
234 {
235 return new DefaultReleaseEnvironment().setSettings( settings )
236 .setJavaHome( javaHome )
237 .setMavenHome( mavenHome )
238 .setLocalRepositoryDirectory( localRepoDirectory )
239 .setMavenExecutorId( mavenExecutorId );
240 }
241
242 /**
243 * {@inheritDoc}
244 */
245 public void execute()
246 throws MojoExecutionException, MojoFailureException
247 {
248 if ( providerImplementations != null )
249 {
250 for ( Map.Entry<String, String> providerEntry : providerImplementations.entrySet() )
251 {
252 getLog().info( "Change the default '" + providerEntry.getKey() + "' provider implementation to '"
253 + providerEntry.getValue() + "'." );
254 scmManager.setScmProviderImplementation( providerEntry.getKey(), providerEntry.getValue() );
255 }
256 }
257 }
258
259 /**
260 * Creates the release descriptor from the various goal parameters.
261 *
262 * @return The release descriptor, never <code>null</code>.
263 */
264 protected ReleaseDescriptor createReleaseDescriptor()
265 {
266 ReleaseDescriptor descriptor = new ReleaseDescriptor();
267
268 descriptor.setInteractive( settings.isInteractiveMode() );
269
270 descriptor.setScmPassword( password );
271 descriptor.setScmReleaseLabel( tag );
272 descriptor.setScmTagNameFormat( tagNameFormat );
273 descriptor.setScmTagBase( tagBase );
274 descriptor.setScmUsername( username );
275 descriptor.setScmCommentPrefix( scmCommentPrefix );
276
277 descriptor.setWorkingDirectory( basedir.getAbsolutePath() );
278
279 descriptor.setPomFileName( pomFileName );
280
281 descriptor.setLocalCheckout( localCheckout );
282
283 descriptor.setPushChanges( pushChanges );
284
285 @SuppressWarnings("unchecked")
286 List<Profile> profiles = project.getActiveProfiles();
287
288 String arguments = this.arguments;
289 if ( profiles != null && !profiles.isEmpty() )
290 {
291 if ( !StringUtils.isEmpty( arguments ) )
292 {
293 arguments += " -P ";
294 }
295 else
296 {
297 arguments = "-P ";
298 }
299
300 for ( Iterator<Profile> it = profiles.iterator(); it.hasNext(); )
301 {
302 Profile profile = it.next();
303
304 arguments += profile.getId();
305 if ( it.hasNext() )
306 {
307 arguments += ",";
308 }
309 }
310
311 String additionalProfiles = getAdditionalProfiles();
312 if ( additionalProfiles != null )
313 {
314 if ( !profiles.isEmpty() )
315 {
316 arguments += ",";
317 }
318 arguments += additionalProfiles;
319 }
320 }
321 descriptor.setAdditionalArguments( arguments );
322
323 return descriptor;
324 }
325
326 /**
327 * Gets the comma separated list of additional profiles for the release build.
328 *
329 * @return additional profiles to enable during release
330 */
331 protected String getAdditionalProfiles()
332 {
333 return null;
334 }
335
336 /**
337 * Sets the component used to perform release actions.
338 *
339 * @param releaseManager The release manager implementation to use, must not be <code>null</code>.
340 */
341 void setReleaseManager( ReleaseManager releaseManager )
342 {
343 this.releaseManager = releaseManager;
344 }
345
346 /**
347 * Gets the effective settings for this build.
348 *
349 * @return The effective settings for this build, never <code>null</code>.
350 */
351 Settings getSettings()
352 {
353 return settings;
354 }
355
356 protected final File getBasedir()
357 {
358 return basedir;
359 }
360
361 /**
362 * Sets the base directory of the build.
363 *
364 * @param basedir The build's base directory, must not be <code>null</code>.
365 */
366 public void setBasedir( File basedir )
367 {
368 this.basedir = basedir;
369 }
370
371 /**
372 * Gets the list of projects in the build reactor.
373 *
374 * @return The list of reactor project, never <code>null</code>.
375 */
376 public List<MavenProject> getReactorProjects()
377 {
378 return reactorProjects;
379 }
380
381 /**
382 * Add additional arguments.
383 *
384 * @param argument The argument to add, must not be <code>null</code>.
385 */
386 protected void addArgument( String argument )
387 {
388 if ( arguments != null )
389 {
390 arguments += " " + argument;
391 }
392 else
393 {
394 arguments = argument;
395 }
396 }
397
398 /**
399 * This method takes some of the release configuration picked up from the command line system properties and copies
400 * it into the release config object.
401 *
402 * @param config The release configuration to merge the system properties into, must not be <code>null</code>.
403 * @param sysPropertiesConfig The configuration from the system properties to merge in, must not be
404 * <code>null</code>.
405 */
406 protected void mergeCommandLineConfig( ReleaseDescriptor config, ReleaseDescriptor sysPropertiesConfig )
407 {
408 // If the user specifies versions, these should override the existing versions
409 if ( sysPropertiesConfig.getReleaseVersions() != null )
410 {
411 config.getReleaseVersions().putAll( sysPropertiesConfig.getReleaseVersions() );
412 }
413 if ( sysPropertiesConfig.getDevelopmentVersions() != null )
414 {
415 config.getDevelopmentVersions().putAll( sysPropertiesConfig.getDevelopmentVersions() );
416 }
417 }
418 }