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