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