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