View Javadoc

1   package org.codehaus.mojo.build;
2   
3   /**
4    * The MIT License
5    *
6    * Copyright (c) 2005 Learning Commons, University of Calgary
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
9    * associated documentation files (the "Software"), to deal in the Software without restriction,
10   * including without limitation the rights to use, copy, modify, merge, publish, distribute,
11   * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   *
14   * The above copyright notice and this permission notice shall be included in all copies or
15   * substantial portions of the Software.
16   *
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
18   * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20   * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22   */
23  
24  import org.apache.maven.execution.MavenSession;
25  import org.apache.maven.plugin.AbstractMojo;
26  import org.apache.maven.plugin.MojoExecutionException;
27  import org.apache.maven.plugin.MojoFailureException;
28  import org.apache.maven.project.MavenProject;
29  import org.apache.maven.scm.CommandParameter;
30  import org.apache.maven.scm.CommandParameters;
31  import org.apache.maven.scm.ScmException;
32  import org.apache.maven.scm.ScmFile;
33  import org.apache.maven.scm.ScmFileSet;
34  import org.apache.maven.scm.ScmResult;
35  import org.apache.maven.scm.command.info.InfoItem;
36  import org.apache.maven.scm.command.info.InfoScmResult;
37  import org.apache.maven.scm.command.status.StatusScmResult;
38  import org.apache.maven.scm.command.update.UpdateScmResult;
39  import org.apache.maven.scm.command.update.UpdateScmResultWithRevision;
40  import org.apache.maven.scm.log.ScmLogDispatcher;
41  import org.apache.maven.scm.log.ScmLogger;
42  import org.apache.maven.scm.manager.ScmManager;
43  import org.apache.maven.scm.provider.ScmProvider;
44  import org.apache.maven.scm.provider.ScmProviderRepository;
45  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
46  import org.apache.maven.scm.repository.ScmRepository;
47  import org.codehaus.plexus.util.StringUtils;
48  
49  import java.io.File;
50  import java.io.FileInputStream;
51  import java.io.FileOutputStream;
52  import java.io.IOException;
53  import java.text.MessageFormat;
54  import java.util.Calendar;
55  import java.util.Collections;
56  import java.util.Date;
57  import java.util.Iterator;
58  import java.util.List;
59  import java.util.Locale;
60  import java.util.Map;
61  import java.util.Map.Entry;
62  import java.util.Properties;
63  
64  /**
65   * This mojo is designed to give you a build number. So when you might make 100 builds of version
66   * 1.0-SNAPSHOT, you can differentiate between them all. The build number is based on the revision
67   * number retrieved from scm. It only works with subversion, currently. This mojo can also check to
68   * make sure that you have checked everything into scm, before issuing the build number. That
69   * behaviour can be suppressed, and then the latest local build number is used. Build numbers are
70   * not reflected in your artifact's filename (automatically), but can be added to the metadata. You
71   * can access the build number in your pom with ${buildNumber}. You can also access ${timestamp} and
72   * the scm branch of the build (if applicable) in ${buildScmBranch}
73   *
74   * @author <a href="mailto:woodj@ucalgary.ca">Julian Wood</a>
75   * @version $Id: CreateMojo.java 16316 2012-04-10 08:21:00Z olamy $
76   * @goal create
77   * @phase initialize
78   * @requiresProject
79   * @description create a timestamp and a build number from scm or an integer sequence
80   */
81  public class CreateMojo
82      extends AbstractMojo
83  {
84  
85      public final String DEFAULT_BRANCH_NAME = "UNKNOWN_BRANCH";
86  
87      /**
88       * @parameter expression="${project.scm.developerConnection}"
89       * @readonly
90       */
91      private String urlScm;
92  
93      /**
94       * @parameter expression="${project.scm.connection}"
95       * @readonly
96       * @since 1.0-beta-5
97       */
98      private String readUrlScm;
99  
100     /**
101      * The username that is used when connecting to the SCM system.
102      *
103      * @parameter expression="${username}"
104      * @since 1.0-beta-1
105      */
106     private String username;
107 
108     /**
109      * The password that is used when connecting to the SCM system.
110      *
111      * @parameter expression="${password}"
112      * @since 1.0-beta-1
113      */
114     private String password;
115 
116     /**
117      * Local directory to be used to issue SCM actions
118      *
119      * @parameter expression="${maven.buildNumber.scmDirectory}" default-value="${basedir}
120      * @since 1.0-beta-
121      */
122     private File scmDirectory;
123 
124 
125     /**
126      * You can rename the buildNumber property name to another property name if desired.
127      *
128      * @parameter expression="${maven.buildNumber.buildNumberPropertyName}"
129      * default-value="buildNumber"
130      * @since 1.0-beta-1
131      */
132     private String buildNumberPropertyName;
133 
134     /**
135      * You can rename the timestamp property name to another property name if desired.
136      *
137      * @parameter expression="${maven.buildNumber.timestampPropertyName}" default-value="timestamp"
138      * @since 1.0-beta-1
139      */
140     private String timestampPropertyName;
141 
142     /**
143      * If this is made true, we check for modified files, and if there are any, we fail the build.
144      * Note that this used to be inverted (skipCheck), but needed to be changed to allow releases to
145      * work. This corresponds to 'svn status'.
146      *
147      * @parameter expression="${maven.buildNumber.doCheck}" default-value="false"
148      * @since 1.0-beta-1
149      */
150     private boolean doCheck;
151 
152     /**
153      * If this is made true, then the revision will be updated to the latest in the repo, otherwise
154      * it will remain what it is locally. Note that this used to be inverted (skipUpdate), but
155      * needed to be changed to allow releases to work. This corresponds to 'svn update'.
156      * <p/>
157      * Note that these expressions (doCheck, doUpdate, etc) are the first thing evaluated. If there
158      * is no matching expression, we get the default-value. If there is (ie
159      * -Dmaven.buildNumber.doCheck=false), we get that value. The configuration, however, gets the
160      * last say, through use of the getters/setters below. So if <doCheck>true</doCheck>, then
161      * normally that's the final value of the param in question. However, this mojo reverses that
162      * behaviour, such that the command line parameters get the last say.
163      *
164      * @parameter expression="${maven.buildNumber.doUpdate}" default-value="false"
165      * @since 1.0-beta-1
166      */
167     private boolean doUpdate;
168 
169     /**
170      * Specify a message as specified by java.text.MessageFormat. This triggers "items"
171      * configuration to be read
172      *
173      * @parameter
174      * @since 1.0-beta-1
175      */
176     private String format;
177 
178     /**
179      * Properties file to be created when "format" is not null and item has "buildNumber". See Usage
180      * for details
181      *
182      * @parameter default-value="${basedir}/buildNumber.properties";
183      * @since 1.0-beta-2
184      */
185     private File buildNumberPropertiesFileLocation;
186 
187     /**
188      * Specify the corresponding items for the format message, as specified by
189      * java.text.MessageFormat. Special item values are "timestamp" and "buildNumber/d*".
190      *
191      * @parameter
192      * @since 1.0-beta-1
193      */
194     private List items;
195 
196     /**
197      * The locale used for date and time formatting. The locale name should be in the format defined
198      * in {@link Locale#toString()}. The default locale is the platform default returned by
199      * {@link Locale#getDefault()}.
200      *
201      * @parameter expression="${maven.buildNumber.locale}"
202      * @since 1.0-beta-2
203      */
204     private String locale;
205 
206     /**
207      * whether to retrieve the revision for the last commit, or the last revision of the repository.
208      *
209      * @parameter expression="${maven.buildNumber.useLastCommittedRevision}" default-value="false"
210      * @since 1.0-beta-2
211      */
212     private boolean useLastCommittedRevision;
213 
214     /**
215      * Apply this java.text.MessageFormat to the timestamp only (as opposed to the
216      * <code>format</code> parameter).
217      *
218      * @parameter
219      * @since 1.0-beta-2
220      */
221     private String timestampFormat;
222 
223     /**
224      * Setting this value allows the build to continue even in the event of an SCM failure.  The value set will be
225      * used as the revision string in the event of a failure to retrieve the revision it from the SCM.
226      *
227      * @parameter
228      * @since 1.0-beta-2
229      */
230     private String revisionOnScmFailure;
231 
232     /**
233      * Selects alternative SCM provider implementations. Each map key denotes the original provider type as given in the
234      * SCM URL like "cvs" or "svn", the map value specifies the provider type of the desired implementation to use
235      * instead. In other words, this map configures a substitition mapping for SCM providers.
236      *
237      * @parameter
238      * @since 1.0-beta-3
239      */
240     private Map<String, String> providerImplementations;
241 
242     /**
243      * @component
244      */
245     private ScmManager scmManager;
246 
247     /**
248      * The maven project.
249      *
250      * @parameter expression="${project}"
251      * @readonly
252      */
253     private MavenProject project;
254 
255     /**
256      * Contains the full list of projects in the reactor.
257      *
258      * @parameter expression="${reactorProjects}"
259      * @readonly
260      * @since 1.0-beta-3
261      */
262     private List reactorProjects;
263 
264     /**
265      * If set to true, will get the scm revision once for all modules of a multi-module project
266      * instead of fetching once for each module.
267      *
268      * @parameter default-value="false"
269      * @since 1.0-beta-3
270      */
271     private boolean getRevisionOnlyOnce;
272 
273     /**
274      * You can rename the buildScmBranch property name to another property name if desired.
275      *
276      * @parameter expression="${maven.buildNumber.scmBranchPropertyName}"
277      * default-value="scmBranch"
278      * @since 1.0-beta-4
279      */
280     private String scmBranchPropertyName;
281 
282 
283     /**
284      * @parameter expression="${session}"
285      * @readonly
286      * @required
287      */
288     protected MavenSession session;
289 
290     private ScmLogDispatcher logger;
291 
292     private String revision;
293 
294     /**
295      * Max length of a revision id (used only for git)
296      *
297      * @parameter default value is null
298      * @since 1.1
299      */
300     private int shortRevisionLength = DEFAULT_SHORT_REVISION_DISABLED;
301 
302     /**
303      * @since 1.1
304      */
305     private static final int DEFAULT_SHORT_REVISION_DISABLED = -1;
306 
307     public void execute()
308         throws MojoExecutionException, MojoFailureException
309     {
310         if ( providerImplementations != null )
311         {
312             for ( Entry<String, String> entry : providerImplementations.entrySet() )
313             {
314                 String providerType = entry.getKey();
315                 String providerImplementation = entry.getValue();
316                 getLog().info(
317                     "Change the default '" + providerType + "' provider implementation to '" + providerImplementation
318                         + "'." );
319                 scmManager.setScmProviderImplementation( providerType, providerImplementation );
320             }
321         }
322         Date now = Calendar.getInstance().getTime();
323         if ( format != null )
324         {
325             if ( items == null )
326             {
327                 throw new MojoExecutionException(
328                     " if you set a format, you must provide at least one item, please check documentation " );
329             }
330             // needs to be an array
331             // look for special values
332             Object[] itemAry = new Object[items.size()];
333             for ( int i = 0; i < items.size(); i++ )
334             {
335                 Object item = items.get( i );
336                 if ( item instanceof String )
337                 {
338                     String s = (String) item;
339                     if ( s.equals( "timestamp" ) )
340                     {
341                         itemAry[i] = now;
342                     }
343                     else if ( s.startsWith( "buildNumber" ) )
344                     {
345                         // check for properties file
346                         File propertiesFile = this.buildNumberPropertiesFileLocation;
347 
348                         // create if not exists
349                         if ( !propertiesFile.exists() )
350                         {
351                             try
352                             {
353                                 if ( !propertiesFile.getParentFile().exists() )
354                                 {
355                                     propertiesFile.getParentFile().mkdirs();
356                                 }
357                                 propertiesFile.createNewFile();
358                             }
359                             catch ( IOException e )
360                             {
361                                 throw new MojoExecutionException( "Couldn't create properties file: " + propertiesFile,
362                                                                   e );
363                             }
364                         }
365 
366                         Properties properties = new Properties();
367                         String buildNumberString = null;
368                         try
369                         {
370                             // get the number for the buildNumber specified
371                             properties.load( new FileInputStream( propertiesFile ) );
372                             buildNumberString = properties.getProperty( s );
373                             if ( buildNumberString == null )
374                             {
375                                 buildNumberString = "0";
376                             }
377                             int buildNumber = Integer.valueOf( buildNumberString ).intValue();
378 
379                             // store the increment
380                             properties.setProperty( s, String.valueOf( ++buildNumber ) );
381                             properties.store( new FileOutputStream( propertiesFile ),
382                                               "maven.buildNumber.plugin properties file" );
383 
384                             // use in the message (format)
385                             itemAry[i] = new Integer( buildNumber );
386                         }
387                         catch ( NumberFormatException e )
388                         {
389                             throw new MojoExecutionException(
390                                 "Couldn't parse buildNumber in properties file to an Integer: " + buildNumberString );
391                         }
392                         catch ( IOException e )
393                         {
394                             throw new MojoExecutionException( "Couldn't load properties file: " + propertiesFile, e );
395                         }
396                     }
397                     else
398                     {
399                         itemAry[i] = item;
400                     }
401                 }
402                 else
403                 {
404                     itemAry[i] = item;
405                 }
406             }
407 
408             revision = format( itemAry );
409         }
410         else
411         {
412             // Check if the plugin has already run.
413             revision = project.getProperties().getProperty( this.buildNumberPropertyName );
414             if ( this.getRevisionOnlyOnce && revision != null )
415             {
416                 getLog().debug( "Revision available from previous execution" );
417                 return;
418             }
419 
420             if ( doCheck )
421             {
422                 // we fail if there are local mods
423                 checkForLocalModifications();
424             }
425             else
426             {
427                 getLog().info( "Checking for local modifications: skipped." );
428             }
429             if ( session.getSettings().isOffline() )
430             {
431                 getLog().info( "maven is executed in offline mode, Updating project files from SCM: skipped." );
432             }
433             else
434             {
435                 if ( doUpdate )
436                 {
437                     // we update your local repo
438                     // even after you commit, your revision stays the same until you update, thus this
439                     // action
440                     List<ScmFile> changedFiles = update();
441                     for ( ScmFile file : changedFiles )
442                     {
443                         getLog().info( "Updated: " + file );
444                     }
445                     if ( changedFiles.size() == 0 )
446                     {
447                         getLog().info( "No files needed updating." );
448                     }
449                 }
450                 else
451                 {
452                     getLog().info( "Updating project files from SCM: skipped." );
453                 }
454             }
455             revision = getRevision();
456         }
457 
458         if ( project != null )
459         {
460             String timestamp = String.valueOf( now.getTime() );
461             if ( timestampFormat != null )
462             {
463                 timestamp = MessageFormat.format( timestampFormat, new Object[]{ now } );
464             }
465 
466             getLog().info( MessageFormat.format( "Storing buildNumber: {0} at timestamp: {1}",
467                                                  new Object[]{ revision, timestamp } ) );
468             if ( revision != null )
469             {
470                 project.getProperties().put( buildNumberPropertyName, revision );
471             }
472             project.getProperties().put( timestampPropertyName, timestamp );
473 
474             String scmBranch = getScmBranch();
475             getLog().info( "Storing buildScmBranch: " + scmBranch );
476             project.getProperties().put( scmBranchPropertyName, scmBranch );
477 
478             // Add the revision and timestamp properties to each project in the reactor
479             if ( getRevisionOnlyOnce && reactorProjects != null )
480             {
481                 Iterator projIter = reactorProjects.iterator();
482                 while ( projIter.hasNext() )
483                 {
484                     MavenProject nextProj = (MavenProject) projIter.next();
485                     if ( revision != null )
486                     {
487                         nextProj.getProperties().put( this.buildNumberPropertyName, revision );
488                     }
489                     nextProj.getProperties().put( this.timestampPropertyName, timestamp );
490                     nextProj.getProperties().put( this.scmBranchPropertyName, scmBranch );
491                 }
492             }
493         }
494     }
495 
496     /**
497      * Formats the given argument using the configured format template and locale.
498      *
499      * @param arguments arguments to be formatted @ @return formatted result
500      */
501     private String format( Object[] arguments )
502     {
503         Locale l = Locale.getDefault();
504         if ( locale != null )
505         {
506             String[] parts = locale.split( "_", 3 );
507             if ( parts.length <= 1 )
508             {
509                 l = new Locale( locale );
510             }
511             else if ( parts.length == 2 )
512             {
513                 l = new Locale( parts[0], parts[1] );
514             }
515             else
516             {
517                 l = new Locale( parts[0], parts[1], parts[2] );
518             }
519         }
520 
521         return new MessageFormat( format, l ).format( arguments );
522     }
523 
524     private void checkForLocalModifications()
525         throws MojoExecutionException
526     {
527         getLog().info( "Verifying there are no local modifications ..." );
528 
529         List<ScmFile> changedFiles;
530 
531         try
532         {
533             changedFiles = getStatus();
534         }
535         catch ( ScmException e )
536         {
537             throw new MojoExecutionException( "An error has occurred while checking scm status.", e );
538         }
539 
540         if ( !changedFiles.isEmpty() )
541         {
542             StringBuilder message = new StringBuilder();
543 
544             String ls = System.getProperty( "line.separator" );
545 
546             for ( ScmFile file : changedFiles )
547             {
548                 message.append( file.toString() );
549 
550                 message.append( ls );
551             }
552 
553             throw new MojoExecutionException(
554                 "Cannot create the build number because you have local modifications : \n" + message );
555         }
556 
557     }
558 
559     public List<ScmFile> update()
560         throws MojoExecutionException
561     {
562         try
563         {
564             ScmRepository repository = getScmRepository();
565 
566             ScmProvider scmProvider = scmManager.getProviderByRepository( repository );
567 
568             UpdateScmResult result = scmProvider.update( repository, new ScmFileSet( scmDirectory ) );
569 
570             if ( result == null )
571             {
572                 return Collections.emptyList();
573             }
574 
575             checkResult( result );
576 
577             if ( result instanceof UpdateScmResultWithRevision )
578             {
579                 String revision = ( (UpdateScmResultWithRevision) result ).getRevision();
580                 getLog().info( "Got a revision during update: " + revision );
581                 this.revision = revision;
582             }
583 
584             return result.getUpdatedFiles();
585         }
586         catch ( ScmException e )
587         {
588             throw new MojoExecutionException( "Couldn't update project. " + e.getMessage(), e );
589         }
590 
591     }
592 
593     public List<ScmFile> getStatus()
594         throws ScmException
595     {
596 
597         ScmRepository repository = getScmRepository();
598 
599         ScmProvider scmProvider = scmManager.getProviderByRepository( repository );
600 
601         StatusScmResult result = scmProvider.status( repository, new ScmFileSet( scmDirectory ) );
602 
603         if ( result == null )
604         {
605             return Collections.emptyList();
606         }
607 
608         checkResult( result );
609 
610         return result.getChangedFiles();
611 
612     }
613 
614     /**
615      * Get the branch info for this revision from the repository. For svn, it is in svn info.
616      *
617      * @return
618      * @throws MojoExecutionException
619      * @throws MojoExecutionException
620      */
621     public String getScmBranch()
622         throws MojoExecutionException
623     {
624         String scmUrl = null;
625         try
626         {
627             ScmRepository repository = getScmRepository();
628             InfoScmResult scmResult = info( repository, new ScmFileSet( scmDirectory ) );
629             if ( scmResult == null || !scmResult.isSuccess() )
630             {
631                 getLog().debug( "Cannot get the branch information from the scm repository : " + ( scmResult == null
632                     ? ""
633                     : scmResult.getCommandOutput() ) );
634                 return DEFAULT_BRANCH_NAME;
635             }
636             if ( scmResult.getInfoItems().isEmpty() )
637             {
638                 if ( !StringUtils.isEmpty( revisionOnScmFailure ) )
639                 {
640                     setDoCheck( false );
641                     setDoUpdate( false );
642 
643                     return DEFAULT_BRANCH_NAME;
644                 }
645             }
646             if ( !scmResult.getInfoItems().isEmpty() )
647             {
648                 InfoItem info = scmResult.getInfoItems().get( 0 );
649                 scmUrl = info.getURL();
650             }
651         }
652         catch ( ScmException e )
653         {
654             if ( !StringUtils.isEmpty( revisionOnScmFailure ) )
655             {
656                 getLog().warn(
657                     "Cannot get the branch information from the scm repository, proceeding with " + DEFAULT_BRANCH_NAME
658                         + " : \n" + e.getLocalizedMessage() );
659 
660                 setDoCheck( false );
661                 setDoUpdate( false );
662 
663                 return DEFAULT_BRANCH_NAME;
664             }
665             throw new MojoExecutionException(
666                 "Cannot get the branch information from the scm repository : \n" + e.getLocalizedMessage(), e );
667         }
668 
669         return filterBranchFromScmUrl( scmUrl );
670     }
671 
672     protected String filterBranchFromScmUrl( String scmUrl )
673     {
674         String scmBranch = "UNKNOWN";
675 
676         if ( StringUtils.contains( scmUrl, "/trunk" ) )
677         {
678             scmBranch = "trunk";
679         }
680         else if ( StringUtils.contains( scmUrl, "/branches" ) || StringUtils.contains( scmUrl, "/tags" ) )
681         {
682             scmBranch = scmUrl.replaceFirst( ".*((branches|tags)[^/]*).*?", "$1" );
683         }
684         return scmBranch;
685     }
686 
687     /**
688      * Get the revision info from the repository. For svn, it is svn info
689      *
690      * @return
691      * @throws MojoExecutionException
692      */
693     public String getRevision()
694         throws MojoExecutionException
695     {
696 
697         if ( format != null )
698         {
699             return revision;
700         }
701 
702         try
703         {
704             ScmRepository repository = getScmRepository();
705 
706             InfoScmResult scmResult = info( repository, new ScmFileSet( scmDirectory ) );
707 
708             if ( scmResult == null || scmResult.getInfoItems().isEmpty() )
709             {
710                 return ( !StringUtils.isEmpty( revisionOnScmFailure ) ) ? revisionOnScmFailure : null;
711             }
712 
713             checkResult( scmResult );
714 
715             InfoItem info = scmResult.getInfoItems().get( 0 );
716 
717             if ( useLastCommittedRevision )
718             {
719                 return info.getLastChangedRevision();
720             }
721 
722             return info.getRevision();
723         }
724         catch ( ScmException e )
725         {
726             if ( !StringUtils.isEmpty( revisionOnScmFailure ) )
727             {
728                 getLog().warn(
729                     "Cannot get the revision information from the scm repository, proceeding with " + "revision of "
730                         + revisionOnScmFailure + " : \n" + e.getLocalizedMessage() );
731 
732                 setDoCheck( false );
733                 setDoUpdate( false );
734 
735                 return revisionOnScmFailure;
736             }
737 
738             throw new MojoExecutionException(
739                 "Cannot get the revision information from the scm repository : \n" + e.getLocalizedMessage(), e );
740 
741         }
742 
743     }
744 
745     /**
746      * Get info from scm.
747      *
748      * @param repository
749      * @param fileSet
750      * @return
751      * @throws ScmException
752      * @todo this should be rolled into org.apache.maven.scm.provider.ScmProvider and
753      * org.apache.maven.scm.provider.svn.SvnScmProvider
754      */
755     public InfoScmResult info( ScmRepository repository, ScmFileSet fileSet )
756         throws ScmException
757     {
758         CommandParameters commandParameters = new CommandParameters();
759         //only for Git, we will make a test for shortRevisionLength parameter
760         if ( GitScmProviderRepository.PROTOCOL_GIT.equals(
761             scmManager.getProviderByRepository( repository ).getScmType() )
762             && this.shortRevisionLength != DEFAULT_SHORT_REVISION_DISABLED )
763         {
764             getLog().info( "ShortRevision tag detected. The value is '" + this.shortRevisionLength + "'." );
765             if ( shortRevisionLength >= 0 && shortRevisionLength < 4 )
766             {
767                 getLog().warn(
768                     "shortRevision parameter less then 4. ShortRevisionLength is relaying on 'git rev-parese --short=LENGTH' command, accordingly to Git rev-parse specification the LENGTH value is miminum 4. " );
769             }
770             commandParameters.setInt( CommandParameter.SCM_SHORT_REVISION_LENGTH, this.shortRevisionLength );
771         }
772 
773         return scmManager.getProviderByRepository( repository ).info( repository.getProviderRepository(), fileSet,
774                                                                       commandParameters );
775     }
776 
777 
778     /**
779      * @return
780      * @todo normally this would be handled in AbstractScmProvider
781      */
782     private ScmLogger getLogger()
783     {
784         if ( logger == null )
785         {
786             logger = new ScmLogDispatcher();
787         }
788         return logger;
789     }
790 
791     private ScmRepository getScmRepository()
792         throws ScmException
793     {
794         ScmRepository repository = scmManager.makeScmRepository( StringUtils.isBlank( urlScm ) ? readUrlScm : urlScm );
795 
796         ScmProviderRepository scmRepo = repository.getProviderRepository();
797 
798         if ( !StringUtils.isEmpty( username ) )
799         {
800             scmRepo.setUser( username );
801         }
802 
803         if ( !StringUtils.isEmpty( password ) )
804         {
805             scmRepo.setPassword( password );
806         }
807 
808         return repository;
809     }
810 
811     private void checkResult( ScmResult result )
812         throws ScmException
813     {
814         if ( !result.isSuccess() )
815         {
816             // TODO: improve error handling
817             getLog().error( "Provider message:" );
818 
819             getLog().error( result.getProviderMessage() );
820 
821             getLog().error( "Command output:" );
822 
823             getLog().error( result.getCommandOutput() );
824 
825             throw new ScmException( "Error!" );
826         }
827     }
828 
829     //////////////////////////////////////////////////////////////////////////////////////////////
830     // setters to help with test
831     public void setScmManager( ScmManager scmManager )
832     {
833         this.scmManager = scmManager;
834     }
835 
836     public void setUrlScm( String urlScm )
837     {
838         this.urlScm = urlScm;
839     }
840 
841     public void setUsername( String username )
842     {
843         this.username = username;
844     }
845 
846     public void setPassword( String password )
847     {
848         this.password = password;
849     }
850 
851     public void setDoCheck( boolean doCheck )
852     {
853         String doCheckSystemProperty = System.getProperty( "maven.buildNumber.doCheck" );
854         if ( doCheckSystemProperty != null )
855         {
856             // well, this gets the final say
857             this.doCheck = Boolean.valueOf( doCheckSystemProperty ).booleanValue();
858         }
859         else
860         {
861             this.doCheck = doCheck;
862         }
863     }
864 
865     public void setDoUpdate( boolean doUpdate )
866     {
867         String doUpdateSystemProperty = System.getProperty( "maven.buildNumber.doUpdate" );
868         if ( doUpdateSystemProperty != null )
869         {
870             // well, this gets the final say
871             this.doUpdate = Boolean.valueOf( doUpdateSystemProperty ).booleanValue();
872         }
873         else
874         {
875             this.doUpdate = doUpdate;
876         }
877     }
878 
879     void setFormat( String format )
880     {
881         this.format = format;
882     }
883 
884     void setLocale( String locale )
885     {
886         this.locale = locale;
887     }
888 
889     void setItems( List items )
890     {
891         this.items = items;
892     }
893 
894     public void setBuildNumberPropertiesFileLocation( File buildNumberPropertiesFileLocation )
895     {
896         this.buildNumberPropertiesFileLocation = buildNumberPropertiesFileLocation;
897     }
898 
899     public void setScmDirectory( File scmDirectory )
900     {
901         this.scmDirectory = scmDirectory;
902     }
903 
904     public void setRevisionOnScmFailure( String revisionOnScmFailure )
905     {
906         this.revisionOnScmFailure = revisionOnScmFailure;
907     }
908 
909     public void setShortRevisionLength( int shortRevision )
910     {
911         this.shortRevisionLength = shortRevision;
912     }
913 }