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<String,String> namesEmailMap = new LinkedHashMap<String,String>();
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 ( String currentDueTo : namesEmailMap.keySet() )
358 {
359 String currentDueToEmail = namesEmailMap.get( currentDueTo );
360 i++;
361
362 if ( StringUtils.isNotEmpty( currentDueToEmail ) )
363 {
364 sinkLink( sink, currentDueTo, "mailto:" + currentDueToEmail );
365 }
366 else if ( StringUtils.isNotEmpty( currentDueTo ) )
367 {
368 sink.text( currentDueTo );
369 }
370
371 if ( i < namesEmailMap.size() )
372 {
373 sink.text( ", " );
374 }
375 }
376
377 sink.text( "." );
378 }
379
380
381
382
383
384
385
386
387
388 private void constructIssueLink( String issue, String system, Sink sink, List fixes )
389 {
390 if ( StringUtils.isNotEmpty( issue ) )
391 {
392 sink.link( parseIssueLink( issue, system ) );
393
394 sink.text( issue );
395
396 sink.link_();
397
398 if ( !fixes.isEmpty() )
399 {
400 sink.text( ", " );
401 }
402 }
403
404 for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); )
405 {
406 FixedIssue fixedIssue = (FixedIssue) iterator.next();
407 String currentIssueId = fixedIssue.getIssue();
408 if ( StringUtils.isNotEmpty( currentIssueId ) )
409 {
410 sink.link( parseIssueLink( currentIssueId, system ) );
411
412 sink.text( currentIssueId );
413
414 sink.link_();
415 }
416
417 if ( iterator.hasNext() )
418 {
419 sink.text( ", " );
420 }
421 }
422 }
423
424
425
426
427
428
429
430
431
432 private void constructIssueText( String issue, Sink sink, List fixes )
433 {
434 if ( StringUtils.isNotEmpty( issue ) )
435 {
436 sink.text( issue );
437
438 if ( !fixes.isEmpty() )
439 {
440 sink.text( ", " );
441 }
442 }
443
444 for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); )
445 {
446 FixedIssue fixedIssue = (FixedIssue) iterator.next();
447
448 String currentIssueId = fixedIssue.getIssue();
449 if ( StringUtils.isNotEmpty( currentIssueId ) )
450 {
451 sink.text( currentIssueId );
452 }
453
454 if ( iterator.hasNext() )
455 {
456 sink.text( ", " );
457 }
458 }
459 }
460
461 private void constructReleaseHistory( Sink sink, ResourceBundle bundle, List releaseList )
462 {
463 sink.section2();
464
465 sinkSectionTitle2Anchor( sink, bundle.getString( "report.changes.label.releasehistory" ),
466 bundle.getString( "report.changes.label.releasehistory" ) );
467
468 sink.table();
469
470 sink.tableRow();
471
472 sinkHeader( sink, bundle.getString( "report.issues.label.fixVersion" ) );
473
474 sinkHeader( sink, bundle.getString( "report.changes.label.releaseDate" ) );
475
476 sinkHeader( sink, bundle.getString( "report.changes.label.releaseDescription" ) );
477
478 sink.tableRow_();
479
480 for ( int idx = 0; idx < releaseList.size(); idx++ )
481 {
482 Release release = (Release) releaseList.get( idx );
483
484 sink.tableRow();
485
486 sinkCellLink( sink, release.getVersion(), "#" + HtmlTools.encodeId( release.getVersion() ) );
487
488 sinkCell( sink, release.getDateRelease() );
489
490 sinkCell( sink, release.getDescription() );
491
492 sink.tableRow_();
493 }
494
495 sink.table_();
496
497
498
499
500
501
502
503
504
505
506 sink.section2_();
507 }
508
509 private void constructReleases( Sink sink, ResourceBundle bundle, List releaseList )
510 {
511
512 for ( int idx = 0; idx < releaseList.size(); idx++ )
513 {
514 Release release = (Release) releaseList.get( idx );
515
516 sink.section2();
517
518 final String date = ( release.getDateRelease() == null ) ? "" : " - " + release.getDateRelease();
519
520 sinkSectionTitle2Anchor( sink, bundle.getString( "report.changes.label.release" ) + " "
521 + release.getVersion() + date, release.getVersion() );
522
523 constructActions( sink, release.getActions(), bundle );
524
525 sink.section2_();
526 }
527 }
528
529
530
531
532
533
534
535
536 private String parseIssueLink( String issue, String system )
537 {
538 String parseLink;
539 String issueLink = (String) this.issueLinksPerSystem.get( system );
540 parseLink = issueLink.replaceFirst( ISSUE_TOKEN, issue );
541 if ( parseLink.indexOf( URL_TOKEN ) >= 0 )
542 {
543 String url = this.url.substring( 0, this.url.lastIndexOf( "/" ) );
544 parseLink = parseLink.replaceFirst( URL_TOKEN, url );
545 }
546
547 return parseLink;
548 }
549
550 }