View Javadoc
1   package org.apache.maven.plugin.announcement;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.plugin.MojoExecutionException;
23  import org.apache.maven.plugin.changes.ChangesXML;
24  import org.apache.maven.plugin.changes.IssueAdapter;
25  import org.apache.maven.plugin.changes.ProjectUtils;
26  import org.apache.maven.plugin.changes.ReleaseUtils;
27  import org.apache.maven.plugin.github.GitHubDownloader;
28  import org.apache.maven.plugin.github.GitHubIssueManagementSystem;
29  import org.apache.maven.plugin.issues.Issue;
30  import org.apache.maven.plugin.issues.IssueManagementSystem;
31  import org.apache.maven.plugin.issues.IssueUtils;
32  import org.apache.maven.plugin.jira.AbstractJiraDownloader;
33  import org.apache.maven.plugin.jira.AdaptiveJiraDownloader;
34  import org.apache.maven.plugin.jira.JIRAIssueManagmentSystem;
35  import org.apache.maven.plugin.trac.TracDownloader;
36  import org.apache.maven.plugin.trac.TracIssueManagmentSystem;
37  import org.apache.maven.plugins.annotations.Component;
38  import org.apache.maven.plugins.annotations.Mojo;
39  import org.apache.maven.plugins.annotations.Parameter;
40  import org.apache.maven.plugins.changes.model.Release;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.settings.Settings;
43  import org.apache.velocity.Template;
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.apache.velocity.tools.ToolManager;
49  import org.codehaus.plexus.util.ReaderFactory;
50  import org.codehaus.plexus.util.StringUtils;
51  import org.codehaus.plexus.velocity.VelocityComponent;
52  
53  import java.io.File;
54  import java.io.FileOutputStream;
55  import java.io.OutputStreamWriter;
56  import java.io.Writer;
57  import java.util.ArrayList;
58  import java.util.Collections;
59  import java.util.List;
60  import java.util.Map;
61  
62  /**
63   * Goal which generate an announcement from the announcement template.
64   *
65   * @author aramirez@exist.com
66   * @version $Id: AnnouncementMojo.java 1718158 2015-12-06 10:49:10Z olamy $
67   * @since 2.0-beta-2
68   */
69  @Mojo( name = "announcement-generate", threadSafe = true )
70  public class AnnouncementMojo
71      extends AbstractAnnouncementMojo
72  {
73      private static final String CHANGES_XML = "changes.xml";
74  
75      private static final String JIRA = "JIRA";
76  
77      private static final String TRAC = "Trac";
78  
79      private static final String GIT_HUB = "GitHub";
80  
81      /**
82       * The name of the file which will contain the generated announcement. If no value is specified the plugin will use
83       * the name of the template.
84       *
85       * @since 2.4
86       */
87      @Parameter( property = "changes.announcementFile" )
88      private String announcementFile;
89  
90      /**
91       * Map of custom parameters for the announcement. This Map will be passed to the template.
92       *
93       * @since 2.1
94       */
95      @Parameter
96      private Map announceParameters;
97  
98      /**
99       */
100     @Parameter( property = "project.artifactId", readonly = true )
101     private String artifactId;
102 
103     /**
104      * Name of the team that develops the artifact. This parameter will be passed to the template.
105      */
106     @Parameter( property = "changes.developmentTeam", defaultValue = "${project.name} team", required = true )
107     private String developmentTeam;
108 
109     /**
110      * The name of the artifact to be used in the announcement.
111      */
112     @Parameter( property = "changes.finalName", defaultValue = "${project.build.finalName}", required = true )
113     private String finalName;
114 
115     /**
116      */
117     @Parameter( property = "project.groupId", readonly = true )
118     private String groupId;
119 
120     /**
121      * Short description or introduction of the released artifact. This parameter will be passed to the template.
122      */
123     @Parameter( defaultValue = "${project.description}" )
124     private String introduction;
125 
126     /**
127      * A list of issue management systems to fetch releases from. This parameter replaces the parameters
128      * <code>generateJiraAnnouncement</code> and <code>jiraMerge</code>.
129      * <p>
130      * Valid values are: <code>changes.xml</code> and <code>JIRA</code>.
131      * </p>
132      * <strong>Note:</strong> Only one issue management system that is configured in
133      * &lt;project&gt;/&lt;issueManagement&gt; can be used. This currently means that you can combine a changes.xml file
134      * with one other issue management system.
135      *
136      * @since 2.4
137      */
138     @Parameter
139     private List<String> issueManagementSystems;
140 
141     /**
142      * Maps issues types to action types for grouping issues in announcements. If issue types are not defined for a
143      * action type then the default issue type will be applied.
144      * <p>
145      * Valid action types: <code>add</code>, <code>fix</code> and <code>update</code>.
146      * </p>
147      *
148      * @since 2.6
149      */
150     @Parameter
151     private Map<String, String> issueTypes;
152 
153     /**
154      * Directory where the announcement file will be generated.
155      *
156      * @since 2.10
157      */
158     @Parameter( defaultValue = "${project.build.directory}/announcement", required = true )
159     private File announcementDirectory;
160 
161     /**
162      * Directory where the announcement file will be generated.
163      *
164      * @deprecated Starting with version 2.10 this parameter is no longer used. You must use
165      *             {@link #announcementDirectory} instead.
166      */
167     @Parameter
168     private File outputDirectory;
169 
170     /**
171      * Packaging structure for the artifact.
172      */
173     @Parameter( property = "project.packaging", readonly = true )
174     private String packaging;
175 
176     /**
177      * The Maven Project.
178      */
179     @Parameter( defaultValue = "${project}", readonly = true, required = true )
180     private MavenProject project;
181 
182     /**
183      * The Velocity template used to format the announcement.
184      */
185     @Parameter( property = "changes.template", defaultValue = "announcement.vm", required = true )
186     private String template;
187 
188     /**
189      * Directory that contains the template.
190      * <p>
191      * <b>Note:</b> This directory must be a subdirectory of
192      * <code>/src/main/resources/ or current project base directory</code>.
193      * </p>
194      */
195     // CHECKSTYLE_OFF: LineLength
196     @Parameter( property = "changes.templateDirectory", defaultValue = "org/apache/maven/plugin/announcement", required = true )
197     private String templateDirectory;
198     // CHECKSTYLE_ON: LineLength
199 
200     /**
201      * The template encoding.
202      *
203      * @since 2.1
204      */
205     @Parameter( property = "changes.templateEncoding", defaultValue = "${project.build.sourceEncoding}" )
206     private String templateEncoding;
207 
208     /**
209      * Use the JIRA query language instead of the JIRA query based on HTTP parameters. From JIRA 5.1 and up only JQL is
210      * supported. JIRA 4.4 supports both JQL and URL parameter based queries. From 5.1.1 this is obsolete, since REST
211      * queries only use JQL.
212      *
213      * @since 2.10
214      */
215     @Parameter( property = "changes.useJql", defaultValue = "false" )
216     private boolean useJql;
217 
218     /**
219      * Distribution URL of the artifact. This parameter will be passed to the template.
220      */
221     @Parameter( property = "project.url" )
222     private String url;
223 
224     /**
225      * URL where the artifact can be downloaded. If not specified, no URL is used. This parameter will be passed to the
226      * template.
227      */
228     @Parameter
229     private String urlDownload;
230 
231     /**
232      * Velocity Component.
233      */
234     @Component( role = VelocityComponent.class, hint = "maven-changes-plugin" )
235     private VelocityComponent velocity;
236 
237     /**
238      * Version of the artifact.
239      */
240     @Parameter( property = "changes.version", defaultValue = "${project.version}", required = true )
241     private String version;
242 
243     /**
244      * The path of the changes.xml file.
245      *
246      * @parameter expression="${basedir}/src/changes/changes.xml"
247      * @required
248      */
249     @Parameter( defaultValue = "${basedir}/src/changes/changes.xml" )
250     private File xmlPath;
251 
252     // =======================================//
253     // JIRA-Announcement Needed Parameters //
254     // =======================================//
255 
256     /**
257      * Defines the filter parameters to restrict which issues are retrieved from JIRA. The filter parameter uses the
258      * same format of url parameters that is used in a JIRA search.
259      *
260      * @since 2.4
261      */
262     @Parameter( defaultValue = "" )
263     private String filter;
264 
265     /**
266      * Flag to determine if the plugin will generate a JIRA announcement.
267      *
268      * @deprecated Since version 2.4 this parameter has been deprecated. Please use the issueManagementSystems parameter
269      *             instead.
270      */
271     @Parameter( property = "generateJiraAnnouncement", defaultValue = "false", required = true )
272     private boolean generateJiraAnnouncement;
273 
274     /**
275      * If releases from JIRA should be merged with the releases from a changes.xml file.
276      *
277      * @since 2.1
278      * @deprecated Since version 2.4 this parameter has been deprecated. Please use the issueManagementSystems parameter
279      *             instead.
280      */
281     @Parameter( property = "changes.jiraMerge", defaultValue = "false" )
282     private boolean jiraMerge;
283 
284     /**
285      * Defines the JIRA password for authentication into a private JIRA installation.
286      *
287      * @since 2.1
288      */
289     @Parameter( property = "changes.jiraPassword", defaultValue = "" )
290     private String jiraPassword;
291 
292     /**
293      * Defines the JIRA username for authentication into a private JIRA installation.
294      *
295      * @since 2.1
296      */
297     @Parameter( property = "changes.jiraUser", defaultValue = "" )
298     private String jiraUser;
299 
300     /**
301      * Path to the JIRA XML file, which will be parsed.
302      */
303     @Parameter( defaultValue = "${project.build.directory}/jira-announcement.xml", required = true, readonly = true )
304     private File jiraXML;
305 
306     /**
307      * The maximum number of issues to fetch from JIRA.
308      * <p>
309      * <b>Note:</b> In versions 2.0-beta-3 and earlier this parameter was called "nbEntries".
310      * </p>
311      */
312     @Parameter( property = "changes.maxEntries", defaultValue = "25", required = true )
313     private int maxEntries;
314 
315     /**
316      * Include issues from JIRA with these resolution ids. Multiple resolution ids can be specified as a comma separated
317      * list of ids.
318      * <p>
319      * <b>Note:</b> In versions 2.0-beta-3 and earlier this parameter was called "resolutionId".
320      * </p>
321      */
322     @Parameter( property = "changes.resolutionIds", defaultValue = "Fixed" )
323     private String resolutionIds;
324 
325     /**
326      * Settings XML configuration.
327      */
328     @Parameter( defaultValue = "${settings}", readonly = true, required = true )
329     private Settings settings;
330 
331     /**
332      * Include issues from JIRA with these status ids. Multiple status ids can be specified as a comma separated list of
333      * ids.
334      * <p>
335      * <b>Note:</b> In versions 2.0-beta-3 and earlier this parameter was called "statusId".
336      * </p>
337      */
338     @Parameter( property = "changes.statusIds", defaultValue = "Closed" )
339     private String statusIds;
340 
341     /**
342      * Defines the http user for basic authentication into the JIRA webserver.
343      *
344      * @since 2.4
345      */
346     @Parameter( property = "changes.webUser", defaultValue = "" )
347     private String webUser;
348 
349     /**
350      * Defines the http password for basic authentication into the JIRA webserver.
351      *
352      * @since 2.4
353      */
354     @Parameter( property = "changes.webPassword", defaultValue = "" )
355     private String webPassword;
356 
357     /**
358      * The prefix used when naming versions in JIRA.
359      * <p>
360      * If you have a project in JIRA with several components that have different release cycles, it is an often used
361      * pattern to prefix the version with the name of the component, e.g. maven-filtering-1.0 etc. To fetch issues from
362      * JIRA for a release of the "maven-filtering" component you would need to set this parameter to "maven-filtering-".
363      * </p>
364      *
365      * @since 2.5
366      */
367     @Parameter( property = "changes.versionPrefix", defaultValue = "" )
368     private String versionPrefix;
369 
370     /**
371      * Defines the connection timeout in milliseconds when accessing JIRA's REST-API.
372      * <p>
373      * Might help when you have a lot of different resolutions in your JIRA instance.
374      * </p>
375      *
376      * @since 2.11
377      */
378     @Parameter( property = "changes.jiraConnectionTimeout", defaultValue = "36000" )
379     private int jiraConnectionTimeout;
380 
381     /**
382      * Defines the receive timeout in milliseconds when accessing JIRA's REST-API.
383      * <p>
384      * Might help when you have a lot of different resolutions in your JIRA instance.
385      * </p>
386      *
387      * @since 2.11
388      */
389     @Parameter( property = "changes.jiraReceiveTimout", defaultValue = "32000" )
390     private int jiraReceiveTimout;
391 
392     // =======================================//
393     // Trac Parameters //
394     // =======================================//
395 
396     /**
397      * Defines the Trac password for authentication into a private Trac installation.
398      *
399      * @since 2.4
400      */
401     @Parameter( property = "changes.tracPassword", defaultValue = "" )
402     private String tracPassword;
403 
404     /**
405      * Defines the Trac query for searching for tickets.
406      *
407      * @since 2.4
408      */
409     @Parameter( defaultValue = "order=id" )
410     private String tracQuery;
411 
412     /**
413      * Defines the Trac username for authentication into a private Trac installation.
414      *
415      * @since 2.4
416      */
417     @Parameter( property = "changes.tracUser", defaultValue = "" )
418     private String tracUser;
419 
420     // =======================================//
421     // Github Parameters //
422     // =======================================//
423 
424     /**
425      * The scheme of your github api domain. Only use if using github enterprise.
426      * 
427      * @since 2.9
428      */
429     @Parameter( defaultValue = "http", property = "changes.githubAPIScheme" )
430     private String githubAPIScheme;
431 
432     /**
433      * The port of your github api domain. Only use if using github enterprise.
434      * 
435      * @since 2.9
436      */
437     @Parameter( defaultValue = "80", property = "changes.githubAPIPort" )
438     private int githubAPIPort;
439 
440     /**
441      * The settings.xml server id to be used to authenticate into github api domain. Only use if using github
442      * enterprise.
443      *
444      * @since 2.12
445      */
446     @Parameter( defaultValue = "github" )
447     private String githubAPIServerId;
448 
449     /**
450      * Boolean which says if we should include open github issues in the announcement.
451      */
452     @Parameter( defaultValue = "false" )
453     private boolean includeOpenIssues;
454 
455     private ReleaseUtils releaseUtils = new ReleaseUtils( getLog() );
456 
457     private ChangesXML xml;
458 
459     // =======================================//
460     // announcement-generate execution //
461     // =======================================//
462 
463     /**
464      * Generate the template
465      *
466      * @throws MojoExecutionException
467      */
468     public void execute()
469         throws MojoExecutionException
470     {
471         // Fail build fast if it is using deprecated parameters
472         if ( outputDirectory != null )
473         {
474             throw new MojoExecutionException( "You are using the old parameter 'outputDirectory'. "
475                 + "You must use 'announcementDirectory' instead." );
476         }
477 
478         // Run only at the execution root
479         if ( runOnlyAtExecutionRoot && !isThisTheExecutionRoot() )
480         {
481             getLog().info( "Skipping the announcement generation in this project because it's not the Execution Root" );
482         }
483         else
484         {
485             if ( issueManagementSystems == null )
486             {
487                 issueManagementSystems = new ArrayList<String>();
488             }
489 
490             // Handle deprecated parameters, in a backward compatible way
491             if ( issueManagementSystems.isEmpty() )
492             {
493                 if ( this.jiraMerge )
494                 {
495                     issueManagementSystems.add( CHANGES_XML );
496                     issueManagementSystems.add( JIRA );
497                 }
498                 else if ( generateJiraAnnouncement )
499                 {
500                     issueManagementSystems.add( JIRA );
501                 }
502                 else
503                 {
504                     issueManagementSystems.add( CHANGES_XML );
505                 }
506             }
507 
508             // Fetch releases from the configured issue management systems
509             List<Release> releases = null;
510             if ( issueManagementSystems.contains( CHANGES_XML ) )
511             {
512                 if ( getXmlPath().exists() )
513                 {
514                     ChangesXML changesXML = new ChangesXML( getXmlPath(), getLog() );
515                     List<Release> changesReleases = releaseUtils.convertReleaseList( changesXML.getReleaseList() );
516                     releases = releaseUtils.mergeReleases( null, changesReleases );
517                     getLog().info( "Including issues from file " + getXmlPath() + " in announcement..." );
518                 }
519                 else
520                 {
521                     getLog().warn( "changes.xml file " + getXmlPath().getAbsolutePath() + " does not exist." );
522                 }
523             }
524 
525             if ( issueManagementSystems.contains( JIRA ) )
526             {
527                 if ( ProjectUtils.validateIfIssueManagementComplete( project, JIRA, "JIRA announcement", getLog() ) )
528                 {
529                     List<Release> jiraReleases = getJiraReleases();
530                     releases = releaseUtils.mergeReleases( releases, jiraReleases );
531                     getLog().info( "Including issues from JIRA in announcement..." );
532                 }
533                 else
534                 {
535                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
536                         + "See previous error messages." );
537                 }
538             }
539 
540             if ( issueManagementSystems.contains( TRAC ) )
541             {
542                 if ( ProjectUtils.validateIfIssueManagementComplete( project, TRAC, "Trac announcement", getLog() ) )
543                 {
544                     List<Release> tracReleases = getTracReleases();
545                     releases = releaseUtils.mergeReleases( releases, tracReleases );
546                     getLog().info( "Including issues from Trac in announcement..." );
547                 }
548                 else
549                 {
550                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
551                         + "See previous error messages." );
552                 }
553             }
554 
555             if ( issueManagementSystems.contains( GIT_HUB ) )
556             {
557                 if ( ProjectUtils.validateIfIssueManagementComplete( project, GIT_HUB, "GitHub announcement",
558                                                                      getLog() ) )
559                 {
560                     List<Release> gitHubReleases = getGitHubReleases();
561                     releases = releaseUtils.mergeReleases( releases, gitHubReleases );
562                     getLog().info( "Including issues from GitHub in announcement..." );
563                 }
564                 else
565                 {
566                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
567                         + "See previous error messages." );
568                 }
569             }
570 
571             // @todo Add more issue management systems here.
572 
573             // Follow these steps:
574             // 1. Add a constant for the name of the issue management system
575             // 2. Add the @parameters needed to configure the issue management system
576             // 3. Add a protected List get<IMSname>Releases() method that retrieves a list of releases
577             // 4. Merge those releases into the "releases" variable
578             // For help with these steps, you can have a look at how this has been done for JIRA or Trac
579 
580             // Generate the report
581             if ( releases == null || releases.isEmpty() )
582             {
583                 throw new MojoExecutionException( "No releases found in any of the "
584                     + "configured issue management systems." );
585             }
586             else
587             {
588                 doGenerate( releases );
589             }
590         }
591     }
592 
593     /**
594      * Add the parameters to velocity context
595      *
596      * @param releases A <code>List</code> of <code>Release</code>s
597      * @throws MojoExecutionException
598      */
599     public void doGenerate( List<Release> releases )
600         throws MojoExecutionException
601     {
602         String version = ( versionPrefix == null ? "" : versionPrefix ) + getVersion();
603 
604         getLog().debug( "Generating announcement for version [" + version + "]. Found these releases: "
605             + ReleaseUtils.toString( releases ) );
606 
607         doGenerate( releases, releaseUtils.getLatestRelease( releases, version ) );
608     }
609 
610     protected void doGenerate( List<Release> releases, Release release )
611         throws MojoExecutionException
612     {
613         try
614         {
615             ToolManager toolManager = new ToolManager( true );
616             Context context = toolManager.createContext();
617 
618             if ( getIntroduction() == null || getIntroduction().equals( "" ) )
619             {
620                 setIntroduction( getUrl() );
621             }
622 
623             context.put( "releases", releases );
624 
625             context.put( "groupId", getGroupId() );
626 
627             context.put( "artifactId", getArtifactId() );
628 
629             context.put( "version", getVersion() );
630 
631             context.put( "packaging", getPackaging() );
632 
633             context.put( "url", getUrl() );
634 
635             context.put( "release", release );
636 
637             context.put( "introduction", getIntroduction() );
638 
639             context.put( "developmentTeam", getDevelopmentTeam() );
640 
641             context.put( "finalName", getFinalName() );
642 
643             context.put( "urlDownload", getUrlDownload() );
644 
645             context.put( "project", project );
646 
647             if ( announceParameters == null )
648             {
649                 // empty Map to prevent NPE in velocity execution
650                 context.put( "announceParameters", Collections.EMPTY_MAP );
651             }
652             else
653             {
654                 context.put( "announceParameters", announceParameters );
655             }
656 
657             processTemplate( context, announcementDirectory, template, announcementFile );
658         }
659         catch ( ResourceNotFoundException rnfe )
660         {
661             throw new MojoExecutionException( "Resource not found.", rnfe );
662         }
663         catch ( VelocityException ve )
664         {
665             throw new MojoExecutionException( ve.toString(), ve );
666         }
667     }
668 
669     /**
670      * Create the velocity template
671      *
672      * @param context velocity context that has the parameter values
673      * @param outputDirectory directory where the file will be generated
674      * @param template velocity template which will the context be merged
675      * @param announcementFile The file name of the generated announcement
676      * @throws ResourceNotFoundException, VelocityException, IOException
677      */
678     public void processTemplate( Context context, File outputDirectory, String template, String announcementFile )
679         throws VelocityException, MojoExecutionException
680     {
681         File f;
682 
683         // Use the name of the template as a default value
684         if ( StringUtils.isEmpty( announcementFile ) )
685         {
686             announcementFile = template;
687         }
688 
689         try
690         {
691             f = new File( outputDirectory, announcementFile );
692 
693             if ( !f.getParentFile().exists() )
694             {
695                 f.getParentFile().mkdirs();
696             }
697 
698             VelocityEngine engine = velocity.getEngine();
699 
700             engine.setApplicationAttribute( "baseDirectory", basedir );
701 
702             if ( StringUtils.isEmpty( templateEncoding ) )
703             {
704                 templateEncoding = ReaderFactory.FILE_ENCODING;
705                 getLog().warn( "File encoding has not been set, using platform encoding " + templateEncoding
706                     + ", i.e. build is platform dependent!" );
707             }
708 
709             Writer writer = new OutputStreamWriter( new FileOutputStream( f ), templateEncoding );
710 
711             Template velocityTemplate = engine.getTemplate( templateDirectory + "/" + template, templateEncoding );
712 
713             velocityTemplate.merge( context, writer );
714 
715             writer.flush();
716 
717             writer.close();
718 
719             getLog().info( "Created template " + f );
720         }
721 
722         catch ( ResourceNotFoundException rnfe )
723         {
724             throw new ResourceNotFoundException( "Template not found. ( " + templateDirectory + "/" + template + " )" );
725         }
726         catch ( VelocityException ve )
727         {
728             throw new VelocityException( ve.toString() );
729         }
730 
731         catch ( Exception e )
732         {
733             if ( e.getCause() != null )
734             {
735                 getLog().warn( e.getCause() );
736             }
737             throw new MojoExecutionException( e.toString(), e.getCause() );
738         }
739     }
740 
741     protected List<Release> getJiraReleases()
742         throws MojoExecutionException
743     {
744         AbstractJiraDownloader jiraDownloader = new AdaptiveJiraDownloader();
745 
746         File jiraXMLFile = jiraXML;
747 
748         jiraDownloader.setLog( getLog() );
749 
750         jiraDownloader.setOutput( jiraXMLFile );
751 
752         jiraDownloader.setStatusIds( statusIds );
753 
754         jiraDownloader.setResolutionIds( resolutionIds );
755 
756         jiraDownloader.setMavenProject( project );
757 
758         jiraDownloader.setSettings( settings );
759 
760         jiraDownloader.setNbEntries( maxEntries );
761 
762         jiraDownloader.setFilter( filter );
763 
764         jiraDownloader.setJiraUser( jiraUser );
765 
766         jiraDownloader.setJiraPassword( jiraPassword );
767 
768         jiraDownloader.setUseJql( useJql );
769 
770         jiraDownloader.setWebUser( webUser );
771 
772         jiraDownloader.setWebPassword( webPassword );
773 
774         jiraDownloader.setConnectionTimeout( jiraConnectionTimeout );
775 
776         jiraDownloader.setReceiveTimout( jiraReceiveTimout );
777 
778         try
779         {
780             jiraDownloader.doExecute();
781 
782             List<Issue> issueList = jiraDownloader.getIssueList();
783 
784             if ( StringUtils.isNotEmpty( versionPrefix ) )
785             {
786                 int originalNumberOfIssues = issueList.size();
787                 issueList = IssueUtils.filterIssuesWithVersionPrefix( issueList, versionPrefix );
788                 getLog().debug( "Filtered out " + issueList.size() + " issues of " + originalNumberOfIssues
789                     + " that matched the versionPrefix '" + versionPrefix + "'." );
790             }
791 
792             return getReleases( issueList, new JIRAIssueManagmentSystem() );
793         }
794         catch ( Exception e )
795         {
796             throw new MojoExecutionException( "Failed to extract issues from JIRA.", e );
797         }
798     }
799 
800     private List<Release> getReleases( List<Issue> issues, IssueManagementSystem ims )
801         throws MojoExecutionException
802     {
803         if ( issueTypes != null )
804         {
805             ims.applyConfiguration( issueTypes );
806         }
807         if ( issues.isEmpty() )
808         {
809             return Collections.emptyList();
810         }
811         else
812         {
813             IssueAdapter adapter = new IssueAdapter( ims );
814             return adapter.getReleases( issues );
815         }
816     }
817 
818     protected List<Release> getTracReleases()
819         throws MojoExecutionException
820     {
821         TracDownloader issueDownloader = new TracDownloader();
822 
823         issueDownloader.setProject( project );
824 
825         issueDownloader.setQuery( tracQuery );
826 
827         issueDownloader.setTracPassword( tracPassword );
828 
829         issueDownloader.setTracUser( tracUser );
830 
831         try
832         {
833             return getReleases( issueDownloader.getIssueList(), new TracIssueManagmentSystem() );
834         }
835         catch ( Exception e )
836         {
837             throw new MojoExecutionException( "Failed to extract issues from Trac.", e );
838         }
839     }
840 
841     protected List<Release> getGitHubReleases()
842         throws MojoExecutionException
843     {
844         try
845         {
846             GitHubDownloader issueDownloader =
847                 new GitHubDownloader( project, githubAPIScheme, githubAPIPort, includeOpenIssues, true );
848 
849             issueDownloader.configureAuthentication( githubAPIServerId, settings, getLog() );
850 
851             return getReleases( issueDownloader.getIssueList(), new GitHubIssueManagementSystem() );
852         }
853         catch ( Exception e )
854         {
855             throw new MojoExecutionException( "Failed to extract issues from GitHub.", e );
856         }
857     }
858 
859     /*
860      * accessors
861      */
862 
863     public String getArtifactId()
864     {
865         return artifactId;
866     }
867 
868     public void setArtifactId( String artifactId )
869     {
870         this.artifactId = artifactId;
871     }
872 
873     public String getDevelopmentTeam()
874     {
875         return developmentTeam;
876     }
877 
878     public void setDevelopmentTeam( String developmentTeam )
879     {
880         this.developmentTeam = developmentTeam;
881     }
882 
883     public String getFinalName()
884     {
885         return finalName;
886     }
887 
888     public void setFinalName( String finalName )
889     {
890         this.finalName = finalName;
891     }
892 
893     public String getGroupId()
894     {
895         return groupId;
896     }
897 
898     public void setGroupId( String groupId )
899     {
900         this.groupId = groupId;
901     }
902 
903     public String getIntroduction()
904     {
905         return introduction;
906     }
907 
908     public void setIntroduction( String introduction )
909     {
910         this.introduction = introduction;
911     }
912 
913     public void setIssueTypes( Map<String, String> issueTypes )
914     {
915         this.issueTypes = issueTypes;
916     }
917 
918     public Map<String, String> getIssueTypes()
919     {
920         return issueTypes;
921     }
922 
923     public File getAnnouncementDirectory()
924     {
925         return announcementDirectory;
926     }
927 
928     public void setAnnouncementDirectory( File announcementDirectory )
929     {
930         this.announcementDirectory = announcementDirectory;
931     }
932 
933     public String getPackaging()
934     {
935         return packaging;
936     }
937 
938     public void setPackaging( String packaging )
939     {
940         this.packaging = packaging;
941     }
942 
943     public String getUrl()
944     {
945         return url;
946     }
947 
948     public void setUrl( String url )
949     {
950         this.url = url;
951     }
952 
953     public String getUrlDownload()
954     {
955         return urlDownload;
956     }
957 
958     public void setUrlDownload( String urlDownload )
959     {
960         this.urlDownload = urlDownload;
961     }
962 
963     public VelocityComponent getVelocity()
964     {
965         return velocity;
966     }
967 
968     public void setVelocity( VelocityComponent velocity )
969     {
970         this.velocity = velocity;
971     }
972 
973     public String getVersion()
974     {
975         return version;
976     }
977 
978     public void setVersion( String version )
979     {
980         this.version = version;
981     }
982 
983     public ChangesXML getXml()
984     {
985         return xml;
986     }
987 
988     public void setXml( ChangesXML xml )
989     {
990         this.xml = xml;
991     }
992 
993     public File getXmlPath()
994     {
995         return xmlPath;
996     }
997 
998     public void setXmlPath( File xmlPath )
999     {
1000         this.xmlPath = xmlPath;
1001     }
1002 }