1 package org.apache.maven.continuum.release;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.lang.BooleanUtils;
23 import org.apache.continuum.model.release.ReleaseListenerSummary;
24 import org.apache.continuum.model.repository.LocalRepository;
25 import org.apache.continuum.release.config.ContinuumReleaseDescriptor;
26 import org.apache.continuum.taskqueue.manager.TaskQueueManagerException;
27 import org.apache.maven.artifact.ArtifactUtils;
28 import org.apache.maven.continuum.model.project.Project;
29 import org.apache.maven.continuum.release.tasks.PerformReleaseProjectTask;
30 import org.apache.maven.continuum.release.tasks.PrepareReleaseProjectTask;
31 import org.apache.maven.continuum.release.tasks.RollbackReleaseProjectTask;
32 import org.apache.maven.scm.manager.ScmManager;
33 import org.apache.maven.scm.provider.ScmProvider;
34 import org.apache.maven.scm.repository.ScmRepository;
35 import org.apache.maven.shared.release.ReleaseManagerListener;
36 import org.apache.maven.shared.release.config.ReleaseDescriptor;
37 import org.apache.maven.shared.release.config.ReleaseDescriptorStore;
38 import org.apache.maven.shared.release.config.ReleaseDescriptorStoreException;
39 import org.codehaus.plexus.PlexusConstants;
40 import org.codehaus.plexus.PlexusContainer;
41 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
42 import org.codehaus.plexus.context.Context;
43 import org.codehaus.plexus.context.ContextException;
44 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
45 import org.codehaus.plexus.taskqueue.Task;
46 import org.codehaus.plexus.taskqueue.TaskQueue;
47 import org.codehaus.plexus.taskqueue.TaskQueueException;
48 import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor;
49 import org.codehaus.plexus.util.StringUtils;
50
51 import java.io.File;
52 import java.util.Collections;
53 import java.util.Hashtable;
54 import java.util.LinkedHashMap;
55 import java.util.Map;
56 import java.util.Properties;
57
58
59
60
61
62
63 public class DefaultContinuumReleaseManager
64 implements ContinuumReleaseManager, Contextualizable
65 {
66
67 private static final String PLEXUS_KEY_PERFORM_RELEASE_TASKQUEUE_EXECUTOR = "perform-release";
68
69 private static final String PLEXUS_KEY_PREPARE_RELEASE_TASKQUEUE_EXECUTOR = "prepare-release";
70
71 private static final String PLEXUS_KEY_ROLLBACK_RELEASE_TASKQUEUE_EXECUTOR = "rollback-release";
72
73
74
75
76 private ReleaseDescriptorStore releaseStore;
77
78
79
80
81 private TaskQueue prepareReleaseQueue;
82
83
84
85
86 private TaskQueue performReleaseQueue;
87
88
89
90
91 private TaskQueue rollbackReleaseQueue;
92
93
94
95
96 private ScmManager scmManager;
97
98 private PlexusContainer container;
99
100 private Map<String, ContinuumReleaseManagerListener> listeners;
101
102
103
104
105
106
107 private static Map<String, ReleaseDescriptor> preparedReleases;
108
109
110
111
112
113
114 private static Map releaseResults;
115
116 public String prepare( Project project, Properties releaseProperties, Map<String, String> relVersions,
117 Map<String, String> devVersions, ContinuumReleaseManagerListener listener,
118 String workingDirectory )
119 throws ContinuumReleaseException
120 {
121 return prepare( project, releaseProperties, relVersions, devVersions, listener, workingDirectory, null, null );
122 }
123
124 public String prepare( Project project, Properties releaseProperties, Map<String, String> relVersions,
125 Map<String, String> devVersions, ContinuumReleaseManagerListener listener,
126 String workingDirectory, Map<String, String> environments, String executable )
127 throws ContinuumReleaseException
128 {
129 String releaseId = project.getGroupId() + ":" + project.getArtifactId();
130
131 ReleaseDescriptor descriptor = getReleaseDescriptor( project, releaseProperties, relVersions, devVersions,
132 environments, workingDirectory, executable );
133
134 if ( listener == null )
135 {
136 listener = new DefaultReleaseManagerListener();
137 listener.setUsername( releaseProperties.getProperty( "release-by" ) );
138 }
139
140
141 while ( getPreparedReleases().get( releaseId ) != null )
142 {
143 releaseId = releaseId + ":" + String.valueOf( System.currentTimeMillis() );
144 }
145
146 getListeners().put( releaseId, listener );
147
148 try
149 {
150 prepareReleaseQueue.put( new PrepareReleaseProjectTask( releaseId, descriptor,
151 (ReleaseManagerListener) listener ) );
152 }
153 catch ( TaskQueueException e )
154 {
155 throw new ContinuumReleaseException( "Failed to add prepare release task in queue.", e );
156 }
157
158 return releaseId;
159 }
160
161 public void perform( String releaseId, File buildDirectory, String goals, String arguments,
162 boolean useReleaseProfile, ContinuumReleaseManagerListener listener )
163 throws ContinuumReleaseException
164 {
165 perform( releaseId, buildDirectory, goals, arguments, useReleaseProfile, listener, null );
166 }
167
168 public void perform( String releaseId, File buildDirectory, String goals, String arguments,
169 boolean useReleaseProfile, ContinuumReleaseManagerListener listener,
170 LocalRepository repository )
171 throws ContinuumReleaseException
172 {
173 ReleaseDescriptor descriptor = getPreparedReleases().get( releaseId );
174 if ( descriptor != null )
175 {
176 perform( releaseId, descriptor, buildDirectory, goals, arguments, useReleaseProfile, listener, repository );
177 }
178 }
179
180 public void perform( String releaseId, String workingDirectory, File buildDirectory, String goals, String arguments,
181 boolean useReleaseProfile, ContinuumReleaseManagerListener listener )
182 throws ContinuumReleaseException
183 {
184 ReleaseDescriptor descriptor = readReleaseDescriptor( workingDirectory );
185 perform( releaseId, descriptor, buildDirectory, goals, arguments, useReleaseProfile, listener, null );
186 }
187
188 private void perform( String releaseId, ReleaseDescriptor descriptor, File buildDirectory, String goals,
189 String arguments, boolean useReleaseProfile, ContinuumReleaseManagerListener listener,
190 LocalRepository repository )
191 throws ContinuumReleaseException
192 {
193 if ( descriptor != null )
194 {
195 descriptor.setAdditionalArguments( arguments );
196 }
197
198 if ( listener == null )
199 {
200 listener = new DefaultReleaseManagerListener();
201 if ( descriptor instanceof ContinuumReleaseDescriptor )
202 {
203 listener.setUsername( ( (ContinuumReleaseDescriptor) descriptor ).getReleaseBy() );
204 }
205 }
206
207 try
208 {
209 getListeners().put( releaseId, listener );
210
211 performReleaseQueue.put( new PerformReleaseProjectTask( releaseId, descriptor, buildDirectory, goals,
212 useReleaseProfile,
213 (ReleaseManagerListener) listener, repository ) );
214 }
215 catch ( TaskQueueException e )
216 {
217 throw new ContinuumReleaseException( "Failed to add perform release task in queue.", e );
218 }
219 }
220
221 public void rollback( String releaseId, String workingDirectory, ContinuumReleaseManagerListener listener )
222 throws ContinuumReleaseException
223 {
224 ReleaseDescriptor descriptor = readReleaseDescriptor( workingDirectory );
225
226 if ( listener == null )
227 {
228 listener = new DefaultReleaseManagerListener();
229 if ( descriptor instanceof ContinuumReleaseDescriptor )
230 {
231 listener.setUsername( ( (ContinuumReleaseDescriptor) descriptor ).getReleaseBy() );
232 }
233 }
234
235 rollback( releaseId, descriptor, listener );
236 }
237
238 private void rollback( String releaseId, ReleaseDescriptor descriptor, ContinuumReleaseManagerListener listener )
239 throws ContinuumReleaseException
240 {
241 Task releaseTask = new RollbackReleaseProjectTask( releaseId, descriptor, (ReleaseManagerListener) listener );
242
243 try
244 {
245 rollbackReleaseQueue.put( releaseTask );
246 }
247 catch ( TaskQueueException e )
248 {
249 throw new ContinuumReleaseException( "Failed to rollback release.", e );
250 }
251 }
252
253 public Map<String, ReleaseDescriptor> getPreparedReleases()
254 {
255 if ( preparedReleases == null )
256 {
257 preparedReleases = Collections.synchronizedMap( new LinkedHashMap<String, ReleaseDescriptor>() );
258 }
259
260 return preparedReleases;
261 }
262
263 public Map<String, String> getPreparedReleasesForProject( String groupId, String artifactId )
264 {
265 String key = ArtifactUtils.versionlessKey( groupId, artifactId );
266
267 Map<String, String> projectPreparedReleases = new LinkedHashMap<String, String>();
268 Map<String, ReleaseDescriptor> preparedReleases = getPreparedReleases();
269 for ( String releaseId : preparedReleases.keySet() )
270 {
271
272 if ( releaseId.equals( key ) || releaseId.startsWith( key + ":" ) )
273 {
274 ReleaseDescriptor descriptor = preparedReleases.get( releaseId );
275
276
277 projectPreparedReleases.put( releaseId, descriptor.getReleaseVersions().get( key ).toString() );
278 }
279 }
280 return projectPreparedReleases;
281 }
282
283 public Map getReleaseResults()
284 {
285 if ( releaseResults == null )
286 {
287 releaseResults = new Hashtable();
288 }
289
290 return releaseResults;
291 }
292
293 private ReleaseDescriptor getReleaseDescriptor( Project project, Properties releaseProperties,
294 Map<String, String> relVersions, Map<String, String> devVersions,
295 Map<String, String> environments, String workingDirectory,
296 String executable )
297 {
298 ContinuumReleaseDescriptor descriptor = new ContinuumReleaseDescriptor();
299
300
301 descriptor.setWorkingDirectory( workingDirectory );
302 descriptor.setScmSourceUrl( project.getScmUrl() );
303
304
305 descriptor.setScmReleaseLabel( releaseProperties.getProperty( "scm-tag" ) );
306 descriptor.setScmTagBase( releaseProperties.getProperty( "scm-tagbase" ) );
307 descriptor.setReleaseVersions( relVersions );
308 descriptor.setDevelopmentVersions( devVersions );
309 descriptor.setPreparationGoals( releaseProperties.getProperty( "preparation-goals" ) );
310 descriptor.setAdditionalArguments( releaseProperties.getProperty( "arguments" ) );
311 descriptor.setAddSchema( Boolean.valueOf( releaseProperties.getProperty( "add-schema" ) ) );
312 descriptor.setAutoVersionSubmodules( Boolean.valueOf( releaseProperties.getProperty(
313 "auto-version-submodules" ) ) );
314
315 String useEditMode = releaseProperties.getProperty( "use-edit-mode" );
316 if ( BooleanUtils.toBoolean( useEditMode ) )
317 {
318 descriptor.setScmUseEditMode( Boolean.valueOf( useEditMode ) );
319 }
320
321 LocalRepository repository = project.getProjectGroup().getLocalRepository();
322
323 if ( repository != null )
324 {
325 String args = descriptor.getAdditionalArguments();
326
327 if ( StringUtils.isNotEmpty( args ) )
328 {
329 descriptor.setAdditionalArguments( args +
330 " \"-Dmaven.repo.local=" + repository.getLocation() + "\"" );
331 }
332 else
333 {
334 descriptor.setAdditionalArguments( "\"-Dmaven.repo.local=" + repository.getLocation() + "\"" );
335 }
336 }
337
338
339 if ( releaseProperties.containsKey( "scm-username" ) )
340 {
341 descriptor.setScmUsername( releaseProperties.getProperty( "scm-username" ) );
342 }
343 if ( releaseProperties.containsKey( "scm-password" ) )
344 {
345 descriptor.setScmPassword( releaseProperties.getProperty( "scm-password" ) );
346 }
347 if ( releaseProperties.containsKey( "scm-comment-prefix" ) )
348 {
349 descriptor.setScmCommentPrefix( releaseProperties.getProperty( "scm-comment-prefix" ) );
350 }
351 if ( releaseProperties.containsKey( "use-release-profile" ) )
352 {
353 descriptor.setUseReleaseProfile( Boolean.valueOf( releaseProperties.getProperty(
354 "use-release-profile" ) ) );
355 }
356
357
358 descriptor.setInteractive( false );
359
360
361 descriptor.setEnvironments( environments );
362 descriptor.setExecutable( executable );
363
364
365 descriptor.setReleaseBy( releaseProperties.getProperty( "release-by" ) );
366
367 return descriptor;
368 }
369
370 private ReleaseDescriptor readReleaseDescriptor( String workingDirectory )
371 throws ContinuumReleaseException
372 {
373 ReleaseDescriptor descriptor = new ContinuumReleaseDescriptor();
374 descriptor.setWorkingDirectory( workingDirectory );
375
376 try
377 {
378 descriptor = releaseStore.read( descriptor );
379 }
380 catch ( ReleaseDescriptorStoreException e )
381 {
382 throw new ContinuumReleaseException( "Failed to parse descriptor file.", e );
383 }
384
385 return descriptor;
386 }
387
388 public Map<String, ContinuumReleaseManagerListener> getListeners()
389 {
390 if ( listeners == null )
391 {
392 listeners = new Hashtable<String, ContinuumReleaseManagerListener>();
393 }
394
395 return listeners;
396 }
397
398 public String sanitizeTagName( String scmUrl, String tagName )
399 throws Exception
400 {
401 ScmRepository scmRepo = scmManager.makeScmRepository( scmUrl );
402 ScmProvider scmProvider = scmManager.getProviderByRepository( scmRepo );
403 return scmProvider.sanitizeTagName( tagName );
404 }
405
406 public ReleaseListenerSummary getListener( String releaseId )
407 {
408 ContinuumReleaseManagerListener listener = (ContinuumReleaseManagerListener) getListeners().get( releaseId );
409
410 if ( listener != null )
411 {
412 ReleaseListenerSummary listenerSummary = new ReleaseListenerSummary();
413 listenerSummary.setGoalName( listener.getGoalName() );
414 listenerSummary.setError( listener.getError() );
415 listenerSummary.setInProgress( listener.getInProgress() );
416 listenerSummary.setState( listener.getState() );
417 listenerSummary.setPhases( listener.getPhases() );
418 listenerSummary.setCompletedPhases( listener.getCompletedPhases() );
419 listenerSummary.setUsername( listener.getUsername() );
420
421 return listenerSummary;
422 }
423
424 return null;
425 }
426
427 public boolean isExecutingRelease()
428 throws Exception
429 {
430 return prepareReleaseQueue.getQueueSnapshot().size() > 0 ||
431 performReleaseQueue.getQueueSnapshot().size() > 0 ||
432 rollbackReleaseQueue.getQueueSnapshot().size() > 0 ||
433 getPerformReleaseTaskQueueExecutor().getCurrentTask() != null ||
434 getPrepareReleaseTaskQueueExecutor().getCurrentTask() != null ||
435 getRollbackReleaseTaskQueueExecutor().getCurrentTask() != null;
436 }
437
438
439 public TaskQueueExecutor getPerformReleaseTaskQueueExecutor()
440 throws TaskQueueManagerException
441 {
442 try
443 {
444 return (TaskQueueExecutor) container.lookup( TaskQueueExecutor.class,
445 PLEXUS_KEY_PERFORM_RELEASE_TASKQUEUE_EXECUTOR );
446 }
447 catch ( ComponentLookupException e )
448 {
449 throw new TaskQueueManagerException( e.getMessage(), e );
450 }
451 }
452
453 public TaskQueueExecutor getPrepareReleaseTaskQueueExecutor()
454 throws TaskQueueManagerException
455 {
456 try
457 {
458 return (TaskQueueExecutor) container.lookup( TaskQueueExecutor.class,
459 PLEXUS_KEY_PREPARE_RELEASE_TASKQUEUE_EXECUTOR );
460 }
461 catch ( ComponentLookupException e )
462 {
463 throw new TaskQueueManagerException( e.getMessage(), e );
464 }
465 }
466
467 public TaskQueueExecutor getRollbackReleaseTaskQueueExecutor()
468 throws TaskQueueManagerException
469 {
470 try
471 {
472 return (TaskQueueExecutor) container.lookup( TaskQueueExecutor.class,
473 PLEXUS_KEY_ROLLBACK_RELEASE_TASKQUEUE_EXECUTOR );
474 }
475 catch ( ComponentLookupException e )
476 {
477 throw new TaskQueueManagerException( e.getMessage(), e );
478 }
479 }
480
481 public void contextualize( Context context )
482 throws ContextException
483 {
484 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
485 }
486 }