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