1 package org.apache.maven.plugin.announcement;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.OutputStreamWriter;
25 import java.io.Writer;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.changes.IssueAdapter;
33 import org.apache.maven.plugin.changes.ChangesXML;
34 import org.apache.maven.plugin.changes.ProjectUtils;
35 import org.apache.maven.plugin.changes.ReleaseUtils;
36 import org.apache.maven.plugin.jira.JiraXML;
37 import org.apache.maven.plugin.trac.TracDownloader;
38 import org.apache.maven.plugins.changes.model.Release;
39 import org.apache.maven.project.MavenProject;
40 import org.apache.maven.settings.Settings;
41 import org.apache.velocity.Template;
42 import org.apache.velocity.VelocityContext;
43 import org.apache.velocity.app.VelocityEngine;
44 import org.apache.velocity.context.Context;
45 import org.apache.velocity.exception.ResourceNotFoundException;
46 import org.apache.velocity.exception.VelocityException;
47 import org.codehaus.plexus.util.ReaderFactory;
48 import org.codehaus.plexus.util.StringUtils;
49 import org.codehaus.plexus.velocity.VelocityComponent;
50
51
52
53
54
55
56
57
58
59
60
61 public class AnnouncementMojo
62 extends AbstractAnnouncementMojo
63 {
64 private static final String CHANGES_XML = "changes.xml";
65
66 private static final String JIRA = "JIRA";
67
68 private static final String TRAC = "Trac";
69
70
71
72
73
74
75
76
77 private String announcementFile;
78
79
80
81
82
83
84
85
86 private Map announceParameters;
87
88
89
90
91
92 private String artifactId;
93
94
95
96
97
98
99
100
101 private String developmentTeam;
102
103
104
105
106
107
108
109 private String finalName;
110
111
112
113
114
115 private String groupId;
116
117
118
119
120
121
122
123 private String introduction;
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 private List issueManagementSystems;
141
142
143
144
145
146
147
148 private File outputDirectory;
149
150
151
152
153
154
155
156 private String packaging;
157
158
159
160
161
162
163
164
165 private MavenProject project;
166
167
168
169
170
171
172
173 private String template;
174
175
176
177
178
179
180
181
182
183
184
185 private String templateDirectory;
186
187
188
189
190
191
192
193 private String templateEncoding;
194
195
196
197
198
199
200
201 private String url;
202
203
204
205
206
207
208
209
210 private String urlDownload;
211
212
213
214
215
216
217
218 private VelocityComponent velocity;
219
220
221
222
223
224
225 private String version;
226
227
228
229
230
231
232 private File xmlPath;
233
234
235
236
237
238
239
240
241
242
243
244
245
246 private String filter;
247
248
249
250
251
252
253
254
255 private boolean generateJiraAnnouncement;
256
257
258
259
260
261
262
263
264
265 private boolean jiraMerge;
266
267
268
269
270
271
272
273 private String jiraPassword;
274
275
276
277
278
279
280
281 private String jiraUser;
282
283
284
285
286
287
288
289
290 private File jiraXML;
291
292
293
294
295
296
297
298
299
300
301
302 private int maxEntries;
303
304
305
306
307
308
309
310
311
312
313
314 private String resolutionIds;
315
316
317
318
319
320
321
322
323 private Settings settings;
324
325
326
327
328
329
330
331
332
333
334
335 private String statusIds;
336
337
338
339
340
341
342
343 private String webUser;
344
345
346
347
348
349
350
351 private String webPassword;
352
353
354
355
356
357
358
359
360
361
362
363
364 private String tracPassword;
365
366
367
368
369
370
371
372 private String tracQuery;
373
374
375
376
377
378
379
380
381 private String tracUser;
382
383 private ReleaseUtils releaseUtils = new ReleaseUtils( getLog() );
384
385 private ChangesXML xml;
386
387
388
389
390
391
392
393
394
395
396 public void execute()
397 throws MojoExecutionException
398 {
399
400 if ( runOnlyAtExecutionRoot && !isThisTheExecutionRoot() )
401 {
402 getLog().info( "Skipping the announcement generation in this project because it's not the Execution Root" );
403 }
404 else
405 {
406 if ( issueManagementSystems == null )
407 {
408 issueManagementSystems = new ArrayList();
409 }
410
411
412 if ( issueManagementSystems.isEmpty() )
413 {
414 if ( this.jiraMerge )
415 {
416 issueManagementSystems.add( CHANGES_XML );
417 issueManagementSystems.add( JIRA );
418 }
419 else if ( generateJiraAnnouncement )
420 {
421 issueManagementSystems.add( JIRA );
422 }
423 else
424 {
425 issueManagementSystems.add( CHANGES_XML );
426 }
427 }
428
429
430 List releases = null;
431
432 if ( issueManagementSystems.contains( CHANGES_XML ) )
433 {
434 if ( getXmlPath().exists() )
435 {
436 ChangesXML changesXML = new ChangesXML( getXmlPath(), getLog() );
437 List changesReleases = changesXML.getReleaseList();
438 releases = releaseUtils.mergeReleases( releases, changesReleases );
439 getLog().info( "Including issues from file " + getXmlPath() + " in announcement..." );
440 }
441 else
442 {
443 getLog().warn( "changes.xml file " + getXmlPath().getAbsolutePath() + " does not exist." );
444 }
445 }
446
447 if ( issueManagementSystems.contains( JIRA ) )
448 {
449 if ( ProjectUtils.validateIfIssueManagementComplete( project, JIRA, "JIRA announcement", getLog() ) )
450 {
451 List jiraReleases = getJiraReleases();
452 releases = releaseUtils.mergeReleases( releases, jiraReleases );
453 getLog().info( "Including issues from JIRA in announcement..." );
454 }
455 else
456 {
457 throw new MojoExecutionException(
458 "Something is wrong with the Issue Management section." + " See previous error messages." );
459 }
460 }
461
462 if ( issueManagementSystems.contains( TRAC ) )
463 {
464 if ( ProjectUtils.validateIfIssueManagementComplete( project, TRAC, "Trac announcement", getLog() ) )
465 {
466 List tracReleases = getTracReleases();
467 releases = releaseUtils.mergeReleases( releases, tracReleases );
468 getLog().info( "Including issues from Trac in announcement..." );
469 }
470 else
471 {
472 throw new MojoExecutionException(
473 "Something is wrong with the Issue Management section." + " See previous error messages." );
474 }
475 }
476
477
478
479
480
481
482
483
484
485
486
487 if ( releases == null || releases.isEmpty() )
488 {
489 throw new MojoExecutionException(
490 "No releases found in any of the configured issue management systems." );
491 }
492 else
493 {
494 doGenerate( releases );
495 }
496 }
497 }
498
499
500
501
502
503
504
505 public void doGenerate( List releases )
506 throws MojoExecutionException
507 {
508 doGenerate( releases, releaseUtils.getLatestRelease( releases, getVersion() ) );
509 }
510
511 protected void doGenerate( List releases, Release release )
512 throws MojoExecutionException
513 {
514 try
515 {
516 Context context = new VelocityContext();
517
518 if ( getIntroduction() == null || getIntroduction().equals( "" ) )
519 {
520 setIntroduction( getUrl() );
521 }
522
523 context.put( "releases", releases );
524
525 context.put( "groupId", getGroupId() );
526
527 context.put( "artifactId", getArtifactId() );
528
529 context.put( "version", getVersion() );
530
531 context.put( "packaging", getPackaging() );
532
533 context.put( "url", getUrl() );
534
535 context.put( "release", release );
536
537 context.put( "introduction", getIntroduction() );
538
539 context.put( "developmentTeam", getDevelopmentTeam() );
540
541 context.put( "finalName", getFinalName() );
542
543 context.put( "urlDownload", getUrlDownload() );
544
545 context.put( "project", project );
546
547 if ( announceParameters == null )
548 {
549
550 context.put( "announceParameters", Collections.EMPTY_MAP );
551 }
552 else
553 {
554 context.put( "announceParameters", announceParameters );
555 }
556
557
558 processTemplate( context, getOutputDirectory(), template, announcementFile );
559 }
560 catch ( ResourceNotFoundException rnfe )
561 {
562 throw new MojoExecutionException( "Resource not found.", rnfe );
563 }
564 catch ( VelocityException ve )
565 {
566 throw new MojoExecutionException( ve.toString(), ve );
567 }
568 }
569
570
571
572
573
574
575
576
577
578
579 public void processTemplate( Context context, File outputDirectory, String template, String announcementFile )
580 throws ResourceNotFoundException, VelocityException, MojoExecutionException
581 {
582 File f;
583
584
585 if ( StringUtils.isEmpty( announcementFile ) )
586 {
587 announcementFile = template;
588 }
589
590 try
591 {
592 f = new File( outputDirectory, announcementFile );
593
594 if ( !f.getParentFile().exists() )
595 {
596 f.getParentFile().mkdirs();
597 }
598
599 VelocityEngine engine = velocity.getEngine();
600
601 engine.setApplicationAttribute( "baseDirectory", basedir );
602
603 if ( StringUtils.isEmpty( templateEncoding ) )
604 {
605 templateEncoding = ReaderFactory.FILE_ENCODING;
606 getLog().warn(
607 "File encoding has not been set, using platform encoding " + templateEncoding
608 + ", i.e. build is platform dependent!" );
609 }
610
611 Writer writer = new OutputStreamWriter( new FileOutputStream( f ), templateEncoding );
612
613 Template velocityTemplate = engine.getTemplate( templateDirectory + "/" + template, templateEncoding );
614
615 velocityTemplate.merge( context, writer );
616
617 writer.flush();
618
619 writer.close();
620
621 getLog().info( "Created template " + f );
622 }
623
624 catch ( ResourceNotFoundException rnfe )
625 {
626 throw new ResourceNotFoundException( "Template not found. ( " + templateDirectory + "/" + template + " )" );
627 }
628 catch ( VelocityException ve )
629 {
630 throw new VelocityException( ve.toString() );
631 }
632
633 catch ( Exception e )
634 {
635 if ( e.getCause() != null )
636 {
637 getLog().warn( e.getCause() );
638 }
639 throw new MojoExecutionException( e.toString(), e.getCause() );
640 }
641 }
642
643 protected List getJiraReleases()
644 throws MojoExecutionException
645 {
646 JiraDownloader jiraDownloader = new JiraDownloader();
647
648 File jiraXMLFile = jiraXML;
649
650 jiraDownloader.setLog( getLog() );
651
652 jiraDownloader.setOutput( jiraXMLFile );
653
654 jiraDownloader.setStatusIds( statusIds );
655
656 jiraDownloader.setResolutionIds( resolutionIds );
657
658 jiraDownloader.setMavenProject( project );
659
660 jiraDownloader.setSettings( settings );
661
662 jiraDownloader.setNbEntries( maxEntries );
663
664 jiraDownloader.setFilter( filter );
665
666 jiraDownloader.setJiraUser( jiraUser );
667
668 jiraDownloader.setJiraPassword( jiraPassword );
669
670 jiraDownloader.setWebUser( webUser );
671
672 jiraDownloader.setWebPassword( webPassword );
673
674 try
675 {
676 jiraDownloader.doExecute();
677
678 return getReleases( jiraDownloader.getIssueList() );
679 }
680 catch ( Exception e )
681 {
682 throw new MojoExecutionException( "Failed to extract issues from JIRA.", e );
683 }
684 }
685
686 private List getReleases( List issues )
687 {
688 if ( issues.isEmpty() )
689 {
690 return Collections.EMPTY_LIST;
691 }
692 else
693 {
694 return IssueAdapter.getReleases( issues );
695 }
696 }
697
698 protected List getTracReleases()
699 throws MojoExecutionException
700 {
701 TracDownloader issueDownloader = new TracDownloader();
702
703 issueDownloader.setProject( project );
704
705 issueDownloader.setQuery( tracQuery );
706
707 issueDownloader.setTracPassword( tracPassword );
708
709 issueDownloader.setTracUser( tracUser );
710
711 try
712 {
713 return getReleases( issueDownloader.getIssueList() );
714 }
715 catch ( Exception e )
716 {
717 throw new MojoExecutionException( "Failed to extract issues from Trac.", e );
718 }
719 }
720
721
722
723
724
725 public String getArtifactId()
726 {
727 return artifactId;
728 }
729
730 public void setArtifactId( String artifactId )
731 {
732 this.artifactId = artifactId;
733 }
734
735 public String getDevelopmentTeam()
736 {
737 return developmentTeam;
738 }
739
740 public void setDevelopmentTeam( String developmentTeam )
741 {
742 this.developmentTeam = developmentTeam;
743 }
744
745 public String getFinalName()
746 {
747 return finalName;
748 }
749
750 public void setFinalName( String finalName )
751 {
752 this.finalName = finalName;
753 }
754
755 public String getGroupId()
756 {
757 return groupId;
758 }
759
760 public void setGroupId( String groupId )
761 {
762 this.groupId = groupId;
763 }
764
765 public String getIntroduction()
766 {
767 return introduction;
768 }
769
770 public void setIntroduction( String introduction )
771 {
772 this.introduction = introduction;
773 }
774
775 public File getOutputDirectory()
776 {
777 return outputDirectory;
778 }
779
780 public void setOutputDirectory( File outputDirectory )
781 {
782 this.outputDirectory = outputDirectory;
783 }
784
785 public String getPackaging()
786 {
787 return packaging;
788 }
789
790 public void setPackaging( String packaging )
791 {
792 this.packaging = packaging;
793 }
794
795 public String getUrl()
796 {
797 return url;
798 }
799
800 public void setUrl( String url )
801 {
802 this.url = url;
803 }
804
805 public String getUrlDownload()
806 {
807 return urlDownload;
808 }
809
810 public void setUrlDownload( String urlDownload )
811 {
812 this.urlDownload = urlDownload;
813 }
814
815 public VelocityComponent getVelocity()
816 {
817 return velocity;
818 }
819
820 public void setVelocity( VelocityComponent velocity )
821 {
822 this.velocity = velocity;
823 }
824
825 public String getVersion()
826 {
827 return version;
828 }
829
830 public void setVersion( String version )
831 {
832 this.version = version;
833 }
834
835 public ChangesXML getXml()
836 {
837 return xml;
838 }
839
840 public void setXml( ChangesXML xml )
841 {
842 this.xml = xml;
843 }
844
845 public File getXmlPath()
846 {
847 return xmlPath;
848 }
849
850 public void setXmlPath( File xmlPath )
851 {
852 this.xmlPath = xmlPath;
853 }
854 }