1 | |
package org.apache.maven.plugin.changes; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import java.util.HashMap; |
23 | |
import java.util.Iterator; |
24 | |
import java.util.LinkedHashMap; |
25 | |
import java.util.List; |
26 | |
import java.util.Map; |
27 | |
import java.util.ResourceBundle; |
28 | |
|
29 | |
import org.apache.commons.lang.StringUtils; |
30 | |
import org.apache.maven.doxia.sink.Sink; |
31 | |
import org.apache.maven.doxia.util.HtmlTools; |
32 | |
import org.apache.maven.plugin.issues.AbstractIssuesReportGenerator; |
33 | |
import org.apache.maven.plugins.changes.model.Action; |
34 | |
import org.apache.maven.plugins.changes.model.Component; |
35 | |
import org.apache.maven.plugins.changes.model.DueTo; |
36 | |
import org.apache.maven.plugins.changes.model.FixedIssue; |
37 | |
import org.apache.maven.plugins.changes.model.Release; |
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
public class ChangesReportGenerator extends AbstractIssuesReportGenerator |
45 | |
{ |
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
private static final String URL_TOKEN = "%URL%"; |
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
private static final String ISSUE_TOKEN = "%ISSUE%"; |
56 | |
|
57 | |
static final String DEFAULT_ISSUE_SYSTEM_KEY = "default"; |
58 | |
|
59 | |
private static final String NO_TEAMLIST = "none"; |
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
private String system; |
68 | |
|
69 | |
private String teamlist; |
70 | |
|
71 | |
private String url; |
72 | |
|
73 | |
private Map issueLinksPerSystem; |
74 | |
|
75 | |
private boolean addActionDate; |
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
private boolean escapeHTML; |
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
private List releaseList; |
86 | |
|
87 | |
public ChangesReportGenerator() |
88 | 0 | { |
89 | 0 | issueLinksPerSystem = new HashMap(); |
90 | 0 | } |
91 | |
|
92 | |
public ChangesReportGenerator( List releaseList ) |
93 | |
{ |
94 | 0 | this(); |
95 | 0 | this.releaseList = releaseList; |
96 | 0 | } |
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
public boolean isEscapeHTML() |
102 | |
{ |
103 | 0 | return escapeHTML; |
104 | |
} |
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
public void setEscapeHTML( boolean escapeHTML ) |
110 | |
{ |
111 | 0 | this.escapeHTML = escapeHTML; |
112 | 0 | } |
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
public String getSystem() |
118 | |
{ |
119 | 0 | return system; |
120 | |
} |
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
public void setSystem( String system ) |
126 | |
{ |
127 | 0 | this.system = system; |
128 | 0 | } |
129 | |
|
130 | |
public void setTeamlist( final String teamlist ) |
131 | |
{ |
132 | 0 | this.teamlist = teamlist; |
133 | 0 | } |
134 | |
|
135 | |
public String getTeamlist() |
136 | |
{ |
137 | 0 | return teamlist; |
138 | |
} |
139 | |
|
140 | |
public void setUrl( String url ) |
141 | |
{ |
142 | 0 | this.url = url; |
143 | 0 | } |
144 | |
|
145 | |
public String getUrl() |
146 | |
{ |
147 | 0 | return url; |
148 | |
} |
149 | |
|
150 | |
public Map getIssueLinksPerSystem() |
151 | |
{ |
152 | 0 | return issueLinksPerSystem; |
153 | |
} |
154 | |
|
155 | |
public void setIssueLinksPerSystem( Map issueLinksPerSystem ) |
156 | |
{ |
157 | 0 | if ( this.issueLinksPerSystem != null && issueLinksPerSystem == null ) |
158 | |
{ |
159 | 0 | return; |
160 | |
} |
161 | 0 | this.issueLinksPerSystem = issueLinksPerSystem; |
162 | 0 | } |
163 | |
|
164 | |
public boolean isAddActionDate() |
165 | |
{ |
166 | 0 | return addActionDate; |
167 | |
} |
168 | |
|
169 | |
public void setAddActionDate( boolean addActionDate ) |
170 | |
{ |
171 | 0 | this.addActionDate = addActionDate; |
172 | 0 | } |
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
|
178 | |
|
179 | |
|
180 | |
public boolean canGenerateIssueLinks( String system ) |
181 | |
{ |
182 | 0 | if ( !this.issueLinksPerSystem.containsKey( system ) ) |
183 | |
{ |
184 | 0 | return false; |
185 | |
} |
186 | 0 | String issueLink = (String) this.issueLinksPerSystem.get( system ); |
187 | |
|
188 | |
|
189 | 0 | if ( StringUtils.isBlank( issueLink ) ) |
190 | |
{ |
191 | 0 | return false; |
192 | |
} |
193 | |
|
194 | |
|
195 | 0 | if ( issueLink.indexOf( URL_TOKEN ) >= 0 && StringUtils.isBlank( getUrl() ) ) |
196 | |
{ |
197 | 0 | return false; |
198 | |
} |
199 | 0 | return true; |
200 | |
} |
201 | |
|
202 | |
public void doGenerateEmptyReport( ResourceBundle bundle, Sink sink, String message ) |
203 | |
{ |
204 | 0 | sinkBeginReport( sink, bundle ); |
205 | |
|
206 | 0 | sink.text( message ); |
207 | |
|
208 | 0 | sinkEndReport( sink ); |
209 | 0 | } |
210 | |
|
211 | |
public void doGenerateReport( ResourceBundle bundle, Sink sink ) |
212 | |
{ |
213 | 0 | sinkBeginReport( sink, bundle ); |
214 | |
|
215 | 0 | constructReleaseHistory(sink, bundle, releaseList); |
216 | |
|
217 | 0 | constructReleases(sink, bundle, releaseList); |
218 | |
|
219 | 0 | sinkEndReport( sink ); |
220 | 0 | } |
221 | |
|
222 | |
|
223 | |
|
224 | |
|
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
private void constructAction( Sink sink, ResourceBundle bundle, Action action ) |
230 | |
{ |
231 | 0 | sink.tableRow(); |
232 | |
|
233 | 0 | sinkShowTypeIcon(sink, action.getType()); |
234 | |
|
235 | 0 | sink.tableCell(); |
236 | |
|
237 | 0 | if ( escapeHTML ) |
238 | |
{ |
239 | 0 | sink.text( action.getAction() ); |
240 | |
} |
241 | |
else |
242 | |
{ |
243 | 0 | sink.rawText( action.getAction() ); |
244 | |
} |
245 | |
|
246 | |
|
247 | 0 | if ( StringUtils.isNotEmpty( action.getIssue() ) || ( !action.getFixedIssues().isEmpty() ) ) |
248 | |
{ |
249 | 0 | sink.text( " " + bundle.getString( "report.changes.text.fixes" ) + " " ); |
250 | |
|
251 | |
|
252 | 0 | String system = action.getSystem(); |
253 | |
|
254 | 0 | if ( StringUtils.isEmpty( system ) ) |
255 | |
{ |
256 | 0 | system = this.system; |
257 | |
} |
258 | |
|
259 | 0 | if ( StringUtils.isEmpty( system ) ) |
260 | |
{ |
261 | 0 | system = DEFAULT_ISSUE_SYSTEM_KEY; |
262 | |
} |
263 | 0 | if ( !canGenerateIssueLinks( system ) ) |
264 | |
{ |
265 | 0 | constructIssueText( action.getIssue(), sink, action.getFixedIssues() ); |
266 | |
} |
267 | |
else |
268 | |
{ |
269 | 0 | constructIssueLink( action.getIssue(), system, sink, action.getFixedIssues() ); |
270 | |
} |
271 | 0 | sink.text( "." ); |
272 | |
} |
273 | |
|
274 | 0 | if ( StringUtils.isNotEmpty( action.getDueTo() ) || ( !action.getDueTos().isEmpty() ) ) |
275 | |
{ |
276 | 0 | constructDueTo( sink, action, bundle, action.getDueTos() ); |
277 | |
} |
278 | |
|
279 | 0 | sink.tableCell_(); |
280 | |
|
281 | 0 | if ( NO_TEAMLIST.equals( teamlist ) ) |
282 | |
{ |
283 | 0 | sinkCell( sink, action.getDev() ); |
284 | |
} |
285 | |
else |
286 | |
{ |
287 | 0 | sinkCellLink( sink, action.getDev(), teamlist + "#" + action.getDev() ); |
288 | |
} |
289 | |
|
290 | 0 | if ( this.isAddActionDate() ) |
291 | |
{ |
292 | 0 | sinkCell( sink, action.getDate() ); |
293 | |
} |
294 | |
|
295 | 0 | sink.tableRow_(); |
296 | 0 | } |
297 | |
|
298 | |
|
299 | |
|
300 | |
|
301 | |
|
302 | |
|
303 | |
|
304 | |
|
305 | |
|
306 | |
private void constructDueTo( Sink sink, Action action, ResourceBundle bundle, List dueTos ) |
307 | |
{ |
308 | |
|
309 | |
|
310 | 0 | Map<String,String> namesEmailMap = new LinkedHashMap<String,String>(); |
311 | |
|
312 | |
|
313 | 0 | if ( StringUtils.isNotEmpty( action.getDueTo() ) || StringUtils.isNotEmpty( action.getDueToEmail() ) ) |
314 | |
{ |
315 | 0 | namesEmailMap.put(action.getDueTo(), action.getDueToEmail()); |
316 | |
} |
317 | |
|
318 | 0 | for ( Iterator iterator = dueTos.iterator(); iterator.hasNext(); ) |
319 | |
{ |
320 | 0 | DueTo dueTo = (DueTo) iterator.next(); |
321 | 0 | namesEmailMap.put( dueTo.getName(), dueTo.getEmail() ); |
322 | 0 | } |
323 | |
|
324 | 0 | if ( namesEmailMap.isEmpty() ) |
325 | |
{ |
326 | 0 | return; |
327 | |
} |
328 | |
|
329 | 0 | sink.text( " " + bundle.getString( "report.changes.text.thanx" ) + " " ); |
330 | 0 | int i = 0; |
331 | 0 | for ( String currentDueTo : namesEmailMap.keySet() ) |
332 | |
{ |
333 | 0 | String currentDueToEmail = namesEmailMap.get( currentDueTo ); |
334 | 0 | i++; |
335 | |
|
336 | 0 | if ( StringUtils.isNotEmpty( currentDueToEmail ) ) |
337 | |
{ |
338 | 0 | sinkLink( sink, currentDueTo, "mailto:" + currentDueToEmail ); |
339 | |
} |
340 | 0 | else if ( StringUtils.isNotEmpty( currentDueTo ) ) |
341 | |
{ |
342 | 0 | sink.text( currentDueTo ); |
343 | |
} |
344 | |
|
345 | 0 | if ( i < namesEmailMap.size() ) |
346 | |
{ |
347 | 0 | sink.text( ", " ); |
348 | |
} |
349 | 0 | } |
350 | |
|
351 | 0 | sink.text("."); |
352 | 0 | } |
353 | |
|
354 | |
|
355 | |
|
356 | |
|
357 | |
|
358 | |
|
359 | |
|
360 | |
|
361 | |
|
362 | |
private void constructIssueLink( String issue, String system, Sink sink, List fixes ) |
363 | |
{ |
364 | 0 | if ( StringUtils.isNotEmpty( issue ) ) |
365 | |
{ |
366 | 0 | sink.link( parseIssueLink( issue, system ) ); |
367 | |
|
368 | 0 | sink.text( issue ); |
369 | |
|
370 | 0 | sink.link_(); |
371 | |
|
372 | 0 | if ( !fixes.isEmpty() ) |
373 | |
{ |
374 | 0 | sink.text( ", " ); |
375 | |
} |
376 | |
} |
377 | |
|
378 | 0 | for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); ) |
379 | |
{ |
380 | 0 | FixedIssue fixedIssue = (FixedIssue) iterator.next(); |
381 | 0 | String currentIssueId = fixedIssue.getIssue(); |
382 | 0 | if ( StringUtils.isNotEmpty( currentIssueId ) ) |
383 | |
{ |
384 | 0 | sink.link( parseIssueLink( currentIssueId, system ) ); |
385 | |
|
386 | 0 | sink.text( currentIssueId ); |
387 | |
|
388 | 0 | sink.link_(); |
389 | |
} |
390 | |
|
391 | 0 | if ( iterator.hasNext() ) |
392 | |
{ |
393 | 0 | sink.text( ", " ); |
394 | |
} |
395 | 0 | } |
396 | 0 | } |
397 | |
|
398 | |
|
399 | |
|
400 | |
|
401 | |
|
402 | |
|
403 | |
|
404 | |
|
405 | |
|
406 | |
private void constructIssueText( String issue, Sink sink, List fixes ) |
407 | |
{ |
408 | 0 | if ( StringUtils.isNotEmpty( issue ) ) |
409 | |
{ |
410 | 0 | sink.text(issue); |
411 | |
|
412 | 0 | if ( !fixes.isEmpty() ) |
413 | |
{ |
414 | 0 | sink.text( ", " ); |
415 | |
} |
416 | |
} |
417 | |
|
418 | 0 | for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); ) |
419 | |
{ |
420 | 0 | FixedIssue fixedIssue = (FixedIssue) iterator.next(); |
421 | |
|
422 | 0 | String currentIssueId = fixedIssue.getIssue(); |
423 | 0 | if ( StringUtils.isNotEmpty( currentIssueId ) ) |
424 | |
{ |
425 | 0 | sink.text(currentIssueId); |
426 | |
} |
427 | |
|
428 | 0 | if ( iterator.hasNext() ) |
429 | |
{ |
430 | 0 | sink.text( ", " ); |
431 | |
} |
432 | 0 | } |
433 | 0 | } |
434 | |
|
435 | |
private void constructReleaseHistory( Sink sink, ResourceBundle bundle, List releaseList ) |
436 | |
{ |
437 | 0 | sink.section2(); |
438 | |
|
439 | 0 | sinkSectionTitle2Anchor( sink, bundle.getString( "report.changes.label.releasehistory" ), |
440 | |
bundle.getString( "report.changes.label.releasehistory" ) ); |
441 | |
|
442 | 0 | sink.table(); |
443 | |
|
444 | 0 | sink.tableRow(); |
445 | |
|
446 | 0 | sinkHeader( sink, bundle.getString( "report.issues.label.fixVersion" ) ); |
447 | |
|
448 | 0 | sinkHeader( sink, bundle.getString( "report.changes.label.releaseDate" ) ); |
449 | |
|
450 | 0 | sinkHeader( sink, bundle.getString( "report.changes.label.releaseDescription" ) ); |
451 | |
|
452 | 0 | sink.tableRow_(); |
453 | |
|
454 | 0 | for ( int idx = 0; idx < releaseList.size(); idx++ ) |
455 | |
{ |
456 | 0 | Release release = (Release) releaseList.get( idx ); |
457 | |
|
458 | 0 | sink.tableRow(); |
459 | |
|
460 | 0 | sinkCellLink( sink, release.getVersion(), "#" + HtmlTools.encodeId( release.getVersion() ) ); |
461 | |
|
462 | 0 | sinkCell( sink, release.getDateRelease() ); |
463 | |
|
464 | 0 | sinkCell( sink, release.getDescription() ); |
465 | |
|
466 | 0 | sink.tableRow_(); |
467 | |
} |
468 | |
|
469 | 0 | sink.table_(); |
470 | |
|
471 | |
|
472 | |
|
473 | |
|
474 | |
|
475 | |
|
476 | |
|
477 | |
|
478 | |
|
479 | |
|
480 | 0 | sink.section2_(); |
481 | 0 | } |
482 | |
|
483 | |
|
484 | |
|
485 | |
|
486 | |
|
487 | |
|
488 | |
|
489 | |
|
490 | |
private void constructReleases( Sink sink, ResourceBundle bundle, List releaseList ) |
491 | |
{ |
492 | 0 | for ( int idx = 0; idx < releaseList.size(); idx++ ) |
493 | |
{ |
494 | 0 | Release release = (Release) releaseList.get(idx); |
495 | 0 | constructRelease( sink, bundle, release ); |
496 | |
} |
497 | 0 | } |
498 | |
|
499 | |
|
500 | |
|
501 | |
|
502 | |
|
503 | |
|
504 | |
|
505 | |
|
506 | |
private void constructRelease( Sink sink, ResourceBundle bundle, Release release ) |
507 | |
{ |
508 | 0 | sink.section2(); |
509 | |
|
510 | 0 | final String date = ( release.getDateRelease() == null ) ? "" : " - " + release.getDateRelease(); |
511 | |
|
512 | 0 | sinkSectionTitle2Anchor(sink, bundle.getString("report.changes.label.release") + " " |
513 | |
+ release.getVersion() + date, release.getVersion()); |
514 | |
|
515 | 0 | if ( isReleaseEmpty( release ) ) |
516 | |
{ |
517 | 0 | sink.paragraph(); |
518 | 0 | sink.text( bundle.getString("report.changes.text.no.changes") ); |
519 | 0 | sink.paragraph_(); |
520 | |
} |
521 | |
else |
522 | |
{ |
523 | 0 | sink.table(); |
524 | |
|
525 | 0 | sink.tableRow(); |
526 | 0 | sinkHeader( sink, bundle.getString( "report.issues.label.type" ) ); |
527 | 0 | sinkHeader( sink, bundle.getString( "report.issues.label.summary" ) ); |
528 | 0 | sinkHeader(sink, bundle.getString("report.issues.label.assignee")); |
529 | 0 | if ( this.isAddActionDate() ) |
530 | |
{ |
531 | 0 | sinkHeader( sink, bundle.getString( "report.issues.label.updated" ) ); |
532 | |
} |
533 | 0 | sink.tableRow_(); |
534 | |
|
535 | 0 | for (Iterator iterator = release.getActions().iterator(); iterator.hasNext();) |
536 | |
{ |
537 | 0 | Action action = (Action) iterator.next(); |
538 | 0 | constructAction(sink, bundle, action); |
539 | 0 | } |
540 | |
|
541 | 0 | for (Iterator iterator = release.getComponents().iterator(); iterator.hasNext();) |
542 | |
{ |
543 | 0 | Component component = (Component) iterator.next(); |
544 | 0 | constructComponent( sink, bundle, component ); |
545 | 0 | } |
546 | |
|
547 | 0 | sink.table_(); |
548 | |
|
549 | 0 | sink.section2_(); |
550 | |
} |
551 | 0 | } |
552 | |
|
553 | |
|
554 | |
|
555 | |
|
556 | |
|
557 | |
|
558 | |
|
559 | |
|
560 | |
|
561 | |
private void constructComponent( Sink sink, ResourceBundle bundle, Component component ) |
562 | |
{ |
563 | 0 | if ( !component.getActions().isEmpty() ) |
564 | |
{ |
565 | 0 | sink.tableRow(); |
566 | |
|
567 | 0 | sink.tableHeaderCell(); |
568 | 0 | sink.tableHeaderCell_(); |
569 | |
|
570 | 0 | sink.tableHeaderCell(); |
571 | 0 | sink.text(component.getName()); |
572 | 0 | sink.tableHeaderCell_(); |
573 | |
|
574 | 0 | sink.tableHeaderCell(); |
575 | 0 | sink.tableHeaderCell_(); |
576 | |
|
577 | 0 | if ( isAddActionDate() ) |
578 | |
{ |
579 | 0 | sink.tableHeaderCell(); |
580 | 0 | sink.tableHeaderCell_(); |
581 | |
} |
582 | |
|
583 | 0 | sink.tableRow_(); |
584 | |
|
585 | 0 | for ( Iterator iterator = component.getActions().iterator(); iterator.hasNext(); ) |
586 | |
{ |
587 | 0 | Action action = (Action) iterator.next(); |
588 | 0 | constructAction( sink, bundle, action ); |
589 | 0 | } |
590 | |
} |
591 | 0 | } |
592 | |
|
593 | |
|
594 | |
|
595 | |
|
596 | |
|
597 | |
|
598 | |
|
599 | |
private boolean isReleaseEmpty( Release release ) { |
600 | 0 | if ( !release.getActions().isEmpty() ) |
601 | |
{ |
602 | 0 | return false; |
603 | |
} |
604 | |
|
605 | 0 | for (Iterator iterator = release.getComponents().iterator(); iterator.hasNext();) |
606 | |
{ |
607 | 0 | Component component = (Component) iterator.next(); |
608 | 0 | if ( !component.getActions().isEmpty() ) |
609 | |
{ |
610 | 0 | return false; |
611 | |
} |
612 | 0 | } |
613 | |
|
614 | 0 | return true; |
615 | |
} |
616 | |
|
617 | |
|
618 | |
|
619 | |
|
620 | |
|
621 | |
|
622 | |
|
623 | |
|
624 | |
private String parseIssueLink( String issue, String system ) |
625 | |
{ |
626 | |
String parseLink; |
627 | 0 | String issueLink = (String) this.issueLinksPerSystem.get( system ); |
628 | 0 | parseLink = issueLink.replaceFirst( ISSUE_TOKEN, issue ); |
629 | 0 | if ( parseLink.indexOf( URL_TOKEN ) >= 0 ) |
630 | |
{ |
631 | 0 | String url = this.url.substring( 0, this.url.lastIndexOf( "/" ) ); |
632 | 0 | parseLink = parseLink.replaceFirst( URL_TOKEN, url ); |
633 | |
} |
634 | |
|
635 | 0 | return parseLink; |
636 | |
} |
637 | |
|
638 | |
} |