View Javadoc
1   package org.apache.maven.report.projectinfo;
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 org.apache.commons.lang.SystemUtils;
23  import org.apache.maven.doxia.sink.Sink;
24  import org.apache.maven.model.Model;
25  import org.apache.maven.model.Scm;
26  import org.apache.maven.plugin.logging.Log;
27  import org.apache.maven.plugins.annotations.Component;
28  import org.apache.maven.plugins.annotations.Mojo;
29  import org.apache.maven.plugins.annotations.Parameter;
30  import org.apache.maven.scm.manager.NoSuchScmProviderException;
31  import org.apache.maven.scm.manager.ScmManager;
32  import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
33  import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
34  import org.apache.maven.scm.provider.hg.repository.HgScmProviderRepository;
35  import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
36  import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
37  import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
38  import org.apache.maven.scm.repository.ScmRepository;
39  import org.apache.maven.scm.repository.ScmRepositoryException;
40  import org.codehaus.plexus.i18n.I18N;
41  import org.codehaus.plexus.util.StringUtils;
42  
43  import java.util.ArrayList;
44  import java.util.List;
45  import java.util.Locale;
46  
47  /**
48   * Generates the Project Source Code Management (SCM) report.
49   *
50   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton </a>
51   * @version $Id: ScmReport.html 935177 2015-01-05 21:05:55Z michaelo $
52   * @since 2.0
53   */
54  @Mojo( name = "scm" )
55  public class ScmReport
56      extends AbstractProjectInfoReport
57  {
58      // ----------------------------------------------------------------------
59      // Mojo parameters
60      // ----------------------------------------------------------------------
61  
62      /**
63       * Maven SCM Manager.
64       */
65      @Component
66      protected ScmManager scmManager;
67  
68      /**
69       * The directory name to checkout right after the SCM URL.
70       */
71      @Parameter( defaultValue = "${project.artifactId}" )
72      private String checkoutDirectoryName;
73  
74      /**
75       * The SCM anonymous connection url respecting the SCM URL Format.
76       *
77       * @see <a href="http://maven.apache.org/scm/scm-url-format.html">SCM URL Format</a>
78       * @since 2.1
79       */
80      @Parameter( defaultValue = "${project.scm.connection}" )
81      private String anonymousConnection;
82  
83      /**
84       * The SCM developer connection url respecting the SCM URL Format.
85       *
86       * @see <a href="http://maven.apache.org/scm/scm-url-format.html">SCM URL Format</a>
87       * @since 2.1
88       */
89      @Parameter( defaultValue = "${project.scm.developerConnection}" )
90      private String developerConnection;
91  
92      /**
93       * The SCM web access url.
94       *
95       * @since 2.1
96       */
97      @Parameter( defaultValue = "${project.scm.url}" )
98      private String webAccessUrl;
99  
100     /**
101      * The SCM tag.
102      *
103      * @since 2.8
104      */
105     @Parameter( defaultValue = "${project.scm.tag}" )
106     private String scmTag;
107 
108     // ----------------------------------------------------------------------
109     // Public methods
110     // ----------------------------------------------------------------------
111 
112     @Override
113     public boolean canGenerateReport()
114     {
115         boolean result = super.canGenerateReport();
116         if ( result && skipEmptyReport )
117         {
118             Scm scm = getProject().getModel().getScm();
119             result = scm != null;
120 
121             if ( result && StringUtils.isEmpty( anonymousConnection )
122                     && StringUtils.isEmpty( developerConnection )
123                     && StringUtils.isEmpty( scm.getUrl() ) )
124             {
125                 result = false;
126             }
127         }
128 
129         return result;
130     }
131 
132     @Override
133     public void executeReport( Locale locale )
134     {
135         ScmRenderer r =
136             new ScmRenderer( getLog(), scmManager, getSink(), getProject().getModel(), getI18N( locale ), locale,
137                              checkoutDirectoryName, webAccessUrl, anonymousConnection, developerConnection, scmTag );
138 
139         r.render();
140     }
141 
142     /** {@inheritDoc} */
143     public String getOutputName()
144     {
145         return "source-repository";
146     }
147 
148     @Override
149     protected String getI18Nsection()
150     {
151         return "scm";
152     }
153 
154     // ----------------------------------------------------------------------
155     // Private
156     // ----------------------------------------------------------------------
157 
158     /**
159      * Internal renderer class
160      */
161     private static class ScmRenderer
162         extends AbstractProjectInfoRenderer
163     {
164         private Log log;
165 
166         private Model model;
167 
168         private ScmManager scmManager;
169 
170         /**
171          * To support more SCM
172          */
173         private String anonymousConnection;
174 
175         private String devConnection;
176 
177         private String checkoutDirectoryName;
178 
179         private String webAccessUrl;
180 
181         private String scmTag;
182 
183         ScmRenderer( Log log, ScmManager scmManager, Sink sink, Model model, I18N i18n, Locale locale,
184                      String checkoutDirName, String webAccessUrl, String anonymousConnection, String devConnection,
185                      String scmTag )
186         {
187             super( sink, i18n, locale );
188 
189             this.log = log;
190 
191             this.scmManager = scmManager;
192 
193             this.model = model;
194 
195             this.checkoutDirectoryName = checkoutDirName;
196 
197             this.webAccessUrl = webAccessUrl;
198 
199             this.anonymousConnection = anonymousConnection;
200 
201             this.devConnection = devConnection;
202 
203             this.scmTag = scmTag;
204         }
205 
206         @Override
207         protected String getI18Nsection()
208         {
209             return "scm";
210         }
211 
212         @Override
213         public void renderBody()
214         {
215             Scm scm = model.getScm();
216             if ( scm == null || StringUtils.isEmpty( anonymousConnection )
217                                 && StringUtils.isEmpty( devConnection )
218                                 && StringUtils.isEmpty( scm.getUrl() ) )
219             {
220                 startSection( getTitle() );
221 
222                 paragraph( getI18nString( "noscm" ) );
223 
224                 endSection();
225 
226                 return;
227             }
228 
229             ScmRepository anonymousRepository = getScmRepository( anonymousConnection );
230             ScmRepository devRepository = getScmRepository( devConnection );
231 
232             // Overview section
233             renderOverviewSection( anonymousRepository, devRepository );
234 
235             // Web access section
236             renderWebAccessSection( webAccessUrl );
237 
238             // Anonymous access section if needed
239             renderAnonymousAccessSection( anonymousRepository );
240 
241             // Developer access section
242             renderDeveloperAccessSection( devRepository );
243 
244             // Access from behind a firewall section if needed
245             renderAccessBehindFirewallSection( devRepository );
246 
247             // Access through a proxy section if needed
248             renderAccessThroughProxySection( anonymousRepository, devRepository );
249         }
250 
251         /**
252          * Render the overview section
253          *
254          * @param anonymousRepository the anonymous repository
255          * @param devRepository the developer repository
256          */
257         private void renderOverviewSection( ScmRepository anonymousRepository, ScmRepository devRepository )
258         {
259             startSection( getI18nString( "overview.title" ) );
260 
261             if ( isScmSystem( anonymousRepository, "clearcase" ) || isScmSystem( devRepository, "clearcase" ) )
262             {
263                 sink.paragraph();
264                 linkPatternedText( getI18nString( "clearcase.intro" ) );
265                 sink.paragraph_();
266             }
267             else if ( isScmSystem( anonymousRepository, "cvs" ) || isScmSystem( devRepository, "cvs" ) )
268             {
269                 sink.paragraph();
270                 linkPatternedText( getI18nString( "cvs.intro" ) );
271                 sink.paragraph_();
272             }
273             else if ( isScmSystem( anonymousRepository, "git" ) || isScmSystem( devRepository, "git" ) )
274             {
275                 sink.paragraph();
276                 linkPatternedText( getI18nString( "git.intro" ) );
277                 sink.paragraph_();
278             }
279             else if ( isScmSystem( anonymousRepository, "hg" ) || isScmSystem( devRepository, "hg" ) )
280             {
281                 sink.paragraph();
282                 linkPatternedText( getI18nString( "hg.intro" ) );
283                 sink.paragraph_();
284             }
285             else if ( isScmSystem( anonymousRepository, "perforce" ) || isScmSystem( devRepository, "perforce" ) )
286             {
287                 sink.paragraph();
288                 linkPatternedText( getI18nString( "perforce.intro" ) );
289                 sink.paragraph_();
290             }
291             else if ( isScmSystem( anonymousRepository, "starteam" ) || isScmSystem( devRepository, "starteam" ) )
292             {
293                 sink.paragraph();
294                 linkPatternedText( getI18nString( "starteam.intro" ) );
295                 sink.paragraph_();
296             }
297             else if ( isScmSystem( anonymousRepository, "svn" ) || isScmSystem( devRepository, "svn" ) )
298             {
299                 sink.paragraph();
300                 linkPatternedText( getI18nString( "svn.intro" ) );
301                 sink.paragraph_();
302             }
303             else
304             {
305                 paragraph( getI18nString( "general.intro" ) );
306             }
307 
308             endSection();
309         }
310 
311         /**
312          * Render the web access section
313          *
314          * @param scmUrl The URL to the project's browsable repository.
315          */
316         private void renderWebAccessSection( String scmUrl )
317         {
318             startSection( getI18nString( "webaccess.title" ) );
319 
320             if ( StringUtils.isEmpty( scmUrl ) )
321             {
322                 paragraph( getI18nString( "webaccess.nourl" ) );
323             }
324             else
325             {
326                 paragraph( getI18nString( "webaccess.url" ) );
327 
328                 verbatimLink( scmUrl, scmUrl );
329             }
330 
331             endSection();
332         }
333 
334         /**
335          * Render the anonymous access section depending the repository.
336          * <p>
337          * Note: ClearCase, Starteam et Perforce seems to have no anonymous access.
338          * </p>
339          *
340          * @param anonymousRepository the anonymous repository
341          */
342         private void renderAnonymousAccessSection( ScmRepository anonymousRepository )
343         {
344             if ( isScmSystem( anonymousRepository, "clearcase" ) || isScmSystem( anonymousRepository, "perforce" )
345                 || isScmSystem( anonymousRepository, "starteam" ) || StringUtils.isEmpty( anonymousConnection ) )
346             {
347                 return;
348             }
349 
350             startSection( getI18nString( "anonymousaccess.title" ) );
351 
352             if ( anonymousRepository != null && isScmSystem( anonymousRepository, "cvs" ) )
353             {
354                 CvsScmProviderRepository cvsRepo =
355                     (CvsScmProviderRepository) anonymousRepository.getProviderRepository();
356 
357                 anonymousAccessCVS( cvsRepo );
358             }
359             else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "git" ) )
360             {
361                 GitScmProviderRepository gitRepo =
362                     (GitScmProviderRepository) anonymousRepository.getProviderRepository();
363 
364                 anonymousAccessGit( gitRepo );
365             }
366             else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "hg" ) )
367             {
368                 HgScmProviderRepository hgRepo = (HgScmProviderRepository) anonymousRepository.getProviderRepository();
369 
370                 anonymousAccessMercurial( hgRepo );
371             }
372             else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "svn" ) )
373             {
374                 SvnScmProviderRepository svnRepo =
375                     (SvnScmProviderRepository) anonymousRepository.getProviderRepository();
376 
377                 anonymousAccessSubversion( svnRepo );
378             }
379             else
380             {
381                 paragraph( getI18nString( "anonymousaccess.general.intro" ) );
382 
383                 verbatimText( anonymousConnection.substring( 4 ) );
384             }
385 
386             endSection();
387         }
388 
389         /**
390          * Render the developer access section
391          *
392          * @param devRepository the dev repository
393          */
394         private void renderDeveloperAccessSection( ScmRepository devRepository )
395         {
396             if ( StringUtils.isEmpty( devConnection ) )
397             {
398                 return;
399             }
400 
401             startSection( getI18nString( "devaccess.title" ) );
402 
403             if ( devRepository != null && isScmSystem( devRepository, "clearcase" ) )
404             {
405                 developerAccessClearCase();
406             }
407             else if ( devRepository != null && isScmSystem( devRepository, "cvs" ) )
408             {
409                 CvsScmProviderRepository cvsRepo = (CvsScmProviderRepository) devRepository.getProviderRepository();
410 
411                 developerAccessCVS( cvsRepo );
412             }
413             else if ( devRepository != null && isScmSystem( devRepository, "git" ) )
414             {
415                 GitScmProviderRepository gitRepo = (GitScmProviderRepository) devRepository.getProviderRepository();
416 
417                 developerAccessGit( gitRepo );
418             }
419             else if ( devRepository != null && isScmSystem( devRepository, "hg" ) )
420             {
421                 HgScmProviderRepository hgRepo = (HgScmProviderRepository) devRepository.getProviderRepository();
422 
423                 developerAccessMercurial( hgRepo );
424             }
425             else if ( devRepository != null && isScmSystem( devRepository, "perforce" ) )
426             {
427                 PerforceScmProviderRepository perforceRepo =
428                     (PerforceScmProviderRepository) devRepository.getProviderRepository();
429 
430                 developerAccessPerforce( perforceRepo );
431             }
432             else if ( devRepository != null && isScmSystem( devRepository, "starteam" ) )
433             {
434                 StarteamScmProviderRepository starteamRepo =
435                     (StarteamScmProviderRepository) devRepository.getProviderRepository();
436 
437                 developerAccessStarteam( starteamRepo );
438             }
439             else if ( devRepository != null && isScmSystem( devRepository, "svn" ) )
440             {
441                 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
442 
443                 developerAccessSubversion( svnRepo );
444             }
445             else
446             {
447                 paragraph( getI18nString( "devaccess.general.intro" ) );
448 
449                 verbatimText( devConnection.substring( 4 ) );
450             }
451 
452             endSection();
453         }
454 
455         /**
456          * Render the access from behind a firewall section
457          *
458          * @param devRepository the dev repository
459          */
460         private void renderAccessBehindFirewallSection( ScmRepository devRepository )
461         {
462             startSection( getI18nString( "accessbehindfirewall.title" ) );
463 
464             if ( devRepository != null && isScmSystem( devRepository, "svn" ) )
465             {
466                 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
467 
468                 paragraph( getI18nString( "accessbehindfirewall.svn.intro" ) );
469 
470                 verbatimText( "$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName );
471             }
472             else if ( devRepository != null && isScmSystem( devRepository, "cvs" ) )
473             {
474                 linkPatternedText( getI18nString( "accessbehindfirewall.cvs.intro" ) );
475             }
476             else
477             {
478                 paragraph( getI18nString( "accessbehindfirewall.general.intro" ) );
479             }
480 
481             endSection();
482         }
483 
484         /**
485          * Render the access from behind a firewall section
486          *
487          * @param anonymousRepository the anonymous repository
488          * @param devRepository the dev repository
489          */
490         private void renderAccessThroughProxySection( ScmRepository anonymousRepository, ScmRepository devRepository )
491         {
492             if ( isScmSystem( anonymousRepository, "svn" ) || isScmSystem( devRepository, "svn" ) )
493             {
494                 startSection( getI18nString( "accessthroughtproxy.title" ) );
495 
496                 paragraph( getI18nString( "accessthroughtproxy.svn.intro1" ) );
497                 paragraph( getI18nString( "accessthroughtproxy.svn.intro2" ) );
498                 paragraph( getI18nString( "accessthroughtproxy.svn.intro3" ) );
499 
500                 verbatimText( "[global]" + SystemUtils.LINE_SEPARATOR + "http-proxy-host = your.proxy.name"
501                     + SystemUtils.LINE_SEPARATOR + "http-proxy-port = 3128" + SystemUtils.LINE_SEPARATOR );
502 
503                 endSection();
504             }
505         }
506 
507         // Clearcase
508 
509         /**
510          * Create the documentation to provide an developer access with a <code>Clearcase</code> SCM. For example,
511          * generate the following command line:
512          * <p>
513          * cleartool checkout module
514          * </p>
515          */
516         private void developerAccessClearCase()
517         {
518             paragraph( getI18nString( "devaccess.clearcase.intro" ) );
519 
520             verbatimText( "$ cleartool checkout " );
521         }
522 
523         // CVS
524 
525         // CHECKSTYLE_OFF: LineLength
526         /**
527          * Create the documentation to provide an anonymous access with a <code>CVS</code> SCM. For example, generate
528          * the following command line:
529          * <p>
530          * cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
531          * </p>
532          * <p>
533          * cvs -z3 -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic co maven-plugins/dist
534          * </p>
535          *
536          * @param cvsRepo
537          * @see <a
538          *      href="https://www.cvshome.org/docs/manual/cvs-1.12.12/cvs_16.html#SEC115">https://www.cvshome.org/docs/manual/cvs-1.12.12/cvs_16.html#SEC115</a>
539          */
540         // CHECKSTYLE_ON: LineLength
541         private void anonymousAccessCVS( CvsScmProviderRepository cvsRepo )
542         {
543             paragraph( getI18nString( "anonymousaccess.cvs.intro" ) );
544 
545             verbatimText( "$ cvs -d " + cvsRepo.getCvsRoot() + " login" + SystemUtils.LINE_SEPARATOR + "$ cvs -z3 -d "
546                 + cvsRepo.getCvsRoot() + " co " + cvsRepo.getModule() );
547         }
548 
549         // Git
550 
551         private void gitClone( String url )
552         {
553             int index = url.indexOf( ".git/" );
554             if ( index > 0 )
555             {
556                 log.warn( "Wrong effective scm url " + url + ": removing " + url.substring( index + 4 )
557                     + " in report, but this should be configured in pom.xml." );
558 
559                 url = url.substring( 0, index + 4 );
560             }
561 
562             boolean head = StringUtils.isEmpty( scmTag ) || "HEAD".equals( scmTag );
563             verbatimText( "$ git clone " + ( head ? "" : ( "--branch " + scmTag + ' ' ) ) + url );
564         }
565 
566         /**
567          * Create the documentation to provide an anonymous access with a <code>Git</code> SCM. For example, generate
568          * the following command line:
569          * <p>
570          * git clone uri
571          * </p>
572          *
573          * @param gitRepo
574          */
575         private void anonymousAccessGit( GitScmProviderRepository gitRepo )
576         {
577             sink.paragraph();
578             linkPatternedText( getI18nString( "anonymousaccess.git.intro" ) );
579             sink.paragraph_();
580 
581             gitClone( gitRepo.getFetchUrl() );
582         }
583 
584         // Mercurial
585 
586         /**
587          * Create the documentation to provide an anonymous access with a <code>Mercurial</code> SCM. For example,
588          * generate the following command line:
589          * <p>
590          * hg clone uri
591          * </p>
592          *
593          * @param hgRepo
594          */
595         private void anonymousAccessMercurial( HgScmProviderRepository hgRepo )
596         {
597             sink.paragraph();
598             linkPatternedText( getI18nString( "anonymousaccess.hg.intro" ) );
599             sink.paragraph_();
600 
601             verbatimText( "$ hg clone " + hgRepo.getURI() );
602         }
603 
604         // CHECKSTYLE_OFF: LineLength
605         /**
606          * Create the documentation to provide an developer access with a <code>CVS</code> SCM. For example, generate
607          * the following command line:
608          * <p>
609          * cvs -d :pserver:username@cvs.apache.org:/home/cvs login
610          * </p>
611          * <p>
612          * cvs -z3 -d :ext:username@cvs.apache.org:/home/cvs co maven-plugins/dist
613          * </p>
614          *
615          * @param cvsRepo
616          * @see <a
617          *      href="https://www.cvshome.org/docs/manual/cvs-1.12.12/cvs_16.html#SEC115">https://www.cvshome.org/docs/manual/cvs-1.12.12/cvs_16.html#SEC115</a>
618          */
619         // CHECKSTYLE_ON: LineLength
620         private void developerAccessCVS( CvsScmProviderRepository cvsRepo )
621         {
622             paragraph( getI18nString( "devaccess.cvs.intro" ) );
623 
624             // Safety: remove the username if present
625             String cvsRoot = StringUtils.replace( cvsRepo.getCvsRoot(), cvsRepo.getUser(), "username" );
626 
627             verbatimText( "$ cvs -d " + cvsRoot + " login" + SystemUtils.LINE_SEPARATOR + "$ cvs -z3 -d " + cvsRoot
628                 + " co " + cvsRepo.getModule() );
629         }
630 
631         // Git
632 
633         /**
634          * Create the documentation to provide an developer access with a <code>Git</code> SCM. For example, generate
635          * the following command line:
636          * <p>
637          * git clone repo
638          * </p>
639          *
640          * @param gitRepo
641          */
642         private void developerAccessGit( GitScmProviderRepository gitRepo )
643         {
644             sink.paragraph();
645             linkPatternedText( getI18nString( "devaccess.git.intro" ) );
646             sink.paragraph_();
647 
648             gitClone( gitRepo.getPushUrl() );
649         }
650 
651         // Mercurial
652 
653         /**
654          * Create the documentation to provide an developer access with a <code>Mercurial</code> SCM. For example,
655          * generate the following command line:
656          * <p>
657          * hg clone repo
658          * </p>
659          *
660          * @param hgRepo
661          */
662         private void developerAccessMercurial( HgScmProviderRepository hgRepo )
663         {
664             sink.paragraph();
665             linkPatternedText( getI18nString( "devaccess.hg.intro" ) );
666             sink.paragraph_();
667 
668             verbatimText( "$ hg clone " + hgRepo.getURI() );
669         }
670 
671         // Perforce
672 
673         // CHECKSTYLE_OFF: LineLength
674         /**
675          * Create the documentation to provide an developer access with a <code>Perforce</code> SCM. For example,
676          * generate the following command line:
677          * <p>
678          * p4 -H hostname -p port -u username -P password path
679          * </p>
680          * <p>
681          * p4 -H hostname -p port -u username -P password path submit -c changement
682          * </p>
683          *
684          * @param perforceRepo
685          * @see <a
686          *      href="http://www.perforce.com/perforce/doc.051/manuals/cmdref/index.html">http://www.perforce.com/
687          *      perforce
688          *      /doc.051/manuals/cmdref/index.html</>
689          */
690         // CHECKSTYLE_ON: LineLength
691         private void developerAccessPerforce( PerforceScmProviderRepository perforceRepo )
692         {
693             paragraph( getI18nString( "devaccess.perforce.intro" ) );
694 
695             StringBuilder command = new StringBuilder();
696             command.append( "$ p4" );
697             if ( !StringUtils.isEmpty( perforceRepo.getHost() ) )
698             {
699                 command.append( " -H " ).append( perforceRepo.getHost() );
700             }
701             if ( perforceRepo.getPort() > 0 )
702             {
703                 command.append( " -p " ).append( perforceRepo.getPort() );
704             }
705             command.append( " -u username" );
706             command.append( " -P password" );
707             command.append( " " );
708             command.append( perforceRepo.getPath() );
709             command.append( SystemUtils.LINE_SEPARATOR );
710             command.append( "$ p4 submit -c \"A comment\"" );
711 
712             verbatimText( command.toString() );
713         }
714 
715         // Starteam
716 
717         /**
718          * Create the documentation to provide an developer access with a <code>Starteam</code> SCM. For example,
719          * generate the following command line:
720          * <p>
721          * stcmd co -x -nologo -stop -p myusername:mypassword@myhost:1234/projecturl -is
722          * </p>
723          * <p>
724          * stcmd ci -x -nologo -stop -p myusername:mypassword@myhost:1234/projecturl -f NCI -is
725          * </p>
726          *
727          * @param starteamRepo
728          */
729         private void developerAccessStarteam( StarteamScmProviderRepository starteamRepo )
730         {
731             paragraph( getI18nString( "devaccess.starteam.intro" ) );
732 
733             StringBuilder command = new StringBuilder();
734 
735             // Safety: remove the username/password if present
736             String fullUrl = StringUtils.replace( starteamRepo.getFullUrl(), starteamRepo.getUser(), "username" );
737             fullUrl = StringUtils.replace( fullUrl, starteamRepo.getPassword(), "password" );
738 
739             command.append( "$ stcmd co -x -nologo -stop -p " );
740             command.append( fullUrl );
741             command.append( " -is" );
742             command.append( SystemUtils.LINE_SEPARATOR );
743             command.append( "$ stcmd ci -x -nologo -stop -p " );
744             command.append( fullUrl );
745             command.append( " -f NCI -is" );
746 
747             verbatimText( command.toString() );
748         }
749 
750         // Subversion
751 
752         /**
753          * Create the documentation to provide an anonymous access with a <code>Subversion</code>
754          * SCM. For example, generate the following command line:
755          * <p>
756          * svn checkout http://svn.apache.org/repos/asf/maven/components/trunk maven
757          * </p>
758          *
759          * @param svnRepo
760          * @see <a href="http://svnbook.red-bean.com/">http://svnbook.red-bean.com/</a>
761          */
762         private void anonymousAccessSubversion( SvnScmProviderRepository svnRepo )
763         {
764             paragraph( getI18nString( "anonymousaccess.svn.intro" ) );
765 
766             verbatimText( "$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName );
767         }
768 
769         /**
770          * Create the documentation to provide an developer access with a <code>Subversion</code>
771          * SCM. For example, generate the following command line:
772          * <p>
773          * svn checkout https://svn.apache.org/repos/asf/maven/components/trunk maven
774          * </p>
775          * <p>
776          * svn commit --username your-username -m "A message"
777          * </p>
778          *
779          * @param svnRepo
780          * @see <a href="http://svnbook.red-bean.com/">http://svnbook.red-bean.com/</a>
781          */
782         private void developerAccessSubversion( SvnScmProviderRepository svnRepo )
783         {
784             if ( svnRepo.getUrl() != null )
785             {
786                 if ( svnRepo.getUrl().startsWith( "https://" ) )
787                 {
788                     paragraph( getI18nString( "devaccess.svn.intro1.https" ) );
789                 }
790                 else if ( svnRepo.getUrl().startsWith( "svn://" ) )
791                 {
792                     paragraph( getI18nString( "devaccess.svn.intro1.svn" ) );
793                 }
794                 else if ( svnRepo.getUrl().startsWith( "svn+ssh://" ) )
795                 {
796                     paragraph( getI18nString( "devaccess.svn.intro1.svnssh" ) );
797                 }
798                 else
799                 {
800                     paragraph( getI18nString( "devaccess.svn.intro1.other" ) );
801                 }
802             }
803 
804             StringBuilder sb = new StringBuilder();
805 
806             sb.append( "$ svn checkout " ).append( svnRepo.getUrl() ).append( " " ).append( checkoutDirectoryName );
807 
808             verbatimText( sb.toString() );
809 
810             paragraph( getI18nString( "devaccess.svn.intro2" ) );
811 
812             sb = new StringBuilder();
813             sb.append( "$ svn commit --username your-username -m \"A message\"" );
814 
815             verbatimText( sb.toString() );
816         }
817 
818         /**
819          * Return a <code>SCM repository</code> defined by a given url
820          *
821          * @param scmUrl an SCM URL
822          * @return a valid SCM repository or null
823          */
824         public ScmRepository getScmRepository( String scmUrl )
825         {
826             if ( StringUtils.isEmpty( scmUrl ) )
827             {
828                 return null;
829             }
830 
831             ScmRepository repo = null;
832             List<String> messages = new ArrayList<String>();
833             try
834             {
835                 messages.addAll( scmManager.validateScmRepository( scmUrl ) );
836             }
837             catch ( Exception e )
838             {
839                 messages.add( e.getMessage() );
840             }
841 
842             if ( messages.size() > 0 )
843             {
844                 StringBuilder sb = new StringBuilder();
845                 boolean isIntroAdded = false;
846                 for ( String msg : messages )
847                 {
848                     // Ignore NoSuchScmProviderException msg
849                     // See impl of AbstractScmManager#validateScmRepository()
850                     if ( msg.startsWith( "No such provider" ) )
851                     {
852                         continue;
853                     }
854 
855                     if ( !isIntroAdded )
856                     {
857                         sb.append( "This SCM url '" );
858                         sb.append( scmUrl );
859                         sb.append( "' is invalid due to the following errors:" );
860                         sb.append( SystemUtils.LINE_SEPARATOR );
861                         isIntroAdded = true;
862                     }
863                     sb.append( " * " );
864                     sb.append( msg );
865                     sb.append( SystemUtils.LINE_SEPARATOR );
866                 }
867 
868                 if ( StringUtils.isNotEmpty( sb.toString() ) )
869                 {
870                     sb.append( "For more information about SCM URL Format, please refer to: "
871                         + "http://maven.apache.org/scm/scm-url-format.html" );
872 
873                     throw new IllegalArgumentException( sb.toString() );
874                 }
875             }
876 
877             try
878             {
879                 repo = scmManager.makeScmRepository( scmUrl );
880             }
881             catch ( NoSuchScmProviderException e )
882             {
883                 if ( log.isDebugEnabled() )
884                 {
885                     log.debug( e.getMessage(), e );
886                 }
887             }
888             catch ( ScmRepositoryException e )
889             {
890                 if ( log.isDebugEnabled() )
891                 {
892                     log.debug( e.getMessage(), e );
893                 }
894             }
895             catch ( Exception e )
896             {
897                 // Should be already catched
898                 if ( log.isDebugEnabled() )
899                 {
900                     log.debug( e.getMessage(), e );
901                 }
902             }
903 
904             return repo;
905         }
906 
907         /**
908          * Convenience method that return true is the defined <code>SCM repository</code> is a known provider.
909          * <p>
910          * Currently, we fully support ClearCase, CVS, Git, Perforce, Mercurial, Starteam and Subversion
911          * by the maven-scm-providers component.
912          * </p>
913          *
914          * @param scmRepository a SCM repository
915          * @param scmProvider a SCM provider name
916          * @return true if the provider of the given SCM repository is equal to the given scm provider.
917          * @see <a href="http://svn.apache.org/repos/asf/maven/scm/trunk/maven-scm-providers/">maven-scm-providers</a>
918          */
919         private static boolean isScmSystem( ScmRepository scmRepository, String scmProvider )
920         {
921             if ( StringUtils.isEmpty( scmProvider ) )
922             {
923                 return false;
924             }
925 
926             if ( scmRepository != null && scmProvider.equalsIgnoreCase( scmRepository.getProvider() ) )
927             {
928                 return true;
929             }
930 
931             return false;
932         }
933     }
934 }