1 package org.apache.maven.report.projectinfo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
46
47
48
49
50 @Mojo( name = "scm" )
51 public class ScmReport
52 extends AbstractProjectInfoReport
53 {
54
55
56
57
58
59
60
61 @Component
62 protected ScmManager scmManager;
63
64
65
66
67 @Parameter( defaultValue = "${project.artifactId}" )
68 private String checkoutDirectoryName;
69
70
71
72
73
74
75
76 @Parameter( defaultValue = "${project.scm.connection}" )
77 private String anonymousConnection;
78
79
80
81
82
83
84
85 @Parameter( defaultValue = "${project.scm.developerConnection}" )
86 private String developerConnection;
87
88
89
90
91
92
93 @Parameter( defaultValue = "${project.scm.url}" )
94 private String webAccessUrl;
95
96
97
98
99
100
101 @Parameter( defaultValue = "${project.scm.tag}" )
102 private String scmTag;
103
104
105
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
139 public String getOutputName()
140 {
141 return "scm";
142 }
143
144 @Override
145 protected String getI18Nsection()
146 {
147 return "scm";
148 }
149
150
151
152
153
154
155
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
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
231 renderOverviewSection( anonymousRepository, devRepository );
232
233
234 renderWebAccessSection( webAccessUrl );
235
236
237 renderAnonymousAccessSection( anonymousRepository );
238
239
240 renderDeveloperAccessSection( devRepository );
241
242
243 renderAccessBehindFirewallSection( devRepository );
244
245
246 renderAccessThroughProxySection( anonymousRepository, devRepository );
247 }
248
249
250
251
252
253
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
311
312
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
334
335
336
337
338
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
389
390
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
455
456
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
484
485
486
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
506
507
508
509
510
511
512
513
514 private void developerAccessClearCase()
515 {
516 paragraph( getI18nString( "devaccess.clearcase.intro" ) );
517
518 verbatimText( "$ cleartool checkout " );
519 }
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
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
548
549 private void gitClone( String url )
550 {
551
552
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
565
566
567
568
569
570
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
582
583
584
585
586
587
588
589
590
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
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 private void developerAccessCVS( CvsScmProviderRepository cvsRepo )
618 {
619 paragraph( getI18nString( "devaccess.cvs.intro" ) );
620
621
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
629
630
631
632
633
634
635
636
637
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
649
650
651
652
653
654
655
656
657
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
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
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
713
714
715
716
717
718
719
720
721
722
723
724
725
726 private void developerAccessStarteam( StarteamScmProviderRepository starteamRepo )
727 {
728 paragraph( getI18nString( "devaccess.starteam.intro" ) );
729
730 StringBuilder command = new StringBuilder();
731
732
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
748
749
750
751
752
753
754
755
756
757
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
768
769
770
771
772
773
774
775
776
777
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
817
818
819
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
846
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
881 if ( log.isDebugEnabled() )
882 {
883 log.debug( e.getMessage(), e );
884 }
885 }
886
887 return repo;
888 }
889
890
891
892
893
894
895
896
897
898
899
900
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 }