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