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 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.github.GitHubDownloader;
37  import org.apache.maven.plugin.github.GitHubIssueManagementSystem;
38  import org.apache.maven.plugin.issues.Issue;
39  import org.apache.maven.plugin.issues.IssueManagementSystem;
40  import org.apache.maven.plugin.issues.IssueUtils;
41  import org.apache.maven.plugin.jira.AbstractJiraDownloader;
42  import org.apache.maven.plugin.jira.AdaptiveJiraDownloader;
43  import org.apache.maven.plugin.jira.JIRAIssueManagmentSystem;
44  import org.apache.maven.plugin.trac.TracDownloader;
45  import org.apache.maven.plugin.trac.TracIssueManagmentSystem;
46  import org.apache.maven.plugins.annotations.Component;
47  import org.apache.maven.plugins.annotations.Mojo;
48  import org.apache.maven.plugins.annotations.Parameter;
49  import org.apache.maven.plugins.changes.model.Release;
50  import org.apache.maven.project.MavenProject;
51  import org.apache.maven.settings.Settings;
52  import org.apache.velocity.Template;
53  import org.apache.velocity.app.VelocityEngine;
54  import org.apache.velocity.context.Context;
55  import org.apache.velocity.exception.ResourceNotFoundException;
56  import org.apache.velocity.exception.VelocityException;
57  import org.apache.velocity.tools.ToolManager;
58  import org.codehaus.plexus.util.ReaderFactory;
59  import org.codehaus.plexus.util.StringUtils;
60  import org.codehaus.plexus.velocity.VelocityComponent;
61  
62  /**
63   * Goal which generate an announcement from the announcement template.
64   *
65   * @author aramirez@exist.com
66   * @version $Id: AnnouncementMojo.java 1765156 2016-10-16 13:54:35Z gboue $
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                 String message = ProjectUtils.validateIssueManagement( project, JIRA, "JIRA announcement" );
528                 if ( message == null )
529                 {
530                     List<Release> jiraReleases = getJiraReleases();
531                     releases = releaseUtils.mergeReleases( releases, jiraReleases );
532                     getLog().info( "Including issues from JIRA in announcement..." );
533                 }
534                 else
535                 {
536                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
537                         + message );
538                 }
539             }
540 
541             if ( issueManagementSystems.contains( TRAC ) )
542             {
543                 String message = ProjectUtils.validateIssueManagement( project, TRAC, "Trac announcement" );
544                 if ( message == null )
545                 {
546                     List<Release> tracReleases = getTracReleases();
547                     releases = releaseUtils.mergeReleases( releases, tracReleases );
548                     getLog().info( "Including issues from Trac in announcement..." );
549                 }
550                 else
551                 {
552                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
553                                     + message );
554                 }
555             }
556 
557             if ( issueManagementSystems.contains( GIT_HUB ) )
558             {
559                 String message = ProjectUtils.validateIssueManagement( project, GIT_HUB, "GitHub announcement" );
560                 if ( message == null )
561                 {
562                     List<Release> gitHubReleases = getGitHubReleases();
563                     releases = releaseUtils.mergeReleases( releases, gitHubReleases );
564                     getLog().info( "Including issues from GitHub in announcement..." );
565                 }
566                 else
567                 {
568                     throw new MojoExecutionException( "Something is wrong with the Issue Management section. "
569                                     + message );
570                 }
571             }
572 
573             // @todo Add more issue management systems here.
574 
575             // Follow these steps:
576             // 1. Add a constant for the name of the issue management system
577             // 2. Add the @parameters needed to configure the issue management system
578             // 3. Add a protected List get<IMSname>Releases() method that retrieves a list of releases
579             // 4. Merge those releases into the "releases" variable
580             // For help with these steps, you can have a look at how this has been done for JIRA or Trac
581 
582             // Generate the report
583             if ( releases == null || releases.isEmpty() )
584             {
585                 throw new MojoExecutionException( "No releases found in any of the "
586                     + "configured issue management systems." );
587             }
588             else
589             {
590                 doGenerate( releases );
591             }
592         }
593     }
594 
595     /**
596      * Add the parameters to velocity context
597      *
598      * @param releases A <code>List</code> of <code>Release</code>s
599      * @throws MojoExecutionException
600      */
601     public void doGenerate( List<Release> releases )
602         throws MojoExecutionException
603     {
604         String version = ( versionPrefix == null ? "" : versionPrefix ) + getVersion();
605 
606         getLog().debug( "Generating announcement for version [" + version + "]. Found these releases: "
607             + ReleaseUtils.toString( releases ) );
608 
609         doGenerate( releases, releaseUtils.getLatestRelease( releases, version ) );
610     }
611 
612     protected void doGenerate( List<Release> releases, Release release )
613         throws MojoExecutionException
614     {
615         try
616         {
617             ToolManager toolManager = new ToolManager( true );
618             Context context = toolManager.createContext();
619 
620             if ( getIntroduction() == null || getIntroduction().equals( "" ) )
621             {
622                 setIntroduction( getUrl() );
623             }
624 
625             context.put( "releases", releases );
626 
627             context.put( "groupId", getGroupId() );
628 
629             context.put( "artifactId", getArtifactId() );
630 
631             context.put( "version", getVersion() );
632 
633             context.put( "packaging", getPackaging() );
634 
635             context.put( "url", getUrl() );
636 
637             context.put( "release", release );
638 
639             context.put( "introduction", getIntroduction() );
640 
641             context.put( "developmentTeam", getDevelopmentTeam() );
642 
643             context.put( "finalName", getFinalName() );
644 
645             context.put( "urlDownload", getUrlDownload() );
646 
647             context.put( "project", project );
648 
649             if ( announceParameters == null )
650             {
651                 // empty Map to prevent NPE in velocity execution
652                 context.put( "announceParameters", Collections.EMPTY_MAP );
653             }
654             else
655             {
656                 context.put( "announceParameters", announceParameters );
657             }
658 
659             processTemplate( context, announcementDirectory, template, announcementFile );
660         }
661         catch ( ResourceNotFoundException rnfe )
662         {
663             throw new MojoExecutionException( "Resource not found.", rnfe );
664         }
665         catch ( VelocityException ve )
666         {
667             throw new MojoExecutionException( ve.toString(), ve );
668         }
669     }
670 
671     /**
672      * Create the velocity template
673      *
674      * @param context velocity context that has the parameter values
675      * @param outputDirectory directory where the file will be generated
676      * @param template velocity template which will the context be merged
677      * @param announcementFile The file name of the generated announcement
678      * @throws ResourceNotFoundException, VelocityException, IOException
679      */
680     public void processTemplate( Context context, File outputDirectory, String template, String announcementFile )
681         throws VelocityException, MojoExecutionException
682     {
683         File f;
684 
685         // Use the name of the template as a default value
686         if ( StringUtils.isEmpty( announcementFile ) )
687         {
688             announcementFile = template;
689         }
690 
691         try
692         {
693             f = new File( outputDirectory, announcementFile );
694 
695             if ( !f.getParentFile().exists() )
696             {
697                 f.getParentFile().mkdirs();
698             }
699 
700             VelocityEngine engine = velocity.getEngine();
701 
702             engine.setApplicationAttribute( "baseDirectory", basedir );
703 
704             if ( StringUtils.isEmpty( templateEncoding ) )
705             {
706                 templateEncoding = ReaderFactory.FILE_ENCODING;
707                 getLog().warn( "File encoding has not been set, using platform encoding " + templateEncoding
708                     + ", i.e. build is platform dependent!" );
709             }
710 
711             Writer writer = new OutputStreamWriter( new FileOutputStream( f ), templateEncoding );
712 
713             Template velocityTemplate = engine.getTemplate( templateDirectory + "/" + template, templateEncoding );
714 
715             velocityTemplate.merge( context, writer );
716 
717             writer.flush();
718 
719             writer.close();
720 
721             getLog().info( "Created template " + f );
722         }
723 
724         catch ( ResourceNotFoundException rnfe )
725         {
726             throw new ResourceNotFoundException( "Template not found. ( " + templateDirectory + "/" + template + " )" );
727         }
728         catch ( VelocityException ve )
729         {
730             throw new VelocityException( ve.toString() );
731         }
732 
733         catch ( Exception e )
734         {
735             if ( e.getCause() != null )
736             {
737                 getLog().warn( e.getCause() );
738             }
739             throw new MojoExecutionException( e.toString(), e.getCause() );
740         }
741     }
742 
743     protected List<Release> getJiraReleases()
744         throws MojoExecutionException
745     {
746         AbstractJiraDownloader jiraDownloader = new AdaptiveJiraDownloader();
747 
748         File jiraXMLFile = jiraXML;
749 
750         jiraDownloader.setLog( getLog() );
751 
752         jiraDownloader.setOutput( jiraXMLFile );
753 
754         jiraDownloader.setStatusIds( statusIds );
755 
756         jiraDownloader.setResolutionIds( resolutionIds );
757 
758         jiraDownloader.setMavenProject( project );
759 
760         jiraDownloader.setSettings( settings );
761 
762         jiraDownloader.setNbEntries( maxEntries );
763 
764         jiraDownloader.setFilter( filter );
765 
766         jiraDownloader.setJiraUser( jiraUser );
767 
768         jiraDownloader.setJiraPassword( jiraPassword );
769 
770         jiraDownloader.setUseJql( useJql );
771 
772         jiraDownloader.setWebUser( webUser );
773 
774         jiraDownloader.setWebPassword( webPassword );
775 
776         jiraDownloader.setConnectionTimeout( jiraConnectionTimeout );
777 
778         jiraDownloader.setReceiveTimout( jiraReceiveTimout );
779 
780         try
781         {
782             jiraDownloader.doExecute();
783 
784             List<Issue> issueList = jiraDownloader.getIssueList();
785 
786             if ( StringUtils.isNotEmpty( versionPrefix ) )
787             {
788                 int originalNumberOfIssues = issueList.size();
789                 issueList = IssueUtils.filterIssuesWithVersionPrefix( issueList, versionPrefix );
790                 getLog().debug( "Filtered out " + issueList.size() + " issues of " + originalNumberOfIssues
791                     + " that matched the versionPrefix '" + versionPrefix + "'." );
792             }
793 
794             return getReleases( issueList, new JIRAIssueManagmentSystem() );
795         }
796         catch ( Exception e )
797         {
798             throw new MojoExecutionException( "Failed to extract issues from JIRA.", e );
799         }
800     }
801 
802     private List<Release> getReleases( List<Issue> issues, IssueManagementSystem ims )
803         throws MojoExecutionException
804     {
805         if ( issueTypes != null )
806         {
807             ims.applyConfiguration( issueTypes );
808         }
809         if ( issues.isEmpty() )
810         {
811             return Collections.emptyList();
812         }
813         else
814         {
815             IssueAdapter adapter = new IssueAdapter( ims );
816             return adapter.getReleases( issues );
817         }
818     }
819 
820     protected List<Release> getTracReleases()
821         throws MojoExecutionException
822     {
823         TracDownloader issueDownloader = new TracDownloader();
824 
825         issueDownloader.setProject( project );
826 
827         issueDownloader.setQuery( tracQuery );
828 
829         issueDownloader.setTracPassword( tracPassword );
830 
831         issueDownloader.setTracUser( tracUser );
832 
833         try
834         {
835             return getReleases( issueDownloader.getIssueList(), new TracIssueManagmentSystem() );
836         }
837         catch ( Exception e )
838         {
839             throw new MojoExecutionException( "Failed to extract issues from Trac.", e );
840         }
841     }
842 
843     protected List<Release> getGitHubReleases()
844         throws MojoExecutionException
845     {
846         try
847         {
848             GitHubDownloader issueDownloader =
849                 new GitHubDownloader( project, githubAPIScheme, githubAPIPort, includeOpenIssues, true );
850 
851             issueDownloader.configureAuthentication( githubAPIServerId, settings, getLog() );
852 
853             return getReleases( issueDownloader.getIssueList(), new GitHubIssueManagementSystem() );
854         }
855         catch ( Exception e )
856         {
857             throw new MojoExecutionException( "Failed to extract issues from GitHub.", e );
858         }
859     }
860 
861     /*
862      * accessors
863      */
864 
865     public String getArtifactId()
866     {
867         return artifactId;
868     }
869 
870     public void setArtifactId( String artifactId )
871     {
872         this.artifactId = artifactId;
873     }
874 
875     public String getDevelopmentTeam()
876     {
877         return developmentTeam;
878     }
879 
880     public void setDevelopmentTeam( String developmentTeam )
881     {
882         this.developmentTeam = developmentTeam;
883     }
884 
885     public String getFinalName()
886     {
887         return finalName;
888     }
889 
890     public void setFinalName( String finalName )
891     {
892         this.finalName = finalName;
893     }
894 
895     public String getGroupId()
896     {
897         return groupId;
898     }
899 
900     public void setGroupId( String groupId )
901     {
902         this.groupId = groupId;
903     }
904 
905     public String getIntroduction()
906     {
907         return introduction;
908     }
909 
910     public void setIntroduction( String introduction )
911     {
912         this.introduction = introduction;
913     }
914 
915     public void setIssueTypes( Map<String, String> issueTypes )
916     {
917         this.issueTypes = issueTypes;
918     }
919 
920     public Map<String, String> getIssueTypes()
921     {
922         return issueTypes;
923     }
924 
925     public File getAnnouncementDirectory()
926     {
927         return announcementDirectory;
928     }
929 
930     public void setAnnouncementDirectory( File announcementDirectory )
931     {
932         this.announcementDirectory = announcementDirectory;
933     }
934 
935     public String getPackaging()
936     {
937         return packaging;
938     }
939 
940     public void setPackaging( String packaging )
941     {
942         this.packaging = packaging;
943     }
944 
945     public String getUrl()
946     {
947         return url;
948     }
949 
950     public void setUrl( String url )
951     {
952         this.url = url;
953     }
954 
955     public String getUrlDownload()
956     {
957         return urlDownload;
958     }
959 
960     public void setUrlDownload( String urlDownload )
961     {
962         this.urlDownload = urlDownload;
963     }
964 
965     public VelocityComponent getVelocity()
966     {
967         return velocity;
968     }
969 
970     public void setVelocity( VelocityComponent velocity )
971     {
972         this.velocity = velocity;
973     }
974 
975     public String getVersion()
976     {
977         return version;
978     }
979 
980     public void setVersion( String version )
981     {
982         this.version = version;
983     }
984 
985     public ChangesXML getXml()
986     {
987         return xml;
988     }
989 
990     public void setXml( ChangesXML xml )
991     {
992         this.xml = xml;
993     }
994 
995     public File getXmlPath()
996     {
997         return xmlPath;
998     }
999 
1000     public void setXmlPath( File xmlPath )
1001     {
1002         this.xmlPath = xmlPath;
1003     }
1004 }