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