1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
45
46
47
48
49 @Mojo(name = "scm")
50 public class ScmReport extends AbstractProjectInfoReport {
51
52
53
54
55
56
57
58 @Component
59 protected ScmManager scmManager;
60
61
62
63
64 @Parameter(defaultValue = "${project.artifactId}")
65 private String checkoutDirectoryName;
66
67
68
69
70
71
72
73 @Parameter(defaultValue = "${project.scm.connection}")
74 private String anonymousConnection;
75
76
77
78
79
80
81
82 @Parameter(defaultValue = "${project.scm.developerConnection}")
83 private String developerConnection;
84
85
86
87
88
89
90 @Parameter(defaultValue = "${project.scm.url}")
91 private String webAccessUrl;
92
93
94
95
96
97
98 @Parameter(defaultValue = "${project.scm.tag}")
99 private String scmTag;
100
101
102
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
142 public String getOutputName() {
143 return "scm";
144 }
145
146 @Override
147 protected String getI18Nsection() {
148 return "scm";
149 }
150
151
152
153
154
155
156
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
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
236 renderOverviewSection(anonymousRepository, devRepository);
237
238
239 renderWebAccessSection(webAccessUrl);
240
241
242 renderAnonymousAccessSection(anonymousRepository);
243
244
245 renderDeveloperAccessSection(devRepository);
246
247
248 renderAccessBehindFirewallSection(devRepository);
249
250
251 renderAccessThroughProxySection(anonymousRepository, devRepository);
252 }
253
254
255
256
257
258
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
300
301
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
319
320
321
322
323
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
365
366
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
414
415
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
437
438
439
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
457
458
459
460
461
462
463
464
465 private void developerAccessClearCase() {
466 paragraph(getI18nString("devaccess.clearcase.intro"));
467
468 verbatimText("$ cleartool checkout ");
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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
497
498 private void gitClone(String url) {
499
500
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
512
513
514
515
516
517
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
528
529
530
531
532
533
534
535
536
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
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 private void developerAccessCVS(CvsScmProviderRepository cvsRepo) {
563 paragraph(getI18nString("devaccess.cvs.intro"));
564
565
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
573
574
575
576
577
578
579
580
581
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
592
593
594
595
596
597
598
599
600
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
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
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
652
653
654
655
656
657
658
659
660
661
662
663
664
665 private void developerAccessStarteam(StarteamScmProviderRepository starteamRepo) {
666 paragraph(getI18nString("devaccess.starteam.intro"));
667
668 StringBuilder command = new StringBuilder();
669
670
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
686
687
688
689
690
691
692
693
694
695
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
705
706
707
708
709
710
711
712
713
714
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
745
746
747
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
767
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
796 if (log.isDebugEnabled()) {
797 log.debug(e.getMessage(), e);
798 }
799 }
800
801 return repo;
802 }
803
804
805
806
807
808
809
810
811
812
813
814
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 }