1 package org.apache.maven.shared.release;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.util.Collections;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.lang3.BooleanUtils;
30 import org.apache.maven.shared.release.config.ReleaseDescriptor;
31 import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
32 import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor;
33 import org.apache.maven.shared.release.config.ReleaseDescriptorStore;
34 import org.apache.maven.shared.release.config.ReleaseDescriptorStoreException;
35 import org.apache.maven.shared.release.config.ReleaseUtils;
36 import org.apache.maven.shared.release.phase.ReleasePhase;
37 import org.apache.maven.shared.release.phase.ResourceGenerator;
38 import org.apache.maven.shared.release.strategy.Strategy;
39 import org.codehaus.plexus.component.annotations.Component;
40 import org.codehaus.plexus.component.annotations.Requirement;
41 import org.codehaus.plexus.logging.AbstractLogEnabled;
42 import org.codehaus.plexus.util.StringUtils;
43
44
45
46
47
48
49 @Component( role = ReleaseManager.class )
50 public class DefaultReleaseManager
51 extends AbstractLogEnabled
52 implements ReleaseManager
53 {
54 @Requirement
55 private Map<String, Strategy> strategies;
56
57
58
59
60 @Requirement
61 private Map<String, ReleasePhase> releasePhases;
62
63
64
65
66 @Requirement( hint = "properties" )
67 private ReleaseDescriptorStore configStore;
68
69 private static final int PHASE_SKIP = 0, PHASE_START = 1, PHASE_END = 2, GOAL_END = 12, ERROR = 99;
70
71 @Override
72 public ReleaseResult prepareWithResult( ReleasePrepareRequest prepareRequest )
73 {
74 ReleaseResult result = new ReleaseResult();
75
76 result.setStartTime( System.currentTimeMillis() );
77
78 try
79 {
80 prepare( prepareRequest, result );
81
82 result.setResultCode( ReleaseResult.SUCCESS );
83 }
84 catch ( ReleaseExecutionException | ReleaseFailureException e )
85 {
86 captureException( result, prepareRequest.getReleaseManagerListener(), e );
87 }
88 finally
89 {
90 result.setEndTime( System.currentTimeMillis() );
91 }
92
93 return result;
94 }
95
96 @Override
97 public void prepare( ReleasePrepareRequest prepareRequest )
98 throws ReleaseExecutionException, ReleaseFailureException
99 {
100 prepare( prepareRequest, new ReleaseResult() );
101 }
102
103 private void prepare( ReleasePrepareRequest prepareRequest, ReleaseResult result )
104 throws ReleaseExecutionException, ReleaseFailureException
105 {
106
107 final ReleaseDescriptorBuilder builder = prepareRequest.getReleaseDescriptorBuilder();
108
109
110 ReleaseUtils.copyPropertiesToReleaseDescriptor( prepareRequest.getUserProperties(),
111 new ReleaseDescriptorBuilder()
112 {
113 public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
114 String value )
115 {
116 builder.addDevelopmentVersion( key, value );
117 return this;
118 }
119
120 public ReleaseDescriptorBuilder addReleaseVersion( String key,
121 String value )
122 {
123 builder.addReleaseVersion( key, value );
124 return this;
125 }
126
127 public ReleaseDescriptorBuilder addDependencyReleaseVersion( String dependencyKey,
128 String version )
129 {
130 builder.addDependencyReleaseVersion( dependencyKey, version );
131 return this;
132 }
133
134 public ReleaseDescriptorBuilder addDependencyDevelopmentVersion( String dependencyKey,
135 String version )
136 {
137 builder.addDependencyDevelopmentVersion( dependencyKey, version );
138 return this;
139 }
140 } );
141
142 BuilderReleaseDescriptor config;
143 if ( BooleanUtils.isNotFalse( prepareRequest.getResume() ) )
144 {
145 config = loadReleaseDescriptor( builder, prepareRequest.getReleaseManagerListener() );
146 }
147 else
148 {
149 config = ReleaseUtils.buildReleaseDescriptor( builder );
150 }
151
152 Strategy releaseStrategy = getStrategy( config.getReleaseStrategyId() );
153
154 List<String> preparePhases = getGoalPhases( releaseStrategy, "prepare" );
155
156 goalStart( prepareRequest.getReleaseManagerListener(), "prepare", preparePhases );
157
158
159
160
161 String completedPhase = config.getCompletedPhase();
162 int index = preparePhases.indexOf( completedPhase );
163
164 for ( int idx = 0; idx <= index; idx++ )
165 {
166 updateListener( prepareRequest.getReleaseManagerListener(), preparePhases.get( idx ), PHASE_SKIP );
167 }
168
169 if ( index == preparePhases.size() - 1 )
170 {
171 logInfo( result, "Release preparation already completed. You can now continue with release:perform, "
172 + "or start again using the -Dresume=false flag" );
173 }
174 else if ( index >= 0 )
175 {
176 logInfo( result, "Resuming release from phase '" + preparePhases.get( index + 1 ) + "'" );
177 }
178
179
180 for ( int i = index + 1; i < preparePhases.size(); i++ )
181 {
182 String name = preparePhases.get( i );
183
184 ReleasePhase phase = releasePhases.get( name );
185
186 if ( phase == null )
187 {
188 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
189 }
190
191 updateListener( prepareRequest.getReleaseManagerListener(), name, PHASE_START );
192
193 ReleaseResult phaseResult = null;
194 try
195 {
196 if ( BooleanUtils.isTrue( prepareRequest.getDryRun() ) )
197 {
198 phaseResult = phase.simulate( config,
199 prepareRequest.getReleaseEnvironment(),
200 prepareRequest.getReactorProjects() );
201 }
202 else
203 {
204 phaseResult = phase.execute( config,
205 prepareRequest.getReleaseEnvironment(),
206 prepareRequest.getReactorProjects() );
207 }
208 }
209 finally
210 {
211 if ( result != null && phaseResult != null )
212 {
213 result.appendOutput( phaseResult.getOutput() );
214 }
215 }
216
217 config.setCompletedPhase( name );
218 try
219 {
220 configStore.write( config );
221 }
222 catch ( ReleaseDescriptorStoreException e )
223 {
224
225 throw new ReleaseExecutionException( "Error writing release properties after completing phase", e );
226 }
227
228 updateListener( prepareRequest.getReleaseManagerListener(), name, PHASE_END );
229 }
230
231 updateListener( prepareRequest.getReleaseManagerListener(), "prepare", GOAL_END );
232 }
233
234 @Override
235 public void rollback( ReleaseRollbackRequest rollbackRequest )
236 throws ReleaseExecutionException, ReleaseFailureException
237 {
238 ReleaseDescriptor releaseDescriptor =
239 loadReleaseDescriptor( rollbackRequest.getReleaseDescriptorBuilder(), null );
240
241 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
242
243 List<String> rollbackPhases = getGoalPhases( releaseStrategy, "rollback" );
244
245 goalStart( rollbackRequest.getReleaseManagerListener(), "rollback", rollbackPhases );
246
247 for ( String name : rollbackPhases )
248 {
249 ReleasePhase phase = releasePhases.get( name );
250
251 if ( phase == null )
252 {
253 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
254 }
255
256 updateListener( rollbackRequest.getReleaseManagerListener(), name, PHASE_START );
257 phase.execute( releaseDescriptor,
258 rollbackRequest.getReleaseEnvironment(),
259 rollbackRequest.getReactorProjects() );
260 updateListener( rollbackRequest.getReleaseManagerListener(), name, PHASE_END );
261 }
262
263
264 clean( rollbackRequest );
265 updateListener( rollbackRequest.getReleaseManagerListener(), "rollback", GOAL_END );
266 }
267
268 @Override
269 public ReleaseResult performWithResult( ReleasePerformRequest performRequest )
270 {
271 ReleaseResult result = new ReleaseResult();
272
273 try
274 {
275 result.setStartTime( System.currentTimeMillis() );
276
277 perform( performRequest, result );
278
279 result.setResultCode( ReleaseResult.SUCCESS );
280 }
281 catch ( ReleaseExecutionException | ReleaseFailureException e )
282 {
283 captureException( result, performRequest.getReleaseManagerListener(), e );
284 }
285 finally
286 {
287 result.setEndTime( System.currentTimeMillis() );
288 }
289
290 return result;
291 }
292
293 @Override
294 public void perform( ReleasePerformRequest performRequest )
295 throws ReleaseExecutionException, ReleaseFailureException
296 {
297 perform( performRequest, new ReleaseResult() );
298 }
299
300 private void perform( ReleasePerformRequest performRequest, ReleaseResult result )
301 throws ReleaseExecutionException, ReleaseFailureException
302 {
303 ReleaseDescriptor releaseDescriptor =
304 loadReleaseDescriptor( performRequest.getReleaseDescriptorBuilder(),
305 performRequest.getReleaseManagerListener() );
306
307 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
308
309 List<String> performPhases = getGoalPhases( releaseStrategy, "perform" );
310
311 goalStart( performRequest.getReleaseManagerListener(), "perform", performPhases );
312
313 for ( String name : performPhases )
314 {
315 ReleasePhase phase = releasePhases.get( name );
316
317 if ( phase == null )
318 {
319 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
320 }
321
322 updateListener( performRequest.getReleaseManagerListener(), name, PHASE_START );
323
324 ReleaseResult phaseResult = null;
325 try
326 {
327 if ( BooleanUtils.isTrue( performRequest.getDryRun() ) )
328 {
329 phaseResult = phase.simulate( releaseDescriptor,
330 performRequest.getReleaseEnvironment(),
331 performRequest.getReactorProjects() );
332 }
333 else
334 {
335 phaseResult = phase.execute( releaseDescriptor,
336 performRequest.getReleaseEnvironment(),
337 performRequest.getReactorProjects() );
338 }
339 }
340 finally
341 {
342 if ( result != null && phaseResult != null )
343 {
344 result.appendOutput( phaseResult.getOutput() );
345 }
346 }
347
348 updateListener( performRequest.getReleaseManagerListener(), name, PHASE_END );
349 }
350
351 if ( BooleanUtils.isNotFalse( performRequest.getClean() ) )
352 {
353
354 clean( performRequest );
355 }
356
357 updateListener( performRequest.getReleaseManagerListener(), "perform", GOAL_END );
358 }
359
360 @Override
361 public void branch( ReleaseBranchRequest branchRequest )
362 throws ReleaseExecutionException, ReleaseFailureException
363 {
364 final ReleaseDescriptorBuilder builder = branchRequest.getReleaseDescriptorBuilder();
365
366 ReleaseUtils.copyPropertiesToReleaseDescriptor( branchRequest.getUserProperties(),
367 new ReleaseDescriptorBuilder()
368 {
369 public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
370 String value )
371 {
372 builder.addDevelopmentVersion( key, value );
373 return this;
374 }
375
376 public ReleaseDescriptorBuilder addReleaseVersion( String key,
377 String value )
378 {
379 builder.addReleaseVersion( key, value );
380 return this;
381 };
382 } );
383
384 ReleaseDescriptor releaseDescriptor =
385 loadReleaseDescriptor( builder, branchRequest.getReleaseManagerListener() );
386
387 boolean dryRun = BooleanUtils.isTrue( branchRequest.getDryRun() );
388
389 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
390
391 List<String> branchPhases = getGoalPhases( releaseStrategy, "branch" );
392
393 goalStart( branchRequest.getReleaseManagerListener(), "branch", branchPhases );
394
395 for ( String name : branchPhases )
396 {
397 ReleasePhase phase = releasePhases.get( name );
398
399 if ( phase == null )
400 {
401 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
402 }
403
404 updateListener( branchRequest.getReleaseManagerListener(), name, PHASE_START );
405
406 if ( dryRun )
407 {
408 phase.simulate( releaseDescriptor,
409 branchRequest.getReleaseEnvironment(),
410 branchRequest.getReactorProjects() );
411 }
412 else
413 {
414 phase.execute( releaseDescriptor,
415 branchRequest.getReleaseEnvironment(),
416 branchRequest.getReactorProjects() );
417 }
418 updateListener( branchRequest.getReleaseManagerListener(), name, PHASE_END );
419 }
420
421 if ( !dryRun )
422 {
423 clean( branchRequest );
424 }
425
426 updateListener( branchRequest.getReleaseManagerListener(), "branch", GOAL_END );
427 }
428
429 @Override
430 public void updateVersions( ReleaseUpdateVersionsRequest updateVersionsRequest )
431 throws ReleaseExecutionException, ReleaseFailureException
432 {
433 final ReleaseDescriptorBuilder builder = updateVersionsRequest.getReleaseDescriptorBuilder();
434
435
436 ReleaseUtils.copyPropertiesToReleaseDescriptor( updateVersionsRequest.getUserProperties(),
437 new ReleaseDescriptorBuilder()
438 {
439 public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
440 String value )
441 {
442 builder.addDevelopmentVersion( key, value );
443 return this;
444 }
445
446 public ReleaseDescriptorBuilder addReleaseVersion( String key,
447 String value )
448 {
449 builder.addReleaseVersion( key, value );
450 return this;
451 };
452 } );
453
454 ReleaseDescriptor releaseDescriptor =
455 loadReleaseDescriptor( builder, updateVersionsRequest.getReleaseManagerListener() );
456
457 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
458
459 List<String> updateVersionsPhases = getGoalPhases( releaseStrategy, "updateVersions" );
460
461 goalStart( updateVersionsRequest.getReleaseManagerListener(), "updateVersions", updateVersionsPhases );
462
463 for ( String name : updateVersionsPhases )
464 {
465 ReleasePhase phase = releasePhases.get( name );
466
467 if ( phase == null )
468 {
469 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
470 }
471
472 updateListener( updateVersionsRequest.getReleaseManagerListener(), name, PHASE_START );
473 phase.execute( releaseDescriptor,
474 updateVersionsRequest.getReleaseEnvironment(),
475 updateVersionsRequest.getReactorProjects() );
476 updateListener( updateVersionsRequest.getReleaseManagerListener(), name, PHASE_END );
477 }
478
479 clean( updateVersionsRequest );
480
481 updateListener( updateVersionsRequest.getReleaseManagerListener(), "updateVersions", GOAL_END );
482 }
483
484
485
486
487
488
489
490
491
492
493
494 protected File determineWorkingDirectory( File checkoutDirectory, String relativePathProjectDirectory )
495 {
496 if ( StringUtils.isNotEmpty( relativePathProjectDirectory ) )
497 {
498 return new File( checkoutDirectory, relativePathProjectDirectory );
499 }
500 else
501 {
502 return checkoutDirectory;
503 }
504 }
505
506 private BuilderReleaseDescriptor loadReleaseDescriptor( ReleaseDescriptorBuilder builder,
507 ReleaseManagerListener listener )
508 throws ReleaseExecutionException
509 {
510 try
511 {
512 updateListener( listener, "verify-release-configuration", PHASE_START );
513 BuilderReleaseDescriptor descriptor = ReleaseUtils.buildReleaseDescriptor( configStore.read( builder ) );
514 updateListener( listener, "verify-release-configuration", PHASE_END );
515 return descriptor;
516 }
517 catch ( ReleaseDescriptorStoreException e )
518 {
519 updateListener( listener, e.getMessage(), ERROR );
520
521 throw new ReleaseExecutionException( "Error reading stored configuration: " + e.getMessage(), e );
522 }
523 }
524
525
526 protected void clean( AbstractReleaseRequest releaseRequest ) throws ReleaseFailureException
527 {
528 ReleaseCleanRequest cleanRequest = new ReleaseCleanRequest();
529 cleanRequest.setReleaseDescriptorBuilder( releaseRequest.getReleaseDescriptorBuilder() );
530 cleanRequest.setReleaseManagerListener( releaseRequest.getReleaseManagerListener() );
531 cleanRequest.setReactorProjects( releaseRequest.getReactorProjects() );
532
533 clean( cleanRequest );
534 }
535
536 @Override
537 public void clean( ReleaseCleanRequest cleanRequest ) throws ReleaseFailureException
538 {
539 updateListener( cleanRequest.getReleaseManagerListener(), "cleanup", PHASE_START );
540
541 getLogger().info( "Cleaning up after release..." );
542
543 ReleaseDescriptor releaseDescriptor =
544 ReleaseUtils.buildReleaseDescriptor( cleanRequest.getReleaseDescriptorBuilder() );
545
546 configStore.delete( releaseDescriptor );
547
548 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
549
550 Set<String> phases = new LinkedHashSet<>();
551 phases.addAll( getGoalPhases( releaseStrategy, "prepare" ) );
552 phases.addAll( getGoalPhases( releaseStrategy, "branch" ) );
553
554 for ( String name : phases )
555 {
556 ReleasePhase phase = releasePhases.get( name );
557
558 if ( phase instanceof ResourceGenerator )
559 {
560 ( (ResourceGenerator) phase ).clean( cleanRequest.getReactorProjects() );
561 }
562 }
563
564 updateListener( cleanRequest.getReleaseManagerListener(), "cleanup", PHASE_END );
565 }
566
567 void setConfigStore( ReleaseDescriptorStore configStore )
568 {
569 this.configStore = configStore;
570 }
571
572 void goalStart( ReleaseManagerListener listener, String goal, List<String> phases )
573 {
574 if ( listener != null )
575 {
576 listener.goalStart( goal, phases );
577 }
578 }
579
580 void updateListener( ReleaseManagerListener listener, String name, int state )
581 {
582 if ( listener != null )
583 {
584 switch ( state )
585 {
586 case GOAL_END:
587 listener.goalEnd();
588 break;
589 case PHASE_SKIP:
590 listener.phaseSkip( name );
591 break;
592 case PHASE_START:
593 listener.phaseStart( name );
594 break;
595 case PHASE_END:
596 listener.phaseEnd();
597 break;
598 default:
599 listener.error( name );
600 }
601 }
602 }
603
604 private Strategy getStrategy( String strategyId ) throws ReleaseFailureException
605 {
606 Strategy strategy = strategies.get( strategyId );
607 if ( strategy == null )
608 {
609 throw new ReleaseFailureException( "Unknown strategy: " + strategyId );
610 }
611 return strategy;
612 }
613
614 private List<String> getGoalPhases( Strategy strategy, String goal )
615 {
616 List<String> phases;
617
618 if ( "prepare".equals( goal ) )
619 {
620 phases = strategy.getPreparePhases();
621 if ( phases == null )
622 {
623 phases = strategies.get( "default" ).getPreparePhases();
624 }
625 }
626 else if ( "perform".equals( goal ) )
627 {
628 phases = strategy.getPerformPhases();
629 if ( phases == null )
630 {
631 phases = strategies.get( "default" ).getPerformPhases();
632 }
633 }
634 else if ( "rollback".equals( goal ) )
635 {
636 phases = strategy.getRollbackPhases();
637 if ( phases == null )
638 {
639 phases = strategies.get( "default" ).getRollbackPhases();
640 }
641 }
642 else if ( "branch".equals( goal ) )
643 {
644 phases = strategy.getBranchPhases();
645 if ( phases == null )
646 {
647 phases = strategies.get( "default" ).getBranchPhases();
648 }
649 }
650 else if ( "updateVersions".equals( goal ) )
651 {
652 phases = strategy.getUpdateVersionsPhases();
653 if ( phases == null )
654 {
655 phases = strategies.get( "default" ).getUpdateVersionsPhases();
656 }
657 }
658 else
659 {
660 phases = null;
661 }
662
663 return Collections.unmodifiableList( phases );
664 }
665
666 private void logInfo( ReleaseResult result, String message )
667 {
668 if ( result != null )
669 {
670 result.appendInfo( message );
671 }
672
673 getLogger().info( message );
674 }
675
676 private void captureException( ReleaseResult result, ReleaseManagerListener listener, Exception e )
677 {
678 updateListener( listener, e.getMessage(), ERROR );
679
680 result.appendError( e );
681
682 result.setResultCode( ReleaseResult.ERROR );
683 }
684 }