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