View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.shared.release.phase;
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.io.IOException;
27  import java.io.Writer;
28  import java.nio.file.Path;
29  import java.util.ArrayList;
30  import java.util.Collections;
31  import java.util.LinkedHashMap;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Properties;
35  import java.util.Set;
36  
37  import org.apache.maven.artifact.Artifact;
38  import org.apache.maven.artifact.ArtifactUtils;
39  import org.apache.maven.model.Build;
40  import org.apache.maven.model.Dependency;
41  import org.apache.maven.model.Extension;
42  import org.apache.maven.model.Model;
43  import org.apache.maven.model.Plugin;
44  import org.apache.maven.model.ReportPlugin;
45  import org.apache.maven.model.Reporting;
46  import org.apache.maven.model.Resource;
47  import org.apache.maven.model.Scm;
48  import org.apache.maven.model.building.DefaultModelBuildingRequest;
49  import org.apache.maven.model.building.ModelBuildingRequest;
50  import org.apache.maven.model.interpolation.ModelInterpolator;
51  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
52  import org.apache.maven.model.superpom.SuperPomProvider;
53  import org.apache.maven.project.MavenProject;
54  import org.apache.maven.scm.ScmException;
55  import org.apache.maven.scm.ScmFileSet;
56  import org.apache.maven.scm.command.add.AddScmResult;
57  import org.apache.maven.scm.provider.ScmProvider;
58  import org.apache.maven.scm.repository.ScmRepository;
59  import org.apache.maven.shared.release.ReleaseExecutionException;
60  import org.apache.maven.shared.release.ReleaseFailureException;
61  import org.apache.maven.shared.release.ReleaseResult;
62  import org.apache.maven.shared.release.config.ReleaseDescriptor;
63  import org.apache.maven.shared.release.env.ReleaseEnvironment;
64  import org.apache.maven.shared.release.scm.ReleaseScmCommandException;
65  import org.apache.maven.shared.release.scm.ScmRepositoryConfigurator;
66  import org.apache.maven.shared.release.scm.ScmTranslator;
67  import org.apache.maven.shared.release.util.ReleaseUtil;
68  import org.codehaus.plexus.util.WriterFactory;
69  
70  import static java.util.Objects.requireNonNull;
71  
72  /**
73   * Generate release POMs.
74   *
75   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
76   * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
77   */
78  @Singleton
79  @Named("generate-release-poms")
80  public class GenerateReleasePomsPhase extends AbstractReleasePomsPhase implements ResourceGenerator {
81      private static final String FINALNAME_EXPRESSION = "${project.artifactId}-${project.version}";
82  
83      private final SuperPomProvider superPomProvider;
84  
85      private final ModelInterpolator modelInterpolator;
86  
87      /**
88       * SCM URL translators mapped by provider name.
89       */
90      private final Map<String, ScmTranslator> scmTranslators;
91  
92      @Inject
93      public GenerateReleasePomsPhase(
94              ScmRepositoryConfigurator scmRepositoryConfigurator,
95              SuperPomProvider superPomProvider,
96              ModelInterpolator modelInterpolator,
97              Map<String, ScmTranslator> scmTranslators) {
98          super(scmRepositoryConfigurator);
99          this.superPomProvider = requireNonNull(superPomProvider);
100         this.modelInterpolator = requireNonNull(modelInterpolator);
101         this.scmTranslators = requireNonNull(scmTranslators);
102     }
103 
104     /*
105      * @see org.apache.maven.shared.release.phase.ReleasePhase#execute(org.apache.maven.shared.release.config.ReleaseDescriptor,
106      *      org.apache.maven.settings.Settings, java.util.List)
107      */
108     @Override
109     public ReleaseResult execute(
110             ReleaseDescriptor releaseDescriptor,
111             ReleaseEnvironment releaseEnvironment,
112             List<MavenProject> reactorProjects)
113             throws ReleaseExecutionException, ReleaseFailureException {
114         return execute(releaseDescriptor, releaseEnvironment, reactorProjects, false);
115     }
116 
117     private ReleaseResult execute(
118             ReleaseDescriptor releaseDescriptor,
119             ReleaseEnvironment releaseEnvironment,
120             List<MavenProject> reactorProjects,
121             boolean simulate)
122             throws ReleaseExecutionException, ReleaseFailureException {
123         ReleaseResult result = new ReleaseResult();
124 
125         if (releaseDescriptor.isGenerateReleasePoms()) {
126             logInfo(result, "Generating release POMs...");
127 
128             generateReleasePoms(releaseDescriptor, releaseEnvironment, reactorProjects, simulate, result);
129         } else {
130             logInfo(result, "Not generating release POMs");
131         }
132 
133         result.setResultCode(ReleaseResult.SUCCESS);
134 
135         return result;
136     }
137 
138     private void generateReleasePoms(
139             ReleaseDescriptor releaseDescriptor,
140             ReleaseEnvironment releaseEnvironment,
141             List<MavenProject> reactorProjects,
142             boolean simulate,
143             ReleaseResult result)
144             throws ReleaseExecutionException, ReleaseFailureException {
145         List<File> releasePoms = new ArrayList<>();
146 
147         for (MavenProject project : reactorProjects) {
148             logInfo(result, "Generating release POM for '" + project.getName() + "'...");
149 
150             releasePoms.add(generateReleasePom(project, releaseDescriptor, releaseEnvironment, result));
151         }
152 
153         addReleasePomsToScm(releaseDescriptor, releaseEnvironment, reactorProjects, simulate, result, releasePoms);
154     }
155 
156     private File generateReleasePom(
157             MavenProject project,
158             ReleaseDescriptor releaseDescriptor,
159             ReleaseEnvironment releaseEnvironment,
160             ReleaseResult result)
161             throws ReleaseExecutionException, ReleaseFailureException {
162         // create release pom
163 
164         Model releasePom = createReleaseModel(project, releaseDescriptor, releaseEnvironment, result);
165 
166         // write release pom to file
167 
168         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
169 
170         File releasePomFile = ReleaseUtil.getReleasePom(project);
171 
172         // MRELEASE-273 : A release pom can be null
173         if (releasePomFile == null) {
174             throw new ReleaseExecutionException("Cannot generate release POM : pom file is null");
175         }
176 
177         try (Writer fileWriter = WriterFactory.newXmlWriter(releasePomFile)) {
178             pomWriter.write(fileWriter, releasePom);
179         } catch (IOException exception) {
180             throw new ReleaseExecutionException("Cannot generate release POM", exception);
181         }
182 
183         return releasePomFile;
184     }
185 
186     private void addReleasePomsToScm(
187             ReleaseDescriptor releaseDescriptor,
188             ReleaseEnvironment releaseEnvironment,
189             List<MavenProject> reactorProjects,
190             boolean simulate,
191             ReleaseResult result,
192             List<File> releasePoms)
193             throws ReleaseFailureException, ReleaseExecutionException {
194         if (simulate) {
195             logInfo(result, "Full run would be adding " + releasePoms);
196         } else {
197             ScmRepository scmRepository = getScmRepository(releaseDescriptor, releaseEnvironment);
198             ScmProvider scmProvider = getScmProvider(scmRepository);
199 
200             MavenProject rootProject = ReleaseUtil.getRootProject(reactorProjects);
201             ScmFileSet scmFileSet = new ScmFileSet(rootProject.getFile().getParentFile(), releasePoms);
202 
203             try {
204                 AddScmResult scmResult = scmProvider.add(scmRepository, scmFileSet);
205 
206                 if (!scmResult.isSuccess()) {
207                     throw new ReleaseScmCommandException("Cannot add release POM to SCM", scmResult);
208                 }
209             } catch (ScmException exception) {
210                 throw new ReleaseExecutionException(
211                         "Cannot add release POM to SCM: " + exception.getMessage(), exception);
212             }
213         }
214     }
215 
216     private Model createReleaseModel(
217             MavenProject project,
218             ReleaseDescriptor releaseDescriptor,
219             ReleaseEnvironment releaseEnvironment,
220             ReleaseResult result)
221             throws ReleaseFailureException, ReleaseExecutionException {
222         MavenProject releaseProject = project.clone();
223         Model releaseModel = releaseProject.getModel();
224 
225         // the release POM should reflect bits of these which were injected at build time...
226         // we don't need these polluting the POM.
227         releaseModel.setParent(null);
228         releaseModel.setProfiles(Collections.emptyList());
229         releaseModel.setDependencyManagement(null);
230         releaseProject.getBuild().setPluginManagement(null);
231 
232         // update project version
233         String projectVersion = releaseModel.getVersion();
234         String releaseVersion = getNextVersion(releaseDescriptor, project.getGroupId(), project.getArtifactId());
235         releaseModel.setVersion(releaseVersion);
236 
237         String originalFinalName = releaseModel.getBuild().getFinalName();
238         // update final name if implicit
239         if (!FINALNAME_EXPRESSION.equals(originalFinalName)) {
240             originalFinalName = findOriginalFinalName(project);
241 
242             if (originalFinalName == null) {
243                 // as defined in super-pom
244                 originalFinalName = FINALNAME_EXPRESSION;
245             }
246         }
247 
248         // make finalName always explicit
249         String finalName = ReleaseUtil.interpolate(originalFinalName, releaseModel);
250 
251         // still required?
252         if (finalName.contains(Artifact.SNAPSHOT_VERSION)) {
253             throw new ReleaseFailureException(
254                     "Cannot reliably adjust the finalName of project: " + releaseProject.getId());
255         }
256         releaseModel.getBuild().setFinalName(finalName);
257 
258         // update scm
259         Scm scm = releaseModel.getScm();
260 
261         if (scm != null) {
262             ScmRepository scmRepository = getScmRepository(releaseDescriptor, releaseEnvironment);
263             ScmTranslator scmTranslator = getScmTranslator(scmRepository);
264 
265             if (scmTranslator != null) {
266                 releaseModel.setScm(createReleaseScm(releaseModel.getScm(), scmTranslator, releaseDescriptor));
267             } else {
268                 String message = "No SCM translator found - skipping rewrite";
269 
270                 result.appendDebug(message);
271 
272                 getLogger().debug(message);
273             }
274         }
275 
276         // rewrite dependencies
277         releaseModel.setDependencies(createReleaseDependencies(releaseDescriptor, releaseProject));
278 
279         // rewrite plugins
280         releaseModel.getBuild().setPlugins(createReleasePlugins(releaseDescriptor, releaseProject));
281 
282         // rewrite reports
283         releaseModel.getReporting().setPlugins(createReleaseReportPlugins(releaseDescriptor, releaseProject));
284 
285         // rewrite extensions
286         releaseModel.getBuild().setExtensions(createReleaseExtensions(releaseDescriptor, releaseProject));
287 
288         unalignFromBaseDirectory(releaseModel, project.getBasedir());
289 
290         return releaseModel;
291     }
292 
293     private void unalignFromBaseDirectory(Model releaseModel, File basedir) {
294         Model rawSuperModel = superPomProvider.getSuperModel(releaseModel.getModelVersion());
295 
296         ModelBuildingRequest buildingRequest = new DefaultModelBuildingRequest();
297         buildingRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
298 
299         // inject proper values used by project.build.finalName
300         Properties properties = new Properties();
301         properties.put("project.version", releaseModel.getVersion());
302         properties.put("project.artifactId", releaseModel.getArtifactId());
303         buildingRequest.setUserProperties(properties);
304 
305         Model interpolatedSuperModel =
306                 modelInterpolator.interpolateModel(rawSuperModel.clone(), basedir, buildingRequest, null);
307 
308         Build currentBuild = releaseModel.getBuild();
309         Build interpolatedSuperBuild = interpolatedSuperModel.getBuild();
310         Build rawSuperBuild = rawSuperModel.getBuild();
311 
312         currentBuild.setSourceDirectory(resolvePath(
313                 basedir.toPath(),
314                 currentBuild.getSourceDirectory(),
315                 interpolatedSuperBuild.getSourceDirectory(),
316                 rawSuperBuild.getSourceDirectory()));
317         currentBuild.setScriptSourceDirectory(resolvePath(
318                 basedir.toPath(),
319                 currentBuild.getScriptSourceDirectory(),
320                 interpolatedSuperBuild.getScriptSourceDirectory(),
321                 rawSuperBuild.getScriptSourceDirectory()));
322         currentBuild.setTestSourceDirectory(resolvePath(
323                 basedir.toPath(),
324                 currentBuild.getTestSourceDirectory(),
325                 interpolatedSuperBuild.getTestSourceDirectory(),
326                 rawSuperBuild.getTestSourceDirectory()));
327         currentBuild.setOutputDirectory(resolvePath(
328                 basedir.toPath(),
329                 currentBuild.getOutputDirectory(),
330                 interpolatedSuperBuild.getOutputDirectory(),
331                 rawSuperBuild.getOutputDirectory()));
332         currentBuild.setTestOutputDirectory(resolvePath(
333                 basedir.toPath(),
334                 currentBuild.getTestOutputDirectory(),
335                 interpolatedSuperBuild.getTestOutputDirectory(),
336                 rawSuperBuild.getTestOutputDirectory()));
337         currentBuild.setDirectory(resolvePath(
338                 basedir.toPath(),
339                 currentBuild.getDirectory(),
340                 interpolatedSuperBuild.getDirectory(),
341                 rawSuperBuild.getDirectory()));
342 
343         for (Resource currentResource : currentBuild.getResources()) {
344             Map<String, String> superResourceDirectories =
345                     new LinkedHashMap<>(interpolatedSuperBuild.getResources().size());
346             for (int i = 0; i < interpolatedSuperBuild.getResources().size(); i++) {
347                 superResourceDirectories.put(
348                         interpolatedSuperBuild.getResources().get(i).getDirectory(),
349                         rawSuperBuild.getResources().get(i).getDirectory());
350             }
351             currentResource.setDirectory(
352                     resolvePath(basedir.toPath(), currentResource.getDirectory(), superResourceDirectories));
353         }
354 
355         for (Resource currentResource : currentBuild.getTestResources()) {
356             Map<String, String> superResourceDirectories = new LinkedHashMap<>(
357                     interpolatedSuperBuild.getTestResources().size());
358             for (int i = 0; i < interpolatedSuperBuild.getTestResources().size(); i++) {
359                 superResourceDirectories.put(
360                         interpolatedSuperBuild.getTestResources().get(i).getDirectory(),
361                         rawSuperBuild.getTestResources().get(i).getDirectory());
362             }
363             currentResource.setDirectory(
364                     resolvePath(basedir.toPath(), currentResource.getDirectory(), superResourceDirectories));
365         }
366 
367         releaseModel
368                 .getReporting()
369                 .setOutputDirectory(resolvePath(
370                         basedir.toPath(),
371                         releaseModel.getReporting().getOutputDirectory(),
372                         interpolatedSuperModel.getReporting().getOutputDirectory(),
373                         rawSuperModel.getReporting().getOutputDirectory()));
374     }
375 
376     private String resolvePath(Path basedir, String current, String superInterpolated, String superRaw) {
377         return basedir.resolve(current).equals(basedir.resolve(superInterpolated)) ? superRaw : current;
378     }
379 
380     private String resolvePath(
381             Path basedir, String current, Map<String /* interpolated */, String /* raw */> superValues) {
382         for (Map.Entry<String, String> superValue : superValues.entrySet()) {
383             if (basedir.resolve(current).equals(basedir.resolve(superValue.getKey()))) {
384                 return superValue.getValue();
385             }
386         }
387         return current;
388     }
389 
390     private String findOriginalFinalName(MavenProject project) {
391         if (project.getOriginalModel().getBuild() != null
392                 && project.getOriginalModel().getBuild().getFinalName() != null) {
393             return project.getOriginalModel().getBuild().getFinalName();
394         } else if (project.hasParent()) {
395             return findOriginalFinalName(project.getParent());
396         } else {
397             return null;
398         }
399     }
400 
401     @Override
402     public ReleaseResult simulate(
403             ReleaseDescriptor releaseDescriptor,
404             ReleaseEnvironment releaseEnvironment,
405             List<MavenProject> reactorProjects)
406             throws ReleaseExecutionException, ReleaseFailureException {
407         return execute(releaseDescriptor, releaseEnvironment, reactorProjects, true);
408     }
409 
410     private String getNextVersion(ReleaseDescriptor releaseDescriptor, String groupId, String artifactId)
411             throws ReleaseFailureException {
412         // TODO: share with RewritePomsForReleasePhase.rewriteVersion
413 
414         String id = ArtifactUtils.versionlessKey(groupId, artifactId);
415 
416         String nextVersion = releaseDescriptor.getProjectReleaseVersion(id);
417 
418         if (nextVersion == null) {
419             throw new ReleaseFailureException("Version for '" + id + "' was not mapped");
420         }
421 
422         return nextVersion;
423     }
424 
425     private ScmTranslator getScmTranslator(ScmRepository scmRepository) {
426         return scmTranslators.get(scmRepository.getProvider());
427     }
428 
429     private Scm createReleaseScm(Scm scm, ScmTranslator scmTranslator, ReleaseDescriptor releaseDescriptor) {
430         // TODO: share with RewritePomsForReleasePhase.translateScm
431 
432         String tag = releaseDescriptor.getScmReleaseLabel();
433         String tagBase = releaseDescriptor.getScmTagBase();
434 
435         Scm releaseScm = new Scm();
436 
437         if (scm.getConnection() != null) {
438             String value = scmTranslator.translateTagUrl(scm.getConnection(), tag, tagBase);
439             releaseScm.setConnection(value);
440         }
441 
442         if (scm.getDeveloperConnection() != null) {
443             String value = scmTranslator.translateTagUrl(scm.getDeveloperConnection(), tag, tagBase);
444             releaseScm.setDeveloperConnection(value);
445         }
446 
447         if (scm.getUrl() != null) {
448             String value = scmTranslator.translateTagUrl(scm.getUrl(), tag, tagBase);
449             releaseScm.setUrl(value);
450         }
451 
452         if (scm.getTag() != null) {
453             String value = scmTranslator.resolveTag(scm.getTag());
454             releaseScm.setTag(value);
455         }
456 
457         return releaseScm;
458     }
459 
460     private List<Dependency> createReleaseDependencies(ReleaseDescriptor releaseDescriptor, MavenProject project)
461             throws ReleaseFailureException {
462         Set<Artifact> artifacts = project.getArtifacts();
463 
464         List<Dependency> releaseDependencies = null;
465 
466         if (artifacts != null) {
467             // make dependency order deterministic for tests (related to MNG-1412)
468             List<Artifact> orderedArtifacts = new ArrayList<>(artifacts);
469             Collections.sort(orderedArtifacts);
470 
471             releaseDependencies = new ArrayList<>();
472 
473             for (Artifact artifact : orderedArtifacts) {
474                 Dependency releaseDependency = new Dependency();
475 
476                 releaseDependency.setGroupId(artifact.getGroupId());
477                 releaseDependency.setArtifactId(artifact.getArtifactId());
478 
479                 String version = getReleaseVersion(releaseDescriptor, artifact);
480 
481                 releaseDependency.setVersion(version);
482                 releaseDependency.setType(artifact.getType());
483                 releaseDependency.setScope(artifact.getScope());
484                 releaseDependency.setClassifier(artifact.getClassifier());
485 
486                 releaseDependencies.add(releaseDependency);
487             }
488         }
489 
490         return releaseDependencies;
491     }
492 
493     private String getReleaseVersion(ReleaseDescriptor releaseDescriptor, Artifact artifact)
494             throws ReleaseFailureException {
495         String key = ArtifactUtils.versionlessKey(artifact);
496 
497         String originalVersion = releaseDescriptor.getProjectOriginalVersion(key);
498         String mappedVersion = releaseDescriptor.getProjectReleaseVersion(key);
499 
500         String version = artifact.getVersion();
501 
502         if (version.equals(originalVersion)) {
503             if (mappedVersion != null) {
504                 version = mappedVersion;
505             } else {
506                 throw new ReleaseFailureException("Version '" + version + "' for '" + key + "' was not mapped");
507             }
508         } else {
509             if (!ArtifactUtils.isSnapshot(version)) {
510                 version = artifact.getBaseVersion();
511             }
512         }
513 
514         return version;
515     }
516 
517     private List<Plugin> createReleasePlugins(ReleaseDescriptor releaseDescriptor, MavenProject project)
518             throws ReleaseFailureException {
519         List<Plugin> releasePlugins = null;
520 
521         // Use original - don't want the lifecycle introduced ones
522         Build build = project.getOriginalModel().getBuild();
523 
524         if (build != null) {
525             List<Plugin> plugins = build.getPlugins();
526 
527             if (plugins != null) {
528                 Map<String, Artifact> artifactsById = project.getPluginArtifactMap();
529 
530                 releasePlugins = new ArrayList<>();
531 
532                 for (Plugin plugin : plugins) {
533                     String id = ArtifactUtils.versionlessKey(plugin.getGroupId(), plugin.getArtifactId());
534                     Artifact artifact = artifactsById.get(id);
535                     String version = getReleaseVersion(releaseDescriptor, artifact);
536 
537                     Plugin releasePlugin = new Plugin();
538                     releasePlugin.setGroupId(plugin.getGroupId());
539                     releasePlugin.setArtifactId(plugin.getArtifactId());
540                     releasePlugin.setVersion(version);
541                     if (plugin.getExtensions() != null) {
542                         releasePlugin.setExtensions(plugin.isExtensions());
543                     }
544                     releasePlugin.setExecutions(plugin.getExecutions());
545                     releasePlugin.setDependencies(plugin.getDependencies());
546                     releasePlugin.setInherited(plugin.getInherited());
547                     if (plugin.getConfiguration() != null) {
548                         releasePlugin.setConfiguration(plugin.getConfiguration());
549                     }
550 
551                     releasePlugins.add(releasePlugin);
552                 }
553             }
554         }
555 
556         return releasePlugins;
557     }
558 
559     private List<ReportPlugin> createReleaseReportPlugins(ReleaseDescriptor releaseDescriptor, MavenProject project)
560             throws ReleaseFailureException {
561         List<ReportPlugin> releaseReportPlugins = null;
562 
563         Reporting reporting = project.getModel().getReporting();
564 
565         if (reporting != null) {
566             List<ReportPlugin> reportPlugins = reporting.getPlugins();
567 
568             if (reportPlugins != null) {
569                 Map<String, Artifact> artifactsById = project.getReportArtifactMap();
570 
571                 releaseReportPlugins = new ArrayList<>();
572 
573                 for (ReportPlugin reportPlugin : reportPlugins) {
574                     String id = ArtifactUtils.versionlessKey(reportPlugin.getGroupId(), reportPlugin.getArtifactId());
575                     Artifact artifact = artifactsById.get(id);
576                     String version = getReleaseVersion(releaseDescriptor, artifact);
577 
578                     ReportPlugin releaseReportPlugin = new ReportPlugin();
579                     releaseReportPlugin.setGroupId(reportPlugin.getGroupId());
580                     releaseReportPlugin.setArtifactId(reportPlugin.getArtifactId());
581                     releaseReportPlugin.setVersion(version);
582                     releaseReportPlugin.setInherited(reportPlugin.getInherited());
583                     releaseReportPlugin.setConfiguration(reportPlugin.getConfiguration());
584                     releaseReportPlugin.setReportSets(reportPlugin.getReportSets());
585 
586                     releaseReportPlugins.add(releaseReportPlugin);
587                 }
588             }
589         }
590 
591         return releaseReportPlugins;
592     }
593 
594     private List<Extension> createReleaseExtensions(ReleaseDescriptor releaseDescriptor, MavenProject project)
595             throws ReleaseFailureException {
596         List<Extension> releaseExtensions = null;
597 
598         // Use original - don't want the lifecycle introduced ones
599         Build build = project.getOriginalModel().getBuild();
600 
601         if (build != null) {
602             List<Extension> extensions = build.getExtensions();
603 
604             if (extensions != null) {
605                 releaseExtensions = new ArrayList<>();
606 
607                 for (Extension extension : extensions) {
608                     String id = ArtifactUtils.versionlessKey(extension.getGroupId(), extension.getArtifactId());
609                     Artifact artifact = project.getExtensionArtifactMap().get(id);
610                     String version = getReleaseVersion(releaseDescriptor, artifact);
611 
612                     Extension releaseExtension = new Extension();
613                     releaseExtension.setGroupId(extension.getGroupId());
614                     releaseExtension.setArtifactId(extension.getArtifactId());
615                     releaseExtension.setVersion(version);
616 
617                     releaseExtensions.add(releaseExtension);
618                 }
619             }
620         }
621 
622         return releaseExtensions;
623     }
624 
625     /*
626      * @see org.apache.maven.shared.release.phase.AbstractReleasePhase#clean(java.util.List)
627      */
628     @Override
629     public ReleaseResult clean(List<MavenProject> reactorProjects) {
630         ReleaseResult result = new ReleaseResult();
631 
632         for (MavenProject project : reactorProjects) {
633             File releasePom = ReleaseUtil.getReleasePom(project);
634 
635             // MRELEASE-273 : A release pom can be null
636             if (releasePom != null && releasePom.exists()) {
637                 logInfo(result, "Deleting release POM for '" + project.getName() + "'...");
638 
639                 if (!releasePom.delete()) {
640                     logWarn(result, "Cannot delete release POM: " + releasePom);
641                 }
642             }
643         }
644 
645         result.setResultCode(ReleaseResult.SUCCESS);
646 
647         return result;
648     }
649 }