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