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 964486 2015-09-05 21:32:50Z hboutemy $
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             // in the future, git scm url should support both repository + path: at the moment, require a hack
554             // to remove path added to repository
555             int index = url.indexOf( ".git/" );
556             if ( index > 0 )
557             {
558                 url = url.substring( 0, index + 4 );
559             }
560 
561             boolean head = StringUtils.isEmpty( scmTag ) || "HEAD".equals( scmTag );
562             verbatimText( "$ git clone " + ( head ? "" : ( "--branch " + scmTag + ' ' ) ) + url );
563         }
564 
565         /**
566          * Create the documentation to provide an anonymous access with a <code>Git</code> SCM. For example, generate
567          * the following command line:
568          * <p>
569          * git clone uri
570          * </p>
571          *
572          * @param gitRepo
573          */
574         private void anonymousAccessGit( GitScmProviderRepository gitRepo )
575         {
576             sink.paragraph();
577             linkPatternedText( getI18nString( "anonymousaccess.git.intro" ) );
578             sink.paragraph_();
579 
580             gitClone( gitRepo.getFetchUrl() );
581         }
582 
583         // Mercurial
584 
585         /**
586          * Create the documentation to provide an anonymous access with a <code>Mercurial</code> SCM. For example,
587          * generate the following command line:
588          * <p>
589          * hg clone uri
590          * </p>
591          *
592          * @param hgRepo
593          */
594         private void anonymousAccessMercurial( HgScmProviderRepository hgRepo )
595         {
596             sink.paragraph();
597             linkPatternedText( getI18nString( "anonymousaccess.hg.intro" ) );
598             sink.paragraph_();
599 
600             verbatimText( "$ hg clone " + hgRepo.getURI() );
601         }
602 
603         // CHECKSTYLE_OFF: LineLength
604         /**
605          * Create the documentation to provide an developer access with a <code>CVS</code> SCM. For example, generate
606          * the following command line:
607          * <p>
608          * cvs -d :pserver:username@cvs.apache.org:/home/cvs login
609          * </p>
610          * <p>
611          * cvs -z3 -d :ext:username@cvs.apache.org:/home/cvs co maven-plugins/dist
612          * </p>
613          *
614          * @param cvsRepo
615          * @see <a
616          *      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>
617          */
618         // CHECKSTYLE_ON: LineLength
619         private void developerAccessCVS( CvsScmProviderRepository cvsRepo )
620         {
621             paragraph( getI18nString( "devaccess.cvs.intro" ) );
622 
623             // Safety: remove the username if present
624             String cvsRoot = StringUtils.replace( cvsRepo.getCvsRoot(), cvsRepo.getUser(), "username" );
625 
626             verbatimText( "$ cvs -d " + cvsRoot + " login" + SystemUtils.LINE_SEPARATOR + "$ cvs -z3 -d " + cvsRoot
627                 + " co " + cvsRepo.getModule() );
628         }
629 
630         // Git
631 
632         /**
633          * Create the documentation to provide an developer access with a <code>Git</code> SCM. For example, generate
634          * the following command line:
635          * <p>
636          * git clone repo
637          * </p>
638          *
639          * @param gitRepo
640          */
641         private void developerAccessGit( GitScmProviderRepository gitRepo )
642         {
643             sink.paragraph();
644             linkPatternedText( getI18nString( "devaccess.git.intro" ) );
645             sink.paragraph_();
646 
647             gitClone( gitRepo.getPushUrl() );
648         }
649 
650         // Mercurial
651 
652         /**
653          * Create the documentation to provide an developer access with a <code>Mercurial</code> SCM. For example,
654          * generate the following command line:
655          * <p>
656          * hg clone repo
657          * </p>
658          *
659          * @param hgRepo
660          */
661         private void developerAccessMercurial( HgScmProviderRepository hgRepo )
662         {
663             sink.paragraph();
664             linkPatternedText( getI18nString( "devaccess.hg.intro" ) );
665             sink.paragraph_();
666 
667             verbatimText( "$ hg clone " + hgRepo.getURI() );
668         }
669 
670         // Perforce
671 
672         // CHECKSTYLE_OFF: LineLength
673         /**
674          * Create the documentation to provide an developer access with a <code>Perforce</code> SCM. For example,
675          * generate the following command line:
676          * <p>
677          * p4 -H hostname -p port -u username -P password path
678          * </p>
679          * <p>
680          * p4 -H hostname -p port -u username -P password path submit -c changement
681          * </p>
682          *
683          * @param perforceRepo
684          * @see <a
685          *      href="http://www.perforce.com/perforce/doc.051/manuals/cmdref/index.html">http://www.perforce.com/
686          *      perforce
687          *      /doc.051/manuals/cmdref/index.html</>
688          */
689         // CHECKSTYLE_ON: LineLength
690         private void developerAccessPerforce( PerforceScmProviderRepository perforceRepo )
691         {
692             paragraph( getI18nString( "devaccess.perforce.intro" ) );
693 
694             StringBuilder command = new StringBuilder();
695             command.append( "$ p4" );
696             if ( !StringUtils.isEmpty( perforceRepo.getHost() ) )
697             {
698                 command.append( " -H " ).append( perforceRepo.getHost() );
699             }
700             if ( perforceRepo.getPort() > 0 )
701             {
702                 command.append( " -p " ).append( perforceRepo.getPort() );
703             }
704             command.append( " -u username" );
705             command.append( " -P password" );
706             command.append( " " );
707             command.append( perforceRepo.getPath() );
708             command.append( SystemUtils.LINE_SEPARATOR );
709             command.append( "$ p4 submit -c \"A comment\"" );
710 
711             verbatimText( command.toString() );
712         }
713 
714         // Starteam
715 
716         /**
717          * Create the documentation to provide an developer access with a <code>Starteam</code> SCM. For example,
718          * generate the following command line:
719          * <p>
720          * stcmd co -x -nologo -stop -p myusername:mypassword@myhost:1234/projecturl -is
721          * </p>
722          * <p>
723          * stcmd ci -x -nologo -stop -p myusername:mypassword@myhost:1234/projecturl -f NCI -is
724          * </p>
725          *
726          * @param starteamRepo
727          */
728         private void developerAccessStarteam( StarteamScmProviderRepository starteamRepo )
729         {
730             paragraph( getI18nString( "devaccess.starteam.intro" ) );
731 
732             StringBuilder command = new StringBuilder();
733 
734             // Safety: remove the username/password if present
735             String fullUrl = StringUtils.replace( starteamRepo.getFullUrl(), starteamRepo.getUser(), "username" );
736             fullUrl = StringUtils.replace( fullUrl, starteamRepo.getPassword(), "password" );
737 
738             command.append( "$ stcmd co -x -nologo -stop -p " );
739             command.append( fullUrl );
740             command.append( " -is" );
741             command.append( SystemUtils.LINE_SEPARATOR );
742             command.append( "$ stcmd ci -x -nologo -stop -p " );
743             command.append( fullUrl );
744             command.append( " -f NCI -is" );
745 
746             verbatimText( command.toString() );
747         }
748 
749         // Subversion
750 
751         /**
752          * Create the documentation to provide an anonymous access with a <code>Subversion</code>
753          * SCM. For example, generate the following command line:
754          * <p>
755          * svn checkout http://svn.apache.org/repos/asf/maven/components/trunk maven
756          * </p>
757          *
758          * @param svnRepo
759          * @see <a href="http://svnbook.red-bean.com/">http://svnbook.red-bean.com/</a>
760          */
761         private void anonymousAccessSubversion( SvnScmProviderRepository svnRepo )
762         {
763             paragraph( getI18nString( "anonymousaccess.svn.intro" ) );
764 
765             verbatimText( "$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName );
766         }
767 
768         /**
769          * Create the documentation to provide an developer access with a <code>Subversion</code>
770          * SCM. For example, generate the following command line:
771          * <p>
772          * svn checkout https://svn.apache.org/repos/asf/maven/components/trunk maven
773          * </p>
774          * <p>
775          * svn commit --username your-username -m "A message"
776          * </p>
777          *
778          * @param svnRepo
779          * @see <a href="http://svnbook.red-bean.com/">http://svnbook.red-bean.com/</a>
780          */
781         private void developerAccessSubversion( SvnScmProviderRepository svnRepo )
782         {
783             if ( svnRepo.getUrl() != null )
784             {
785                 if ( svnRepo.getUrl().startsWith( "https://" ) )
786                 {
787                     paragraph( getI18nString( "devaccess.svn.intro1.https" ) );
788                 }
789                 else if ( svnRepo.getUrl().startsWith( "svn://" ) )
790                 {
791                     paragraph( getI18nString( "devaccess.svn.intro1.svn" ) );
792                 }
793                 else if ( svnRepo.getUrl().startsWith( "svn+ssh://" ) )
794                 {
795                     paragraph( getI18nString( "devaccess.svn.intro1.svnssh" ) );
796                 }
797                 else
798                 {
799                     paragraph( getI18nString( "devaccess.svn.intro1.other" ) );
800                 }
801             }
802 
803             StringBuilder sb = new StringBuilder();
804 
805             sb.append( "$ svn checkout " ).append( svnRepo.getUrl() ).append( " " ).append( checkoutDirectoryName );
806 
807             verbatimText( sb.toString() );
808 
809             paragraph( getI18nString( "devaccess.svn.intro2" ) );
810 
811             sb = new StringBuilder();
812             sb.append( "$ svn commit --username your-username -m \"A message\"" );
813 
814             verbatimText( sb.toString() );
815         }
816 
817         /**
818          * Return a <code>SCM repository</code> defined by a given url
819          *
820          * @param scmUrl an SCM URL
821          * @return a valid SCM repository or null
822          */
823         public ScmRepository getScmRepository( String scmUrl )
824         {
825             if ( StringUtils.isEmpty( scmUrl ) )
826             {
827                 return null;
828             }
829 
830             ScmRepository repo = null;
831             List<String> messages = new ArrayList<String>();
832             try
833             {
834                 messages.addAll( scmManager.validateScmRepository( scmUrl ) );
835             }
836             catch ( Exception e )
837             {
838                 messages.add( e.getMessage() );
839             }
840 
841             if ( messages.size() > 0 )
842             {
843                 StringBuilder sb = new StringBuilder();
844                 boolean isIntroAdded = false;
845                 for ( String msg : messages )
846                 {
847                     // Ignore NoSuchScmProviderException msg
848                     // See impl of AbstractScmManager#validateScmRepository()
849                     if ( msg.startsWith( "No such provider" ) )
850                     {
851                         continue;
852                     }
853 
854                     if ( !isIntroAdded )
855                     {
856                         sb.append( "This SCM url '" );
857                         sb.append( scmUrl );
858                         sb.append( "' is invalid due to the following errors:" );
859                         sb.append( SystemUtils.LINE_SEPARATOR );
860                         isIntroAdded = true;
861                     }
862                     sb.append( " * " );
863                     sb.append( msg );
864                     sb.append( SystemUtils.LINE_SEPARATOR );
865                 }
866 
867                 if ( StringUtils.isNotEmpty( sb.toString() ) )
868                 {
869                     sb.append( "For more information about SCM URL Format, please refer to: "
870                         + "http://maven.apache.org/scm/scm-url-format.html" );
871 
872                     throw new IllegalArgumentException( sb.toString() );
873                 }
874             }
875 
876             try
877             {
878                 repo = scmManager.makeScmRepository( scmUrl );
879             }
880             catch ( NoSuchScmProviderException e )
881             {
882                 if ( log.isDebugEnabled() )
883                 {
884                     log.debug( e.getMessage(), e );
885                 }
886             }
887             catch ( ScmRepositoryException e )
888             {
889                 if ( log.isDebugEnabled() )
890                 {
891                     log.debug( e.getMessage(), e );
892                 }
893             }
894             catch ( Exception e )
895             {
896                 // Should be already catched
897                 if ( log.isDebugEnabled() )
898                 {
899                     log.debug( e.getMessage(), e );
900                 }
901             }
902 
903             return repo;
904         }
905 
906         /**
907          * Convenience method that return true is the defined <code>SCM repository</code> is a known provider.
908          * <p>
909          * Currently, we fully support ClearCase, CVS, Git, Perforce, Mercurial, Starteam and Subversion
910          * by the maven-scm-providers component.
911          * </p>
912          *
913          * @param scmRepository a SCM repository
914          * @param scmProvider a SCM provider name
915          * @return true if the provider of the given SCM repository is equal to the given scm provider.
916          * @see <a href="http://svn.apache.org/repos/asf/maven/scm/trunk/maven-scm-providers/">maven-scm-providers</a>
917          */
918         private static boolean isScmSystem( ScmRepository scmRepository, String scmProvider )
919         {
920             if ( StringUtils.isEmpty( scmProvider ) )
921             {
922                 return false;
923             }
924 
925             if ( scmRepository != null && scmProvider.equalsIgnoreCase( scmRepository.getProvider() ) )
926             {
927                 return true;
928             }
929 
930             return false;
931         }
932     }
933 }