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