View Javadoc
1   package org.apache.maven.shared.release;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.LinkedHashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.commons.lang3.BooleanUtils;
31  import org.apache.maven.shared.release.config.ReleaseDescriptor;
32  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder;
33  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor;
34  import org.apache.maven.shared.release.config.ReleaseDescriptorStore;
35  import org.apache.maven.shared.release.config.ReleaseDescriptorStoreException;
36  import org.apache.maven.shared.release.config.ReleaseUtils;
37  import org.apache.maven.shared.release.phase.ReleasePhase;
38  import org.apache.maven.shared.release.phase.ResourceGenerator;
39  import org.apache.maven.shared.release.strategy.Strategy;
40  import org.codehaus.plexus.component.annotations.Component;
41  import org.codehaus.plexus.component.annotations.Requirement;
42  import org.codehaus.plexus.logging.AbstractLogEnabled;
43  import org.codehaus.plexus.util.StringUtils;
44  
45  /**
46   * Implementation of the release manager.
47   *
48   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
49   */
50  @Component( role = ReleaseManager.class )
51  public class DefaultReleaseManager
52      extends AbstractLogEnabled
53      implements ReleaseManager
54  {
55      @Requirement
56      private Map<String, Strategy> strategies;
57  
58      /**
59       * The available phases.
60       */
61      @Requirement
62      private Map<String, ReleasePhase> releasePhases;
63  
64      /**
65       * The configuration storage.
66       */
67      @Requirement( hint = "properties" )
68      private ReleaseDescriptorStore configStore;
69  
70      private static final int PHASE_SKIP = 0, PHASE_START = 1, PHASE_END = 2, GOAL_END = 12, ERROR = 99;
71  
72      @Override
73      public ReleaseResult prepareWithResult( ReleasePrepareRequest prepareRequest )
74      {
75          ReleaseResult result = new ReleaseResult();
76  
77          result.setStartTime( System.currentTimeMillis() );
78  
79          try
80          {
81              prepare( prepareRequest, result );
82  
83              result.setResultCode( ReleaseResult.SUCCESS );
84          }
85          catch ( ReleaseExecutionException | ReleaseFailureException e )
86          {
87              captureException( result, prepareRequest.getReleaseManagerListener(), e );
88          }
89          finally
90          {
91              result.setEndTime( System.currentTimeMillis() );
92          }
93  
94          return result;
95      }
96  
97      @Override
98      public void prepare( ReleasePrepareRequest prepareRequest )
99          throws ReleaseExecutionException, ReleaseFailureException
100     {
101         prepare( prepareRequest, new ReleaseResult() );
102     }
103 
104     private void prepare( ReleasePrepareRequest prepareRequest, ReleaseResult result )
105         throws ReleaseExecutionException, ReleaseFailureException
106     {
107 
108         final ReleaseDescriptorBuilder builder = prepareRequest.getReleaseDescriptorBuilder();
109 
110         // Create a config containing values from the session properties (ie command line properties with cli).
111         ReleaseUtils.copyPropertiesToReleaseDescriptor( prepareRequest.getUserProperties(),
112                 new ReleaseDescriptorBuilder()
113                 {
114                     public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
115                                                                            String value )
116                     {
117                         builder.addDevelopmentVersion( key, value );
118                         return this;
119                     }
120 
121                     public ReleaseDescriptorBuilder addReleaseVersion( String key,
122                                                                        String value )
123                     {
124                         builder.addReleaseVersion( key, value );
125                         return this;
126                     }
127 
128                     public ReleaseDescriptorBuilder addDependencyReleaseVersion( String dependencyKey,
129                                                                                 String version )
130                     {
131                         builder.addDependencyReleaseVersion( dependencyKey, version );
132                         return this;
133                     }
134 
135                     public ReleaseDescriptorBuilder addDependencyDevelopmentVersion( String dependencyKey,
136                                                                                     String version )
137                     {
138                         builder.addDependencyDevelopmentVersion( dependencyKey, version );
139                         return this;
140                     }
141                 } );
142 
143         BuilderReleaseDescriptor config;
144         if ( BooleanUtils.isNotFalse( prepareRequest.getResume() ) )
145         {
146             config = loadReleaseDescriptor( builder, prepareRequest.getReleaseManagerListener() );
147         }
148         else
149         {
150             config = ReleaseUtils.buildReleaseDescriptor( builder );
151         }
152 
153         Strategy releaseStrategy = getStrategy( config.getReleaseStrategyId() );
154 
155         List<String> preparePhases = getGoalPhases( releaseStrategy, "prepare" );
156 
157         goalStart( prepareRequest.getReleaseManagerListener(), "prepare", preparePhases );
158 
159         // Later, it would be a good idea to introduce a proper workflow tool so that the release can be made up of a
160         // more flexible set of steps.
161 
162         String completedPhase = config.getCompletedPhase();
163         int index = preparePhases.indexOf( completedPhase );
164 
165         for ( int idx = 0; idx <= index; idx++ )
166         {
167             updateListener( prepareRequest.getReleaseManagerListener(), preparePhases.get( idx ), PHASE_SKIP );
168         }
169 
170         if ( index == preparePhases.size() - 1 )
171         {
172             logInfo( result, "Release preparation already completed. You can now continue with release:perform, "
173                 + "or start again using the -Dresume=false flag" );
174         }
175         else if ( index >= 0 )
176         {
177             logInfo( result, "Resuming release from phase '" + preparePhases.get( index + 1 ) + "'" );
178         }
179 
180         // start from next phase
181         for ( int i = index + 1; i < preparePhases.size(); i++ )
182         {
183             String name = preparePhases.get( i );
184 
185             ReleasePhase phase = releasePhases.get( name );
186 
187             if ( phase == null )
188             {
189                 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
190             }
191 
192             updateListener( prepareRequest.getReleaseManagerListener(), name, PHASE_START );
193 
194             ReleaseResult phaseResult = null;
195             try
196             {
197                 if ( BooleanUtils.isTrue( prepareRequest.getDryRun() ) )
198                 {
199                     phaseResult = phase.simulate( config,
200                                                   prepareRequest.getReleaseEnvironment(),
201                                                   prepareRequest.getReactorProjects() );
202                 }
203                 else
204                 {
205                     phaseResult = phase.execute( config,
206                                                  prepareRequest.getReleaseEnvironment(),
207                                                  prepareRequest.getReactorProjects() );
208                 }
209             }
210             finally
211             {
212                 if ( result != null && phaseResult != null )
213                 {
214                     result.appendOutput(  phaseResult.getOutput() );
215                 }
216             }
217 
218             config.setCompletedPhase( name );
219             try
220             {
221                 configStore.write( config );
222             }
223             catch ( ReleaseDescriptorStoreException e )
224             {
225                 // TODO: rollback?
226                 throw new ReleaseExecutionException( "Error writing release properties after completing phase", e );
227             }
228 
229             updateListener( prepareRequest.getReleaseManagerListener(), name, PHASE_END );
230         }
231 
232         updateListener( prepareRequest.getReleaseManagerListener(), "prepare", GOAL_END );
233     }
234 
235     @Override
236     public void rollback( ReleaseRollbackRequest rollbackRequest )
237         throws ReleaseExecutionException, ReleaseFailureException
238     {
239         ReleaseDescriptor releaseDescriptor =
240             loadReleaseDescriptor( rollbackRequest.getReleaseDescriptorBuilder(), null );
241 
242         Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
243 
244         List<String> rollbackPhases = getGoalPhases( releaseStrategy, "rollback" );
245 
246         goalStart( rollbackRequest.getReleaseManagerListener(), "rollback", rollbackPhases );
247 
248         for ( String name : rollbackPhases )
249         {
250             ReleasePhase phase = releasePhases.get( name );
251 
252             if ( phase == null )
253             {
254                 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
255             }
256 
257             updateListener( rollbackRequest.getReleaseManagerListener(), name, PHASE_START );
258             phase.execute( releaseDescriptor,
259                            rollbackRequest.getReleaseEnvironment(),
260                            rollbackRequest.getReactorProjects() );
261             updateListener( rollbackRequest.getReleaseManagerListener(), name, PHASE_END );
262         }
263 
264         //call release:clean so that resume will not be possible anymore after a rollback
265         clean( rollbackRequest );
266         updateListener( rollbackRequest.getReleaseManagerListener(), "rollback", GOAL_END );
267     }
268 
269     @Override
270     public ReleaseResult performWithResult( ReleasePerformRequest performRequest )
271     {
272         ReleaseResult result = new ReleaseResult();
273 
274         try
275         {
276             result.setStartTime( System.currentTimeMillis() );
277 
278             perform( performRequest, result );
279 
280             result.setResultCode( ReleaseResult.SUCCESS );
281         }
282         catch ( ReleaseExecutionException | ReleaseFailureException e )
283         {
284             captureException( result, performRequest.getReleaseManagerListener(), e );
285         }
286         finally
287         {
288             result.setEndTime( System.currentTimeMillis() );
289         }
290 
291         return result;
292     }
293 
294     @Override
295     public void perform( ReleasePerformRequest performRequest )
296         throws ReleaseExecutionException, ReleaseFailureException
297     {
298         perform( performRequest, new ReleaseResult() );
299     }
300 
301     private void perform( ReleasePerformRequest performRequest, ReleaseResult result )
302         throws ReleaseExecutionException, ReleaseFailureException
303     {
304         List<String> specificProfiles =
305             ReleaseUtils.buildReleaseDescriptor( performRequest.getReleaseDescriptorBuilder() )
306             .getActivateProfiles();
307 
308         ReleaseDescriptorBuilder builder =
309             loadReleaseDescriptorBuilder( performRequest.getReleaseDescriptorBuilder(),
310                                           performRequest.getReleaseManagerListener() );
311 
312         if ( specificProfiles != null && !specificProfiles.isEmpty() )
313         {
314             List<String> allProfiles = new ArrayList<>();
315             allProfiles.addAll( ReleaseUtils.buildReleaseDescriptor( builder ).getActivateProfiles() );
316             for ( String specificProfile : specificProfiles )
317             {
318                 if ( !allProfiles.contains( specificProfile ) )
319                 {
320                     allProfiles.add( specificProfile );
321                 }
322             }
323             builder.setActivateProfiles( allProfiles );
324         }
325 
326         ReleaseDescriptor releaseDescriptor = ReleaseUtils.buildReleaseDescriptor( builder );
327 
328         Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
329 
330         List<String> performPhases = getGoalPhases( releaseStrategy, "perform" );
331 
332         goalStart( performRequest.getReleaseManagerListener(), "perform", performPhases );
333 
334         for ( String name : performPhases )
335         {
336             ReleasePhase phase = releasePhases.get( name );
337 
338             if ( phase == null )
339             {
340                 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
341             }
342 
343             updateListener( performRequest.getReleaseManagerListener(), name, PHASE_START );
344 
345             ReleaseResult phaseResult = null;
346             try
347             {
348                 if ( BooleanUtils.isTrue( performRequest.getDryRun() ) )
349                 {
350                     phaseResult = phase.simulate( releaseDescriptor,
351                                                  performRequest.getReleaseEnvironment(),
352                                                  performRequest.getReactorProjects() );
353                 }
354                 else
355                 {
356                     phaseResult = phase.execute( releaseDescriptor,
357                                                  performRequest.getReleaseEnvironment(),
358                                                  performRequest.getReactorProjects() );
359                 }
360             }
361             finally
362             {
363                 if ( result != null && phaseResult != null )
364                 {
365                     result.appendOutput( phaseResult.getOutput() );
366                 }
367             }
368 
369             updateListener( performRequest.getReleaseManagerListener(), name, PHASE_END );
370         }
371 
372         if ( BooleanUtils.isNotFalse( performRequest.getClean() ) )
373         {
374             // call release:clean so that resume will not be possible anymore after a perform
375             clean( performRequest );
376         }
377 
378         updateListener( performRequest.getReleaseManagerListener(), "perform", GOAL_END );
379     }
380 
381     @Override
382     public void branch( ReleaseBranchRequest branchRequest )
383         throws ReleaseExecutionException, ReleaseFailureException
384     {
385         final ReleaseDescriptorBuilder builder = branchRequest.getReleaseDescriptorBuilder();
386         
387         ReleaseUtils.copyPropertiesToReleaseDescriptor( branchRequest.getUserProperties(),
388                     new ReleaseDescriptorBuilder()
389                     {
390                         public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
391                                                                                String value )
392                         {
393                             builder.addDevelopmentVersion( key, value );
394                             return this;
395                         }
396 
397                         public ReleaseDescriptorBuilder addReleaseVersion( String key,
398                                                                            String value )
399                         {
400                             builder.addReleaseVersion( key, value );
401                             return this;
402                         }
403                     } );
404         
405         ReleaseDescriptor releaseDescriptor =
406             loadReleaseDescriptor( builder, branchRequest.getReleaseManagerListener() );
407 
408         boolean dryRun = BooleanUtils.isTrue( branchRequest.getDryRun() );
409 
410         Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
411 
412         List<String> branchPhases = getGoalPhases( releaseStrategy, "branch" );
413 
414         goalStart( branchRequest.getReleaseManagerListener(), "branch", branchPhases );
415 
416         for ( String name : branchPhases )
417         {
418             ReleasePhase phase = releasePhases.get( name );
419 
420             if ( phase == null )
421             {
422                 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
423             }
424 
425             updateListener( branchRequest.getReleaseManagerListener(), name, PHASE_START );
426 
427             if ( dryRun )
428             {
429                 phase.simulate( releaseDescriptor,
430                                 branchRequest.getReleaseEnvironment(),
431                                 branchRequest.getReactorProjects() );
432             }
433             else // getDryRun is null or FALSE
434             {
435                 phase.execute( releaseDescriptor,
436                                branchRequest.getReleaseEnvironment(),
437                                branchRequest.getReactorProjects() );
438             }
439             updateListener( branchRequest.getReleaseManagerListener(), name, PHASE_END );
440         }
441 
442         if ( !dryRun )
443         {
444             clean( branchRequest );
445         }
446 
447         updateListener( branchRequest.getReleaseManagerListener(), "branch", GOAL_END );
448     }
449 
450     @Override
451     public void updateVersions( ReleaseUpdateVersionsRequest updateVersionsRequest )
452         throws ReleaseExecutionException, ReleaseFailureException
453     {
454         final ReleaseDescriptorBuilder builder = updateVersionsRequest.getReleaseDescriptorBuilder();
455         
456         // Create a config containing values from the session properties (ie command line properties with cli).
457         ReleaseUtils.copyPropertiesToReleaseDescriptor( updateVersionsRequest.getUserProperties(),
458                                     new ReleaseDescriptorBuilder()
459                                     {
460                                         public ReleaseDescriptorBuilder addDevelopmentVersion( String key,
461                                                                                                String value )
462                                         {
463                                             builder.addDevelopmentVersion( key, value );
464                                             return this;
465                                         }
466 
467                                         public ReleaseDescriptorBuilder addReleaseVersion( String key,
468                                                                                            String value )
469                                         {
470                                             builder.addReleaseVersion( key, value );
471                                             return this;
472                                         }
473                                     } );
474 
475         ReleaseDescriptor releaseDescriptor =
476             loadReleaseDescriptor( builder, updateVersionsRequest.getReleaseManagerListener() );
477 
478         Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
479 
480         List<String> updateVersionsPhases = getGoalPhases( releaseStrategy, "updateVersions" );
481 
482         goalStart( updateVersionsRequest.getReleaseManagerListener(), "updateVersions", updateVersionsPhases );
483 
484         for ( String name : updateVersionsPhases )
485         {
486             ReleasePhase phase = releasePhases.get( name );
487 
488             if ( phase == null )
489             {
490                 throw new ReleaseExecutionException( "Unable to find phase '" + name + "' to execute" );
491             }
492 
493             updateListener( updateVersionsRequest.getReleaseManagerListener(), name, PHASE_START );
494             phase.execute( releaseDescriptor,
495                            updateVersionsRequest.getReleaseEnvironment(),
496                            updateVersionsRequest.getReactorProjects() );
497             updateListener( updateVersionsRequest.getReleaseManagerListener(), name, PHASE_END );
498         }
499 
500         clean( updateVersionsRequest );
501 
502         updateListener( updateVersionsRequest.getReleaseManagerListener(), "updateVersions", GOAL_END );
503     }
504 
505     /**
506      * Determines the path of the working directory. By default, this is the
507      * checkout directory. For some SCMs, the project root directory is not the
508      * checkout directory itself, but a SCM-specific subdirectory.
509      *
510      * @param checkoutDirectory            The checkout directory as java.io.File
511      * @param relativePathProjectDirectory The relative path of the project directory within the checkout
512      *                                     directory or ""
513      * @return The working directory
514      */
515     protected File determineWorkingDirectory( File checkoutDirectory, String relativePathProjectDirectory )
516     {
517         if ( StringUtils.isNotEmpty( relativePathProjectDirectory ) )
518         {
519             return new File( checkoutDirectory, relativePathProjectDirectory );
520         }
521         else
522         {
523             return checkoutDirectory;
524         }
525     }
526 
527     private BuilderReleaseDescriptor loadReleaseDescriptor( ReleaseDescriptorBuilder builder,
528                                                      ReleaseManagerListener listener )
529         throws ReleaseExecutionException
530     {
531         return ReleaseUtils.buildReleaseDescriptor( loadReleaseDescriptorBuilder( builder, listener ) );
532     }
533 
534     private ReleaseDescriptorBuilder loadReleaseDescriptorBuilder( ReleaseDescriptorBuilder builder,
535                                                      ReleaseManagerListener listener )
536         throws ReleaseExecutionException
537     {
538         try
539         {
540             updateListener( listener, "verify-release-configuration", PHASE_START );
541             ReleaseDescriptorBuilder result = configStore.read( builder );
542             updateListener( listener, "verify-release-configuration", PHASE_END );
543             return result;
544         }
545         catch ( ReleaseDescriptorStoreException e )
546         {
547             updateListener( listener, e.getMessage(), ERROR );
548 
549             throw new ReleaseExecutionException( "Error reading stored configuration: " + e.getMessage(), e );
550         }
551     }
552 
553     /**
554      * <p>clean.</p>
555      *
556      * @param releaseRequest a {@link org.apache.maven.shared.release.AbstractReleaseRequest} object
557      * @throws org.apache.maven.shared.release.ReleaseFailureException if any.
558      */
559     protected void clean( AbstractReleaseRequest releaseRequest  ) throws ReleaseFailureException
560     {
561         ReleaseCleanRequest cleanRequest = new ReleaseCleanRequest();
562         cleanRequest.setReleaseDescriptorBuilder( releaseRequest.getReleaseDescriptorBuilder() );
563         cleanRequest.setReleaseManagerListener( releaseRequest.getReleaseManagerListener() );
564         cleanRequest.setReactorProjects( releaseRequest.getReactorProjects() );
565 
566         clean( cleanRequest );
567     }
568 
569     @Override
570     public void clean( ReleaseCleanRequest cleanRequest ) throws ReleaseFailureException
571     {
572         updateListener( cleanRequest.getReleaseManagerListener(), "cleanup", PHASE_START );
573 
574         getLogger().info( "Cleaning up after release..." );
575 
576         ReleaseDescriptor releaseDescriptor =
577             ReleaseUtils.buildReleaseDescriptor( cleanRequest.getReleaseDescriptorBuilder() );
578 
579         configStore.delete( releaseDescriptor );
580 
581         Strategy releaseStrategy = getStrategy( releaseDescriptor.getReleaseStrategyId() );
582 
583         Set<String> phases = new LinkedHashSet<>();
584         phases.addAll( getGoalPhases( releaseStrategy, "prepare" ) );
585         phases.addAll( getGoalPhases( releaseStrategy, "branch" ) );
586 
587         for ( String name : phases )
588         {
589             ReleasePhase phase = releasePhases.get( name );
590             
591             if ( phase instanceof ResourceGenerator )
592             {
593                 ( (ResourceGenerator) phase ).clean( cleanRequest.getReactorProjects() );
594             }
595         }
596 
597         updateListener( cleanRequest.getReleaseManagerListener(), "cleanup", PHASE_END );
598     }
599 
600     void setConfigStore( ReleaseDescriptorStore configStore )
601     {
602         this.configStore = configStore;
603     }
604 
605     void goalStart( ReleaseManagerListener listener, String goal, List<String> phases )
606     {
607         if ( listener != null )
608         {
609             listener.goalStart( goal, phases );
610         }
611     }
612 
613     void updateListener( ReleaseManagerListener listener, String name, int state )
614     {
615         if ( listener != null )
616         {
617             switch ( state )
618             {
619                 case GOAL_END:
620                     listener.goalEnd();
621                     break;
622                 case PHASE_SKIP:
623                     listener.phaseSkip( name );
624                     break;
625                 case PHASE_START:
626                     listener.phaseStart( name );
627                     break;
628                 case PHASE_END:
629                     listener.phaseEnd();
630                     break;
631                 default:
632                     listener.error( name );
633             }
634         }
635     }
636 
637     private Strategy getStrategy( String strategyId ) throws ReleaseFailureException
638     {
639         Strategy strategy = strategies.get( strategyId );
640         if ( strategy == null )
641         {
642             throw new ReleaseFailureException( "Unknown strategy: " + strategyId );
643         }
644         return strategy;
645     }
646 
647     private List<String> getGoalPhases( Strategy strategy, String goal )
648     {
649         List<String> phases;
650 
651         if ( "prepare".equals( goal ) )
652         {
653             phases = strategy.getPreparePhases();
654             if ( phases  == null )
655             {
656                 phases = strategies.get( "default" ).getPreparePhases();
657             }
658         }
659         else if ( "perform".equals( goal ) )
660         {
661             phases = strategy.getPerformPhases();
662             if ( phases  == null )
663             {
664                 phases = strategies.get( "default" ).getPerformPhases();
665             }
666         }
667         else if ( "rollback".equals( goal ) )
668         {
669             phases = strategy.getRollbackPhases();
670             if ( phases  == null )
671             {
672                 phases = strategies.get( "default" ).getRollbackPhases();
673             }
674         }
675         else if ( "branch".equals( goal ) )
676         {
677             phases = strategy.getBranchPhases();
678             if ( phases  == null )
679             {
680                 phases = strategies.get( "default" ).getBranchPhases();
681             }
682         }
683         else if ( "updateVersions".equals( goal ) )
684         {
685             phases = strategy.getUpdateVersionsPhases();
686             if ( phases  == null )
687             {
688                 phases = strategies.get( "default" ).getUpdateVersionsPhases();
689             }
690         }
691         else
692         {
693             phases = null;
694         }
695 
696         return Collections.unmodifiableList( phases );
697     }
698 
699     private void logInfo( ReleaseResult result, String message )
700     {
701         if ( result != null )
702         {
703             result.appendInfo( message );
704         }
705 
706         getLogger().info( message );
707     }
708 
709     private void captureException( ReleaseResult result, ReleaseManagerListener listener, Exception e )
710     {
711         updateListener( listener, e.getMessage(), ERROR );
712 
713         result.appendError( e );
714 
715         result.setResultCode( ReleaseResult.ERROR );
716     }
717 }