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