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.git.repository.GitScmProviderRepository;
34 import org.apache.maven.scm.provider.hg.repository.HgScmProviderRepository;
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
41
42
43
44
45
46 @Mojo(name = "scm")
47 public class ScmReport extends AbstractProjectInfoReport {
48
49
50
51
52
53
54
55 @Component
56 protected ScmManager scmManager;
57
58
59
60
61 @Parameter(defaultValue = "${project.artifactId}")
62 private String checkoutDirectoryName;
63
64
65
66
67
68
69
70 @Parameter(defaultValue = "${project.scm.connection}")
71 private String anonymousConnection;
72
73
74
75
76
77
78
79 @Parameter(defaultValue = "${project.scm.developerConnection}")
80 private String developerConnection;
81
82
83
84
85
86
87 @Parameter(defaultValue = "${project.scm.url}")
88 private String webAccessUrl;
89
90
91
92
93
94
95 @Parameter(defaultValue = "${project.scm.tag}")
96 private String scmTag;
97
98
99
100
101
102 @Override
103 public boolean canGenerateReport() {
104 boolean result = super.canGenerateReport();
105 if (result && skipEmptyReport) {
106 Scm scm = getProject().getModel().getScm();
107 result = scm != null;
108
109 if (result
110 && (anonymousConnection == null || anonymousConnection.isEmpty())
111 && (developerConnection == null || developerConnection.isEmpty())
112 && StringUtils.isEmpty(scm.getUrl())) {
113 result = false;
114 }
115 }
116
117 return result;
118 }
119
120 @Override
121 public void executeReport(Locale locale) {
122 ScmRenderer r = new ScmRenderer(
123 getLog(),
124 scmManager,
125 getSink(),
126 getProject().getModel(),
127 getI18N(locale),
128 locale,
129 checkoutDirectoryName,
130 webAccessUrl,
131 anonymousConnection,
132 developerConnection,
133 scmTag);
134
135 r.render();
136 }
137
138
139 public String getOutputName() {
140 return "scm";
141 }
142
143 @Override
144 protected String getI18Nsection() {
145 return "scm";
146 }
147
148
149
150
151
152
153
154
155 private static class ScmRenderer extends AbstractProjectInfoRenderer {
156 private static final String LS = System.lineSeparator();
157
158 private Log log;
159
160 private Model model;
161
162 private ScmManager scmManager;
163
164
165
166
167 private String anonymousConnection;
168
169 private String devConnection;
170
171 private String checkoutDirectoryName;
172
173 private String webAccessUrl;
174
175 private String scmTag;
176
177 ScmRenderer(
178 Log log,
179 ScmManager scmManager,
180 Sink sink,
181 Model model,
182 I18N i18n,
183 Locale locale,
184 String checkoutDirName,
185 String webAccessUrl,
186 String anonymousConnection,
187 String devConnection,
188 String scmTag) {
189 super(sink, i18n, locale);
190
191 this.log = log;
192
193 this.scmManager = scmManager;
194
195 this.model = model;
196
197 this.checkoutDirectoryName = checkoutDirName;
198
199 this.webAccessUrl = webAccessUrl;
200
201 this.anonymousConnection = anonymousConnection;
202
203 this.devConnection = devConnection;
204
205 this.scmTag = scmTag;
206 }
207
208 @Override
209 protected String getI18Nsection() {
210 return "scm";
211 }
212
213 @Override
214 protected void renderBody() {
215 Scm scm = model.getScm();
216 if (scm == null
217 || (anonymousConnection == null || anonymousConnection.isEmpty())
218 && (devConnection == null || devConnection.isEmpty())
219 && StringUtils.isEmpty(scm.getUrl())) {
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
233 renderOverviewSection(anonymousRepository, devRepository);
234
235
236 renderWebAccessSection(webAccessUrl);
237
238
239 renderAnonymousAccessSection(anonymousRepository);
240
241
242 renderDeveloperAccessSection(devRepository);
243
244
245 renderAccessBehindFirewallSection(devRepository);
246
247
248 renderAccessThroughProxySection(anonymousRepository, devRepository);
249 }
250
251
252
253
254
255
256
257 private void renderOverviewSection(ScmRepository anonymousRepository, ScmRepository devRepository) {
258 startSection(getI18nString("overview.title"));
259
260 if (isScmSystem(anonymousRepository, "git") || isScmSystem(devRepository, "git")) {
261 sink.paragraph();
262 linkPatternedText(getI18nString("git.intro"));
263 sink.paragraph_();
264 } else if (isScmSystem(anonymousRepository, "hg") || isScmSystem(devRepository, "hg")) {
265 sink.paragraph();
266 linkPatternedText(getI18nString("hg.intro"));
267 sink.paragraph_();
268 } else if (isScmSystem(anonymousRepository, "svn") || isScmSystem(devRepository, "svn")) {
269 sink.paragraph();
270 linkPatternedText(getI18nString("svn.intro"));
271 sink.paragraph_();
272 } else {
273 paragraph(getI18nString("general.intro"));
274 }
275
276 endSection();
277 }
278
279
280
281
282
283
284 private void renderWebAccessSection(String scmUrl) {
285 startSection(getI18nString("webaccess.title"));
286
287 if (scmUrl == null || scmUrl.isEmpty()) {
288 paragraph(getI18nString("webaccess.nourl"));
289 } else {
290 paragraph(getI18nString("webaccess.url"));
291
292 verbatimLink(scmUrl, scmUrl);
293 }
294
295 endSection();
296 }
297
298
299
300
301
302
303
304
305
306 private void renderAnonymousAccessSection(ScmRepository anonymousRepository) {
307 if (anonymousConnection == null || anonymousConnection.isEmpty()) {
308 return;
309 }
310
311 startSection(getI18nString("anonymousaccess.title"));
312
313 if (anonymousRepository != null && isScmSystem(anonymousRepository, "git")) {
314 GitScmProviderRepository gitRepo =
315 (GitScmProviderRepository) anonymousRepository.getProviderRepository();
316
317 anonymousAccessGit(gitRepo);
318 } else if (anonymousRepository != null && isScmSystem(anonymousRepository, "hg")) {
319 HgScmProviderRepository hgRepo = (HgScmProviderRepository) anonymousRepository.getProviderRepository();
320
321 anonymousAccessMercurial(hgRepo);
322 } else if (anonymousRepository != null && isScmSystem(anonymousRepository, "svn")) {
323 SvnScmProviderRepository svnRepo =
324 (SvnScmProviderRepository) anonymousRepository.getProviderRepository();
325
326 anonymousAccessSubversion(svnRepo);
327 } else {
328 paragraph(getI18nString("anonymousaccess.general.intro"));
329
330 verbatimText(anonymousConnection.substring(4));
331 }
332
333 endSection();
334 }
335
336
337
338
339
340
341 private void renderDeveloperAccessSection(ScmRepository devRepository) {
342 if (devConnection == null || devConnection.isEmpty()) {
343 return;
344 }
345
346 startSection(getI18nString("devaccess.title"));
347
348 if (devRepository != null && isScmSystem(devRepository, "git")) {
349 GitScmProviderRepository gitRepo = (GitScmProviderRepository) devRepository.getProviderRepository();
350
351 developerAccessGit(gitRepo);
352 } else if (devRepository != null && isScmSystem(devRepository, "hg")) {
353 HgScmProviderRepository hgRepo = (HgScmProviderRepository) devRepository.getProviderRepository();
354
355 developerAccessMercurial(hgRepo);
356 } else if (devRepository != null && isScmSystem(devRepository, "svn")) {
357 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
358
359 developerAccessSubversion(svnRepo);
360 } else {
361 paragraph(getI18nString("devaccess.general.intro"));
362
363 verbatimText(devConnection.substring(4));
364 }
365
366 endSection();
367 }
368
369
370
371
372
373
374 private void renderAccessBehindFirewallSection(ScmRepository devRepository) {
375 startSection(getI18nString("accessbehindfirewall.title"));
376
377 if (devRepository != null && isScmSystem(devRepository, "svn")) {
378 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
379
380 paragraph(getI18nString("accessbehindfirewall.svn.intro"));
381
382 verbatimText("$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName);
383 } else {
384 paragraph(getI18nString("accessbehindfirewall.general.intro"));
385 }
386
387 endSection();
388 }
389
390
391
392
393
394
395
396 private void renderAccessThroughProxySection(ScmRepository anonymousRepository, ScmRepository devRepository) {
397 if (isScmSystem(anonymousRepository, "svn") || isScmSystem(devRepository, "svn")) {
398 startSection(getI18nString("accessthroughtproxy.title"));
399
400 paragraph(getI18nString("accessthroughtproxy.svn.intro1"));
401 paragraph(getI18nString("accessthroughtproxy.svn.intro2"));
402 paragraph(getI18nString("accessthroughtproxy.svn.intro3"));
403
404 verbatimText(
405 "[global]" + LS + "http-proxy-host = your.proxy.name" + LS + "http-proxy-port = 3128" + LS);
406
407 endSection();
408 }
409 }
410
411
412
413 private void gitClone(String url) {
414
415
416 int index = url.indexOf(".git/");
417 if (index > 0) {
418 url = url.substring(0, index + 4);
419 }
420
421 boolean head = (scmTag == null || scmTag.isEmpty()) || "HEAD".equals(scmTag);
422 verbatimText("$ git clone " + (head ? "" : ("--branch " + scmTag + ' ')) + url);
423 }
424
425
426
427
428
429
430
431
432
433
434 private void anonymousAccessGit(GitScmProviderRepository gitRepo) {
435 sink.paragraph();
436 linkPatternedText(getI18nString("anonymousaccess.git.intro"));
437 sink.paragraph_();
438
439 gitClone(gitRepo.getFetchUrl());
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453 private void anonymousAccessMercurial(HgScmProviderRepository hgRepo) {
454 sink.paragraph();
455 linkPatternedText(getI18nString("anonymousaccess.hg.intro"));
456 sink.paragraph_();
457
458 verbatimText("$ hg clone " + hgRepo.getURI());
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472 private void developerAccessGit(GitScmProviderRepository gitRepo) {
473 sink.paragraph();
474 linkPatternedText(getI18nString("devaccess.git.intro"));
475 sink.paragraph_();
476
477 gitClone(gitRepo.getPushUrl());
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491 private void developerAccessMercurial(HgScmProviderRepository hgRepo) {
492 sink.paragraph();
493 linkPatternedText(getI18nString("devaccess.hg.intro"));
494 sink.paragraph_();
495
496 verbatimText("$ hg clone " + hgRepo.getURI());
497 }
498
499
500
501
502
503
504
505
506
507
508
509
510
511 private void anonymousAccessSubversion(SvnScmProviderRepository svnRepo) {
512 paragraph(getI18nString("anonymousaccess.svn.intro"));
513
514 verbatimText("$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName);
515 }
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530 private void developerAccessSubversion(SvnScmProviderRepository svnRepo) {
531 if (svnRepo.getUrl() != null) {
532 if (svnRepo.getUrl().startsWith("https://")) {
533 paragraph(getI18nString("devaccess.svn.intro1.https"));
534 } else if (svnRepo.getUrl().startsWith("svn://")) {
535 paragraph(getI18nString("devaccess.svn.intro1.svn"));
536 } else if (svnRepo.getUrl().startsWith("svn+ssh://")) {
537 paragraph(getI18nString("devaccess.svn.intro1.svnssh"));
538 } else {
539 paragraph(getI18nString("devaccess.svn.intro1.other"));
540 }
541 }
542
543 StringBuilder sb = new StringBuilder();
544
545 sb.append("$ svn checkout ").append(svnRepo.getUrl()).append(" ").append(checkoutDirectoryName);
546
547 verbatimText(sb.toString());
548
549 paragraph(getI18nString("devaccess.svn.intro2"));
550
551 sb = new StringBuilder();
552 sb.append("$ svn commit --username your-username -m \"A message\"");
553
554 verbatimText(sb.toString());
555 }
556
557
558
559
560
561
562
563 public ScmRepository getScmRepository(String scmUrl) {
564 if (scmUrl == null || scmUrl.isEmpty()) {
565 return null;
566 }
567
568 ScmRepository repo = null;
569 List<String> messages = new ArrayList<>();
570 try {
571 messages.addAll(scmManager.validateScmRepository(scmUrl));
572 } catch (Exception e) {
573 messages.add(e.getMessage());
574 }
575
576 if (!messages.isEmpty()) {
577 StringBuilder sb = new StringBuilder();
578 boolean isIntroAdded = false;
579 for (String msg : messages) {
580
581
582 if (msg.startsWith("No such provider")) {
583 continue;
584 }
585
586 if (!isIntroAdded) {
587 sb.append("This SCM url '");
588 sb.append(scmUrl);
589 sb.append("' is invalid due to the following errors:");
590 sb.append(LS);
591 isIntroAdded = true;
592 }
593 sb.append(" * ");
594 sb.append(msg);
595 sb.append(LS);
596 }
597
598 if (StringUtils.isNotEmpty(sb.toString())) {
599 sb.append("For more information about SCM URL Format, please refer to: "
600 + "http://maven.apache.org/scm/scm-url-format.html");
601
602 throw new IllegalArgumentException(sb.toString());
603 }
604 }
605
606 try {
607 repo = scmManager.makeScmRepository(scmUrl);
608 } catch (Exception e) {
609
610 if (log.isDebugEnabled()) {
611 log.debug(e.getMessage(), e);
612 }
613 }
614
615 return repo;
616 }
617
618
619
620
621
622
623
624
625
626
627
628
629
630 private static boolean isScmSystem(ScmRepository scmRepository, String scmProvider) {
631 if (scmProvider == null || scmProvider.isEmpty()) {
632 return false;
633 }
634 return scmRepository != null && scmProvider.equalsIgnoreCase(scmRepository.getProvider());
635 }
636 }
637 }