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