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 List<String> specificProfiles =
326 ReleaseUtils.buildReleaseDescriptor( performRequest.getReleaseDescriptorBuilder() )
327 .getActivateProfiles();
328
329 ReleaseDescriptorBuilder builder =
330 loadReleaseDescriptorBuilder( performRequest.getReleaseDescriptorBuilder(),
331 performRequest.getReleaseManagerListener() );
332
333 if ( specificProfiles != null && !specificProfiles.isEmpty() )
334 {
335 List<String> allProfiles =
336 new ArrayList<>( ReleaseUtils.buildReleaseDescriptor( builder ).getActivateProfiles() );
337 for ( String specificProfile : specificProfiles )
338 {
339 if ( !allProfiles.contains( specificProfile ) )
340 {
341 allProfiles.add( specificProfile );
342 }
343 }
344 builder.setActivateProfiles( allProfiles );
345 }
346
347 ReleaseDescriptor releaseDescriptor = ReleaseUtils.buildReleaseDescriptor( builder );
348
349 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
350
351 List<String> performPhases = getGoalPhases( releaseStrategy, "perform" );
352
353 goalStart( performRequest.getReleaseManagerListener(), "perform", performPhases );
354
355 for ( String name : performPhases )
356 {
357 ReleasePhase phase = releasePhases.get( name );
358
359 if ( phase == null )
360 {
361 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
362 }
363
364 phaseStart( performRequest.getReleaseManagerListener(), name );
365
366 ReleaseResult phaseResult = null;
367 try
368 {
369 if ( BooleanUtils.isTrue( performRequest.getDryRun() ) )
370 {
371 phaseResult = phase.simulate( releaseDescriptor,
372 performRequest.getReleaseEnvironment(),
373 performRequest.getReactorProjects() );
374 }
375 else
376 {
377 phaseResult = phase.execute( releaseDescriptor,
378 performRequest.getReleaseEnvironment(),
379 performRequest.getReactorProjects() );
380 }
381 }
382 finally
383 {
384 if ( result != null && phaseResult != null )
385 {
386 result.appendOutput( phaseResult.getOutput() );
387 }
388 }
389
390 phaseEnd( performRequest.getReleaseManagerListener() );
391 }
392
393 if ( BooleanUtils.isNotFalse( performRequest.getClean() ) )
394 {
395
396 clean( performRequest );
397 }
398
399 goalEnd( performRequest.getReleaseManagerListener() );
400 }
401
402 @Override
403 public void branch( ReleaseBranchRequest branchRequest )
404 throws ReleaseExecutionException, ReleaseFailureException
405 {
406 final ReleaseDescriptorBuilder builder = branchRequest.getReleaseDescriptorBuilder();
407
408 ReleaseUtils.copyPropertiesToReleaseDescriptor( branchRequest.getUserProperties(),
409 new ReleaseDescriptorBuilder()
410 {
411 public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
412 String value )
413 {
414 builder.addDevelopmentVersion( key, value );
415 return this;
416 }
417
418 public ReleaseDescriptorBuilder addReleaseVersion( String key,
419 String value )
420 {
421 builder.addReleaseVersion( key, value );
422 return this;
423 }
424 } );
425
426 ReleaseDescriptor releaseDescriptor =
427 loadReleaseDescriptor( builder, branchRequest.getReleaseManagerListener() );
428
429 boolean dryRun = BooleanUtils.isTrue( branchRequest.getDryRun() );
430
431 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
432
433 List<String> branchPhases = getGoalPhases( releaseStrategy, "branch" );
434
435 goalStart( branchRequest.getReleaseManagerListener(), "branch", branchPhases );
436
437 for ( String name : branchPhases )
438 {
439 ReleasePhase phase = releasePhases.get( name );
440
441 if ( phase == null )
442 {
443 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
444 }
445
446 phaseStart( branchRequest.getReleaseManagerListener(), name );
447
448 if ( dryRun )
449 {
450 phase.simulate( releaseDescriptor,
451 branchRequest.getReleaseEnvironment(),
452 branchRequest.getReactorProjects() );
453 }
454 else
455 {
456 phase.execute( releaseDescriptor,
457 branchRequest.getReleaseEnvironment(),
458 branchRequest.getReactorProjects() );
459 }
460
461 phaseEnd( branchRequest.getReleaseManagerListener() );
462 }
463
464 if ( !dryRun )
465 {
466 clean( branchRequest );
467 }
468
469 goalEnd( branchRequest.getReleaseManagerListener() );
470 }
471
472 @Override
473 public void updateVersions( ReleaseUpdateVersionsRequest updateVersionsRequest )
474 throws ReleaseExecutionException, ReleaseFailureException
475 {
476 final ReleaseDescriptorBuilder builder = updateVersionsRequest.getReleaseDescriptorBuilder();
477
478
479 ReleaseUtils.copyPropertiesToReleaseDescriptor( updateVersionsRequest.getUserProperties(),
480 new ReleaseDescriptorBuilder()
481 {
482 public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
483 String value )
484 {
485 builder.addDevelopmentVersion( key, value );
486 return this;
487 }
488
489 public ReleaseDescriptorBuilder addReleaseVersion( String key,
490 String value )
491 {
492 builder.addReleaseVersion( key, value );
493 return this;
494 }
495 } );
496
497 ReleaseDescriptor releaseDescriptor =
498 loadReleaseDescriptor( builder, updateVersionsRequest.getReleaseManagerListener() );
499
500 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
501
502 List<String> updateVersionsPhases = getGoalPhases( releaseStrategy, "updateVersions" );
503
504 goalStart( updateVersionsRequest.getReleaseManagerListener(), "updateVersions", updateVersionsPhases );
505
506 for ( String name : updateVersionsPhases )
507 {
508 ReleasePhase phase = releasePhases.get( name );
509
510 if ( phase == null )
511 {
512 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
513 }
514
515 phaseStart( updateVersionsRequest.getReleaseManagerListener(), name );
516 phase.execute( releaseDescriptor,
517 updateVersionsRequest.getReleaseEnvironment(),
518 updateVersionsRequest.getReactorProjects() );
519 phaseEnd( updateVersionsRequest.getReleaseManagerListener() );
520 }
521
522 clean( updateVersionsRequest );
523
524 goalEnd( updateVersionsRequest.getReleaseManagerListener() );
525 }
526
527
528
529
530
531
532
533
534
535
536
537 protected File determineWorkingDirectory( File checkoutDirectory, String relativePathProjectDirectory )
538 {
539 if ( StringUtils.isNotEmpty( relativePathProjectDirectory ) )
540 {
541 return new File( checkoutDirectory, relativePathProjectDirectory );
542 }
543 else
544 {
545 return checkoutDirectory;
546 }
547 }
548
549 private BuilderReleaseDescriptor loadReleaseDescriptor( ReleaseDescriptorBuilder builder,
550 ReleaseManagerListener listener )
551 throws ReleaseExecutionException
552 {
553 return ReleaseUtils.buildReleaseDescriptor( loadReleaseDescriptorBuilder( builder, listener ) );
554 }
555
556 private ReleaseDescriptorBuilder loadReleaseDescriptorBuilder( ReleaseDescriptorBuilder builder,
557 ReleaseManagerListener listener )
558 throws ReleaseExecutionException
559 {
560 try
561 {
562 return configStore.get().read( builder );
563 }
564 catch ( ReleaseDescriptorStoreException e )
565 {
566 throw new ReleaseExecutionException( "Error reading stored configuration: " + e.getMessage(), e );
567 }
568 }
569
570
571
572
573
574
575
576 protected void clean( AbstractReleaseRequest releaseRequest ) throws ReleaseFailureException
577 {
578 ReleaseCleanRequest cleanRequest = new ReleaseCleanRequest();
579 cleanRequest.setReleaseDescriptorBuilder( releaseRequest.getReleaseDescriptorBuilder() );
580 cleanRequest.setReleaseManagerListener( releaseRequest.getReleaseManagerListener() );
581 cleanRequest.setReactorProjects( releaseRequest.getReactorProjects() );
582
583 clean( cleanRequest );
584 }
585
586 @Override
587 public void clean( ReleaseCleanRequest cleanRequest ) throws ReleaseFailureException
588 {
589 logger.info( "Cleaning up after release..." );
590
591 ReleaseDescriptor releaseDescriptor =
592 ReleaseUtils.buildReleaseDescriptor( cleanRequest.getReleaseDescriptorBuilder() );
593
594 configStore.get().delete( releaseDescriptor );
595
596 Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
597
598 Set<String> phases = new LinkedHashSet<>();
599 phases.addAll( getGoalPhases( releaseStrategy, "prepare" ) );
600 phases.addAll( getGoalPhases( releaseStrategy, "branch" ) );
601
602 for ( String name : phases )
603 {
604 ReleasePhase phase = releasePhases.get( name );
605
606 if ( phase instanceof ResourceGenerator )
607 {
608 ( (ResourceGenerator) phase ).clean( cleanRequest.getReactorProjects() );
609 }
610 }
611 }
612
613 void goalStart( ReleaseManagerListener listener, String goal, List<String> phases )
614 {
615 if ( listener != null )
616 {
617 listener.goalStart( goal, phases );
618 }
619 }
620
621 void goalEnd( ReleaseManagerListener listener )
622 {
623 if ( listener != null )
624 {
625 listener.goalEnd();
626 }
627 }
628
629 void phaseSkip( ReleaseManagerListener listener, String name )
630 {
631 if ( listener != null )
632 {
633 listener.phaseSkip( name );
634 }
635 }
636
637 void phaseStart( ReleaseManagerListener listener, String name )
638 {
639 if ( listener != null )
640 {
641 listener.phaseStart( name );
642 }
643 }
644
645 void phaseEnd( ReleaseManagerListener listener )
646 {
647 if ( listener != null )
648 {
649 listener.phaseEnd();
650 }
651 }
652
653 void error( ReleaseManagerListener listener, String name )
654 {
655 if ( listener != null )
656 {
657 listener.error( name );
658 }
659 }
660
661 private Strategy getStrategy( String strategyId ) throws ReleaseFailureException
662 {
663 Strategy strategy = strategies.get( strategyId );
664 if ( strategy == null )
665 {
666 throw new ReleaseFailureException( "Unknown strategy: " + strategyId );
667 }
668 return strategy;
669 }
670
671 private List<String> getGoalPhases( Strategy strategy, String goal )
672 {
673 List<String> phases;
674
675 if ( "prepare".equals( goal ) )
676 {
677 phases = strategy.getPreparePhases();
678 if ( phases == null )
679 {
680 phases = strategies.get( "default" ).getPreparePhases();
681 }
682 }
683 else if ( "perform".equals( goal ) )
684 {
685 phases = strategy.getPerformPhases();
686 if ( phases == null )
687 {
688 phases = strategies.get( "default" ).getPerformPhases();
689 }
690 }
691 else if ( "rollback".equals( goal ) )
692 {
693 phases = strategy.getRollbackPhases();
694 if ( phases == null )
695 {
696 phases = strategies.get( "default" ).getRollbackPhases();
697 }
698 }
699 else if ( "branch".equals( goal ) )
700 {
701 phases = strategy.getBranchPhases();
702 if ( phases == null )
703 {
704 phases = strategies.get( "default" ).getBranchPhases();
705 }
706 }
707 else if ( "updateVersions".equals( goal ) )
708 {
709 phases = strategy.getUpdateVersionsPhases();
710 if ( phases == null )
711 {
712 phases = strategies.get( "default" ).getUpdateVersionsPhases();
713 }
714 }
715 else
716 {
717 phases = null;
718 }
719
720 return Collections.unmodifiableList( phases );
721 }
722
723 private void logInfo( ReleaseResult result, String message )
724 {
725 if ( result != null )
726 {
727 result.appendInfo( message );
728 }
729
730 logger.info( message );
731 }
732
733 private void captureException( ReleaseResult result, ReleaseManagerListener listener, Exception e )
734 {
735 if ( listener != null )
736 {
737 listener.error( e.getMessage() );
738 }
739
740 result.appendError( e );
741
742 result.setResultCode( ReleaseResult.ERROR );
743 }
744 }