View Javadoc

1   package org.apache.maven.plugin.changes;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.List;
6   
7   import org.apache.maven.plugin.AbstractMojo;
8   import org.apache.maven.plugin.MojoExecutionException;
9   
10  /**
11   * Display help information on maven-changes-plugin.<br/> Call <pre>  mvn changes:help -Ddetail=true -Dgoal=&lt;goal-name&gt;</pre> to display parameter details.
12   *
13   * @version generated on Fri Apr 27 08:29:00 EDT 2012
14   * @author org.apache.maven.tools.plugin.generator.PluginHelpGenerator (version 2.8)
15   * @goal help
16   * @requiresProject false
17   * @threadSafe
18   */
19  @SuppressWarnings( "all" )
20  public class HelpMojo
21      extends AbstractMojo
22  {
23      /**
24       * If <code>true</code>, display all settable properties for each goal.
25       * 
26       * @parameter expression="${detail}" default-value="false"
27       */
28      private boolean detail;
29  
30      /**
31       * The name of the goal for which to show help. If unspecified, all goals will be displayed.
32       * 
33       * @parameter expression="${goal}"
34       */
35      private java.lang.String goal;
36  
37      /**
38       * The maximum length of a display line, should be positive.
39       * 
40       * @parameter expression="${lineLength}" default-value="80"
41       */
42      private int lineLength;
43  
44      /**
45       * The number of spaces per indentation level, should be positive.
46       * 
47       * @parameter expression="${indentSize}" default-value="2"
48       */
49      private int indentSize;
50  
51  
52      /** {@inheritDoc} */
53      public void execute()
54          throws MojoExecutionException
55      {
56          if ( lineLength <= 0 )
57          {
58              getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
59              lineLength = 80;
60          }
61          if ( indentSize <= 0 )
62          {
63              getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
64              indentSize = 2;
65          }
66  
67          StringBuffer sb = new StringBuffer();
68  
69          append( sb, "org.apache.maven.plugins:maven-changes-plugin:2.7", 0 );
70          append( sb, "", 0 );
71  
72          append( sb, "Maven Changes Report Plugin", 0 );
73          append( sb, "Creates a release history for inclusion into the site and assists in generating an announcement mail.", 1 );
74          append( sb, "", 0 );
75  
76          if ( goal == null || goal.length() <= 0 )
77          {
78              append( sb, "This plugin has 8 goals:", 0 );
79              append( sb, "", 0 );
80          }
81  
82          if ( goal == null || goal.length() <= 0 || "announcement-generate".equals( goal ) )
83          {
84              append( sb, "changes:announcement-generate", 0 );
85              append( sb, "Goal which generate the template for an announcement.", 1 );
86              append( sb, "", 0 );
87              if ( detail )
88              {
89                  append( sb, "Available parameters:", 1 );
90                  append( sb, "", 0 );
91  
92                  append( sb, "announcementFile", 2 );
93                  append( sb, "The name of the file which will contain the generated announcement. If no value is specified the plugin will use the name of the template.", 3 );
94                  append( sb, "Expression: ${changes.announcementFile}", 3 );
95                  append( sb, "", 0 );
96  
97                  append( sb, "announceParameters", 2 );
98                  append( sb, "Map of custom parameters for the announcement. This Map will be passed to the template.", 3 );
99                  append( sb, "", 0 );
100 
101                 append( sb, "basedir", 2 );
102                 append( sb, "The current project base directory.", 3 );
103                 append( sb, "Required: Yes", 3 );
104                 append( sb, "Expression: ${basedir}", 3 );
105                 append( sb, "", 0 );
106 
107                 append( sb, "developmentTeam (Default: ${project.name} team)", 2 );
108                 append( sb, "Name of the team that develops the artifact. This parameter will be passed to the template.", 3 );
109                 append( sb, "Required: Yes", 3 );
110                 append( sb, "Expression: ${changes.developmentTeam}", 3 );
111                 append( sb, "", 0 );
112 
113                 append( sb, "filter", 2 );
114                 append( sb, "Defines the filter parameters to restrict which issues are retrieved from JIRA. The filter parameter uses the same format of url parameters that is used in a JIRA search.", 3 );
115                 append( sb, "", 0 );
116 
117                 append( sb, "finalName (Default: ${project.build.finalName})", 2 );
118                 append( sb, "The name of the artifact to be used in the announcement.", 3 );
119                 append( sb, "Required: Yes", 3 );
120                 append( sb, "Expression: ${changes.finalName}", 3 );
121                 append( sb, "", 0 );
122 
123                 append( sb, "generateJiraAnnouncement (Default: false)", 2 );
124                 append( sb, "Deprecated. Since version 2.4 this parameter has been deprecated. Please use the issueManagementSystems parameter instead.", 3 );
125                 append( sb, "", 0 );
126                 append( sb, "Flag to determine if the plugin will generate a JIRA announcement.", 3 );
127                 append( sb, "Required: Yes", 3 );
128                 append( sb, "Expression: ${generateJiraAnnouncement}", 3 );
129                 append( sb, "", 0 );
130 
131                 append( sb, "introduction (Default: ${project.description})", 2 );
132                 append( sb, "Short description or introduction of the released artifact. This parameter will be passed to the template.", 3 );
133                 append( sb, "", 0 );
134 
135                 append( sb, "issueManagementSystems", 2 );
136                 append( sb, "A list of issue management systems to fetch releases from. This parameter replaces the parameters generateJiraAnnouncement and jiraMerge.\nValid values are: changes.xml and JIRA.\nNote: Only one issue management system that is configured in <project>/<issueManagement> can be used. This currently means that you can combine a changes.xml file with one other issue management system.", 3 );
137                 append( sb, "", 0 );
138 
139                 append( sb, "issueTypes", 2 );
140                 append( sb, "Maps issues types to action types for grouping issues in announcements. If issue types are not defined for a action type then the default issue type will be applied.\nValid action types: add, fix and update.\n", 3 );
141                 append( sb, "", 0 );
142 
143                 append( sb, "jiraMerge (Default: false)", 2 );
144                 append( sb, "Deprecated. Since version 2.4 this parameter has been deprecated. Please use the issueManagementSystems parameter instead.", 3 );
145                 append( sb, "", 0 );
146                 append( sb, "If releases from JIRA should be merged with the releases from a changes.xml file.", 3 );
147                 append( sb, "Expression: ${changes.jiraMerge}", 3 );
148                 append( sb, "", 0 );
149 
150                 append( sb, "jiraPassword", 2 );
151                 append( sb, "Defines the JIRA password for authentication into a private JIRA installation.", 3 );
152                 append( sb, "Expression: ${changes.jiraPassword}", 3 );
153                 append( sb, "", 0 );
154 
155                 append( sb, "jiraUser", 2 );
156                 append( sb, "Defines the JIRA username for authentication into a private JIRA installation.", 3 );
157                 append( sb, "Expression: ${changes.jiraUser}", 3 );
158                 append( sb, "", 0 );
159 
160                 append( sb, "maxEntries (Default: 25)", 2 );
161                 append( sb, "The maximum number of issues to fetch from JIRA.\nNote: In versions 2.0-beta-3 and earlier this parameter was called \'nbEntries\'.\n", 3 );
162                 append( sb, "Required: Yes", 3 );
163                 append( sb, "Expression: ${changes.maxEntries}", 3 );
164                 append( sb, "", 0 );
165 
166                 append( sb, "outputDirectory", 2 );
167                 append( sb, "Directory where the template file will be generated.", 3 );
168                 append( sb, "Required: Yes", 3 );
169                 append( sb, "Expression: ${project.build.directory}/announcement", 3 );
170                 append( sb, "", 0 );
171 
172                 append( sb, "resolutionIds (Default: Fixed)", 2 );
173                 append( sb, "Include issues from JIRA with these resolution ids. Multiple resolution ids can be specified as a comma separated list of ids.\nNote: In versions 2.0-beta-3 and earlier this parameter was called \'resolutionId\'.\n", 3 );
174                 append( sb, "Expression: ${changes.resolutionIds}", 3 );
175                 append( sb, "", 0 );
176 
177                 append( sb, "runOnlyAtExecutionRoot (Default: false)", 2 );
178                 append( sb, "This will cause the execution to be run only at the top of a given module tree. That is, run in the project contained in the same folder where the mvn execution was launched.", 3 );
179                 append( sb, "Expression: ${announcement.runOnlyAtExecutionRoot}", 3 );
180                 append( sb, "", 0 );
181 
182                 append( sb, "statusIds (Default: Closed)", 2 );
183                 append( sb, "Include issues from JIRA with these status ids. Multiple status ids can be specified as a comma separated list of ids.\nNote: In versions 2.0-beta-3 and earlier this parameter was called \'statusId\'.\n", 3 );
184                 append( sb, "Expression: ${changes.statusIds}", 3 );
185                 append( sb, "", 0 );
186 
187                 append( sb, "template (Default: announcement.vm)", 2 );
188                 append( sb, "The Velocity template used to format the announcement.", 3 );
189                 append( sb, "Required: Yes", 3 );
190                 append( sb, "Expression: ${changes.template}", 3 );
191                 append( sb, "", 0 );
192 
193                 append( sb, "templateDirectory (Default: org/apache/maven/plugin/announcement)", 2 );
194                 append( sb, "Directory that contains the template.\nNote: This directory must be a subdirectory of /src/main/resources/ or current project base directory.\n", 3 );
195                 append( sb, "Required: Yes", 3 );
196                 append( sb, "Expression: ${changes.templateDirectory}", 3 );
197                 append( sb, "", 0 );
198 
199                 append( sb, "templateEncoding (Default: ${project.build.sourceEncoding})", 2 );
200                 append( sb, "The template encoding.", 3 );
201                 append( sb, "Expression: ${changes.templateEncoding}", 3 );
202                 append( sb, "", 0 );
203 
204                 append( sb, "tracPassword", 2 );
205                 append( sb, "Defines the Trac password for authentication into a private Trac installation.", 3 );
206                 append( sb, "Expression: ${changes.tracPassword}", 3 );
207                 append( sb, "", 0 );
208 
209                 append( sb, "tracQuery (Default: order=id)", 2 );
210                 append( sb, "Defines the Trac query for searching for tickets.", 3 );
211                 append( sb, "", 0 );
212 
213                 append( sb, "tracUser", 2 );
214                 append( sb, "Defines the Trac username for authentication into a private Trac installation.", 3 );
215                 append( sb, "Expression: ${changes.tracUser}", 3 );
216                 append( sb, "", 0 );
217 
218                 append( sb, "url", 2 );
219                 append( sb, "Distribution URL of the artifact. This parameter will be passed to the template.", 3 );
220                 append( sb, "Expression: ${project.url}", 3 );
221                 append( sb, "", 0 );
222 
223                 append( sb, "urlDownload", 2 );
224                 append( sb, "URL where the artifact can be downloaded. If not specified, no URL is used. This parameter will be passed to the template.", 3 );
225                 append( sb, "", 0 );
226 
227                 append( sb, "version (Default: ${project.version})", 2 );
228                 append( sb, "Version of the artifact.", 3 );
229                 append( sb, "Required: Yes", 3 );
230                 append( sb, "Expression: ${changes.version}", 3 );
231                 append( sb, "", 0 );
232 
233                 append( sb, "versionPrefix", 2 );
234                 append( sb, "The prefix used when naming versions in JIRA.\nIf you have a project in JIRA with several components that have different release cycles, it is an often used pattern to prefix the version with the name of the component, e.g. maven-filtering-1.0 etc. To fetch issues from JIRA for a release of the \'maven-filtering\' component you would need to set this parameter to \'maven-filtering-\'.\n", 3 );
235                 append( sb, "Expression: ${changes.versionPrefix}", 3 );
236                 append( sb, "", 0 );
237 
238                 append( sb, "webPassword", 2 );
239                 append( sb, "Defines the http password for basic authentication into the JIRA webserver.", 3 );
240                 append( sb, "Expression: ${changes.webPassword}", 3 );
241                 append( sb, "", 0 );
242 
243                 append( sb, "webUser", 2 );
244                 append( sb, "Defines the http user for basic authentication into the JIRA webserver.", 3 );
245                 append( sb, "Expression: ${changes.webUser}", 3 );
246                 append( sb, "", 0 );
247 
248                 append( sb, "xmlPath", 2 );
249                 append( sb, "The path of the changes.xml file.", 3 );
250                 append( sb, "Required: Yes", 3 );
251                 append( sb, "Expression: ${basedir}/src/changes/changes.xml", 3 );
252                 append( sb, "", 0 );
253             }
254         }
255 
256         if ( goal == null || goal.length() <= 0 || "announcement-mail".equals( goal ) )
257         {
258             append( sb, "changes:announcement-mail", 0 );
259             append( sb, "Goal which sends an announcement through email.", 1 );
260             append( sb, "", 0 );
261             if ( detail )
262             {
263                 append( sb, "Available parameters:", 1 );
264                 append( sb, "", 0 );
265 
266                 append( sb, "basedir", 2 );
267                 append( sb, "The current project base directory.", 3 );
268                 append( sb, "Required: Yes", 3 );
269                 append( sb, "Expression: ${basedir}", 3 );
270                 append( sb, "", 0 );
271 
272                 append( sb, "bccAddresses", 2 );
273                 append( sb, "Recipient bcc email address.", 3 );
274                 append( sb, "", 0 );
275 
276                 append( sb, "ccAddresses", 2 );
277                 append( sb, "Recipient cc email address.", 3 );
278                 append( sb, "", 0 );
279 
280                 append( sb, "fromDeveloperId", 2 );
281                 append( sb, "The id of the developer sending the announcement mail. Only used if the mailSender attribute is not set. In this case, this should match the id of one of the developers in the pom. If a matching developer is not found, then the first developer in the pom will be used.", 3 );
282                 append( sb, "Expression: ${changes.fromDeveloperId}", 3 );
283                 append( sb, "", 0 );
284 
285                 append( sb, "mailContentType (Default: text/plain)", 2 );
286                 append( sb, "Mail content type to use.", 3 );
287                 append( sb, "Required: Yes", 3 );
288                 append( sb, "", 0 );
289 
290                 append( sb, "mailSender", 2 );
291                 append( sb, "Defines the sender of the announcement email. This takes precedence over the list of developers specified in the POM. if the sender is not a member of the development team. Note that since this is a bean type, you cannot specify it from command level with\n-D\n. Use\n-Dchanges.sender=\'Your\u00a0Name\u00a0<you@domain>\'\ninstead.", 3 );
292                 append( sb, "Expression: ${changes.mailSender}", 3 );
293                 append( sb, "", 0 );
294 
295                 append( sb, "password", 2 );
296                 append( sb, "The password used to send the email.", 3 );
297                 append( sb, "Expression: ${changes.password}", 3 );
298                 append( sb, "", 0 );
299 
300                 append( sb, "runOnlyAtExecutionRoot (Default: false)", 2 );
301                 append( sb, "This will cause the execution to be run only at the top of a given module tree. That is, run in the project contained in the same folder where the mvn execution was launched.", 3 );
302                 append( sb, "Expression: ${announcement.runOnlyAtExecutionRoot}", 3 );
303                 append( sb, "", 0 );
304 
305                 append( sb, "senderString", 2 );
306                 append( sb, "Defines the sender of the announcement. This takes precedence over both ${changes.mailSender} and the list of developers in the POM. This parameter parses an email address in standard RFC822 format, e.g.\n-Dchanges.sender=\'Your\u00a0Name\u00a0<you@domain>\'\n.", 3 );
307                 append( sb, "Expression: ${changes.sender}", 3 );
308                 append( sb, "", 0 );
309 
310                 append( sb, "smtpHost", 2 );
311                 append( sb, "Smtp Server.", 3 );
312                 append( sb, "Required: Yes", 3 );
313                 append( sb, "Expression: ${changes.smtpHost}", 3 );
314                 append( sb, "", 0 );
315 
316                 append( sb, "smtpPort (Default: 25)", 2 );
317                 append( sb, "Port.", 3 );
318                 append( sb, "Required: Yes", 3 );
319                 append( sb, "Expression: ${changes.smtpPort}", 3 );
320                 append( sb, "", 0 );
321 
322                 append( sb, "sslMode (Default: false)", 2 );
323                 append( sb, "If the email should be sent in SSL mode.", 3 );
324                 append( sb, "Expression: ${changes.sslMode}", 3 );
325                 append( sb, "", 0 );
326 
327                 append( sb, "subject (Default: [ANNOUNCEMENT] - ${project.name} ${project.version} released)", 2 );
328                 append( sb, "Subject for the email.", 3 );
329                 append( sb, "Required: Yes", 3 );
330                 append( sb, "Expression: ${changes.subject}", 3 );
331                 append( sb, "", 0 );
332 
333                 append( sb, "template (Default: announcement.vm)", 2 );
334                 append( sb, "The Velocity template used to format the announcement.", 3 );
335                 append( sb, "Required: Yes", 3 );
336                 append( sb, "Expression: ${changes.template}", 3 );
337                 append( sb, "", 0 );
338 
339                 append( sb, "templateOutputDirectory", 2 );
340                 append( sb, "Directory which contains the template for announcement email.", 3 );
341                 append( sb, "Required: Yes", 3 );
342                 append( sb, "Expression: ${project.build.directory}/announcement", 3 );
343                 append( sb, "", 0 );
344 
345                 append( sb, "toAddresses", 2 );
346                 append( sb, "Recipient email address.", 3 );
347                 append( sb, "Required: Yes", 3 );
348                 append( sb, "", 0 );
349 
350                 append( sb, "username", 2 );
351                 append( sb, "The username used to send the email.", 3 );
352                 append( sb, "Expression: ${changes.username}", 3 );
353                 append( sb, "", 0 );
354             }
355         }
356 
357         if ( goal == null || goal.length() <= 0 || "changes-check".equals( goal ) )
358         {
359             append( sb, "changes:changes-check", 0 );
360             append( sb, "Goal which checks that the changes.xml file has the necessary data to generate an announcement or a report for the current release.", 1 );
361             append( sb, "", 0 );
362             if ( detail )
363             {
364                 append( sb, "Available parameters:", 1 );
365                 append( sb, "", 0 );
366 
367                 append( sb, "releaseDateFormat (Default: yyyy-MM-dd)", 2 );
368                 append( sb, "The format that a correct release date should have. This value will be used as a pattern to try to create a date.", 3 );
369                 append( sb, "Expression: ${changes.releaseDateFormat}", 3 );
370                 append( sb, "", 0 );
371 
372                 append( sb, "skipSnapshots (Default: false)", 2 );
373                 append( sb, "Flag controlling snapshot processing. If set, versions ending with -SNAPSHOT won\'t be checked.", 3 );
374                 append( sb, "Expression: ${changes.skipSnapshots}", 3 );
375                 append( sb, "", 0 );
376 
377                 append( sb, "version (Default: ${project.version})", 2 );
378                 append( sb, "Version of the artifact.", 3 );
379                 append( sb, "Required: Yes", 3 );
380                 append( sb, "Expression: ${changes.version}", 3 );
381                 append( sb, "", 0 );
382 
383                 append( sb, "xmlPath (Default: src/changes/changes.xml)", 2 );
384                 append( sb, "The path of the changes.xml file that will be checked.", 3 );
385                 append( sb, "Expression: ${changes.xmlPath}", 3 );
386                 append( sb, "", 0 );
387             }
388         }
389 
390         if ( goal == null || goal.length() <= 0 || "changes-report".equals( goal ) )
391         {
392             append( sb, "changes:changes-report", 0 );
393             append( sb, "Goal which creates a nicely formatted Changes Report in html format from a changes.xml file.", 1 );
394             append( sb, "", 0 );
395             if ( detail )
396             {
397                 append( sb, "Available parameters:", 1 );
398                 append( sb, "", 0 );
399 
400                 append( sb, "addActionDate (Default: false)", 2 );
401                 append( sb, "A flag whether the report should also include the dates of individual actions. If set to false, only the dates of releases will be written to the report.", 3 );
402                 append( sb, "Expression: ${changes.addActionDate}", 3 );
403                 append( sb, "", 0 );
404 
405                 append( sb, "aggregated (Default: false)", 2 );
406                 append( sb, "A flag whether the report should also include changes from child modules. If set to false, only the changes from current project will be written to the report.", 3 );
407                 append( sb, "", 0 );
408 
409                 append( sb, "escapeHTML (Default: true)", 2 );
410                 append( sb, "Deprecated. using markup inside CDATA sections does not work for all output formats!", 3 );
411                 append( sb, "", 0 );
412                 append( sb, "Whether HTML code within an action should be escaped. By changing this to false you can restore the behavior that was in version 2.2 of this plugin, allowing you to use HTML code to format the content of an action.\nNote: If you use HTML code in an action you need to place it inside a CDATA section.\nNote: Putting any kind of markup inside a CDATA section might mess up the Changes Report or other generated documents, such as PDFs, that are based on your changes.xml file if you are not careful.", 3 );
413                 append( sb, "", 0 );
414 
415                 append( sb, "filteringChanges (Default: false)", 2 );
416                 append( sb, "applying filtering filtering \'a la\' resources plugin", 3 );
417                 append( sb, "", 0 );
418 
419                 append( sb, "issueLinkTemplate (Default: %URL%/ViewIssue.jspa?key=%ISSUE%)", 2 );
420                 append( sb, "Deprecated. As of 2.1 use issueLinkTemplatePerSystem : this one will be with system default", 3 );
421                 append( sb, "", 0 );
422                 append( sb, "Template string that is used to discover the URL to use to display an issue report. There are 2 template tokens you can use. %URL%: this is computed by getting the <issueManagement>/<url> value from the POM, and removing the last \'/\' and everything that comes after it. %ISSUE%: this is the issue number.\nNote: In versions of this plugin prior to 2.0-beta-2 this parameter was called link_template.\n", 3 );
423                 append( sb, "Expression: ${changes.issueLinkTemplate}", 3 );
424                 append( sb, "", 0 );
425 
426                 append( sb, "issueLinkTemplatePerSystem", 2 );
427                 append( sb, "Template strings per system that is used to discover the URL to use to display an issue report. Each key in this map denotes the (case-insensitive) identifier of the issue tracking system and its value gives the URL template.\nThere are 2 template tokens you can use. %URL%: this is computed by getting the <issueManagement>/<url> value from the POM, and removing the last \'/\' and everything that comes after it. %ISSUE%: this is the issue number.\n\nNote: The deprecated issueLinkTemplate will be used for a system called \'default\'.\n\nNote: Starting with version 2.4 you usually don\'t need to specify this, unless you need to link to an issue management system in your Changes report that isn\'t supported out of the box. See the Usage page for more information.\n", 3 );
428                 append( sb, "", 0 );
429 
430                 append( sb, "outputDirectory (Default: ${project.reporting.outputDirectory})", 2 );
431                 append( sb, "Report output directory. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output directory configured in the Maven Site Plugin is used instead.", 3 );
432                 append( sb, "", 0 );
433 
434                 append( sb, "outputEncoding (Default: ${project.reporting.outputEncoding})", 2 );
435                 append( sb, "Report output encoding. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output encoding configured in the Maven Site Plugin is used instead.", 3 );
436                 append( sb, "Expression: ${outputEncoding}", 3 );
437                 append( sb, "", 0 );
438 
439                 append( sb, "publishDateFormat (Default: yyyy-MM-dd)", 2 );
440                 append( sb, "Format to use for publishDate. The value will be available with the following expression ${publishDate}", 3 );
441                 append( sb, "", 0 );
442 
443                 append( sb, "publishDateLocale (Default: en)", 2 );
444                 append( sb, "Locale to use for publishDate when formatting", 3 );
445                 append( sb, "", 0 );
446 
447                 append( sb, "teamlist (Default: team-list.html)", 2 );
448                 append( sb, "The URI of a file containing all the team members. If this is set to the special value \'none\', no links will be generated for the team members.", 3 );
449                 append( sb, "", 0 );
450 
451                 append( sb, "xmlPath (Default: src/changes/changes.xml)", 2 );
452                 append( sb, "The path of the changes.xml file that will be converted into an HTML report.", 3 );
453                 append( sb, "Expression: ${changes.xmlPath}", 3 );
454                 append( sb, "", 0 );
455             }
456         }
457 
458         if ( goal == null || goal.length() <= 0 || "changes-validate".equals( goal ) )
459         {
460             append( sb, "changes:changes-validate", 0 );
461             append( sb, "Goal which validate the changes.xml file.", 1 );
462             append( sb, "", 0 );
463             if ( detail )
464             {
465                 append( sb, "Available parameters:", 1 );
466                 append( sb, "", 0 );
467 
468                 append( sb, "changesXsdVersion (Default: 1.0.0)", 2 );
469                 append( sb, "The changes xsd version.", 3 );
470                 append( sb, "Expression: ${changes.xsdVersion}", 3 );
471                 append( sb, "", 0 );
472 
473                 append( sb, "failOnError (Default: false)", 2 );
474                 append( sb, "Mojo failure if validation failed. If not and validation failed only a warning will be logged.", 3 );
475                 append( sb, "Expression: ${changes.validate.failed}", 3 );
476                 append( sb, "", 0 );
477 
478                 append( sb, "xmlPath (Default: src/changes/changes.xml)", 2 );
479                 append( sb, "The path of the changes.xml file that will be converted into an HTML report.", 3 );
480                 append( sb, "Expression: ${changes.xmlPath}", 3 );
481                 append( sb, "", 0 );
482             }
483         }
484 
485         if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
486         {
487             append( sb, "changes:help", 0 );
488             append( sb, "Display help information on maven-changes-plugin.\nCall\n\u00a0\u00a0mvn\u00a0changes:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
489             append( sb, "", 0 );
490             if ( detail )
491             {
492                 append( sb, "Available parameters:", 1 );
493                 append( sb, "", 0 );
494 
495                 append( sb, "detail (Default: false)", 2 );
496                 append( sb, "If true, display all settable properties for each goal.", 3 );
497                 append( sb, "Expression: ${detail}", 3 );
498                 append( sb, "", 0 );
499 
500                 append( sb, "goal", 2 );
501                 append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
502                 append( sb, "Expression: ${goal}", 3 );
503                 append( sb, "", 0 );
504 
505                 append( sb, "indentSize (Default: 2)", 2 );
506                 append( sb, "The number of spaces per indentation level, should be positive.", 3 );
507                 append( sb, "Expression: ${indentSize}", 3 );
508                 append( sb, "", 0 );
509 
510                 append( sb, "lineLength (Default: 80)", 2 );
511                 append( sb, "The maximum length of a display line, should be positive.", 3 );
512                 append( sb, "Expression: ${lineLength}", 3 );
513                 append( sb, "", 0 );
514             }
515         }
516 
517         if ( goal == null || goal.length() <= 0 || "jira-report".equals( goal ) )
518         {
519             append( sb, "changes:jira-report", 0 );
520             append( sb, "Goal which downloads issues from the Issue Tracking System and generates a report.", 1 );
521             append( sb, "", 0 );
522             if ( detail )
523             {
524                 append( sb, "Available parameters:", 1 );
525                 append( sb, "", 0 );
526 
527                 append( sb, "columnNames (Default: Key,Summary,Status,Resolution,Assignee)", 2 );
528                 append( sb, "Sets the names of the columns that you want in the report. The columns will appear in the report in the same order as you specify them here. Multiple values can be separated by commas.\nValid columns are: Assignee, Component, Created, Fix Version, Id, Key, Priority, Reporter, Resolution, Status, Summary, Type, Updated and Version.\n", 3 );
529                 append( sb, "", 0 );
530 
531                 append( sb, "component", 2 );
532                 append( sb, "Sets the component(s) that you want to limit your report to include. Multiple values can be separated by commas (such as 10011,10012). If this is set to empty - that means all components will be included.", 3 );
533                 append( sb, "", 0 );
534 
535                 append( sb, "filter", 2 );
536                 append( sb, "Defines the filter parameters to restrict which issues are retrieved from JIRA. The filter parameter uses the same format of url parameters that is used in a JIRA search.", 3 );
537                 append( sb, "", 0 );
538 
539                 append( sb, "fixVersionIds", 2 );
540                 append( sb, "Sets the fix version id(s) that you want to limit your report to include. These are JIRA\'s internal version ids, NOT the human readable display ones. Multiple fix versions can be separated by commas. If this is set to empty - that means all fix versions will be included.", 3 );
541                 append( sb, "", 0 );
542 
543                 append( sb, "jiraDatePattern (Default: EEE, d MMM yyyy HH:mm:ss Z)", 2 );
544                 append( sb, "The pattern used by dates in the JIRA XML-file. This is used to parse the Created and Updated fields.", 3 );
545                 append( sb, "", 0 );
546 
547                 append( sb, "jiraPassword", 2 );
548                 append( sb, "Defines the JIRA password for authentication into a private JIRA installation.", 3 );
549                 append( sb, "", 0 );
550 
551                 append( sb, "jiraUser", 2 );
552                 append( sb, "Defines the JIRA username for authentication into a private JIRA installation.", 3 );
553                 append( sb, "", 0 );
554 
555                 append( sb, "maxEntries (Default: 100)", 2 );
556                 append( sb, "Maximum number of entries to be fetched from JIRA.", 3 );
557                 append( sb, "", 0 );
558 
559                 append( sb, "onlyCurrentVersion (Default: false)", 2 );
560                 append( sb, "If you only want to show issues for the current version in the report. The current version being used is ${project.version} minus any \'-SNAPSHOT\' suffix.", 3 );
561                 append( sb, "", 0 );
562 
563                 append( sb, "outputDirectory (Default: ${project.reporting.outputDirectory})", 2 );
564                 append( sb, "Report output directory. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output directory configured in the Maven Site Plugin is used instead.", 3 );
565                 append( sb, "", 0 );
566 
567                 append( sb, "outputEncoding (Default: ${project.reporting.outputEncoding})", 2 );
568                 append( sb, "Report output encoding. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output encoding configured in the Maven Site Plugin is used instead.", 3 );
569                 append( sb, "Expression: ${outputEncoding}", 3 );
570                 append( sb, "", 0 );
571 
572                 append( sb, "priorityIds", 2 );
573                 append( sb, "Sets the priority(s) that you want to limit your report to include. Valid statuses are Blocker, Critical, Major, Minor and Trivial. Multiple values can be separated by commas. If this is set to empty - that means all priorities will be included.", 3 );
574                 append( sb, "", 0 );
575 
576                 append( sb, "resolutionIds (Default: Fixed)", 2 );
577                 append( sb, "Sets the resolution(s) that you want to fetch from JIRA. Valid resolutions are: Unresolved, Fixed, Won\'t Fix, Duplicate, Incomplete and Cannot Reproduce. Multiple values can be separated by commas.\nNote: In versions 2.0-beta-3 and earlier this parameter had no default value.\n", 3 );
578                 append( sb, "", 0 );
579 
580                 append( sb, "sortColumnNames (Default: Priority DESC, Created DESC)", 2 );
581                 append( sb, "Sets the column names that you want to sort the report by. Add DESC following the column name to specify descending sequence. For example Fix Version DESC, Type sorts first by the Fix Version in descending order and then by Type in ascending order. By default sorting is done in ascending order, but is possible to specify ASC for consistency. The previous example would then become Fix Version DESC, Type ASC.\nValid columns are: Assignee, Component, Created, Fix Version, Id, Key, Priority, Reporter, Resolution, Status, Summary, Type, Updated and Version.\n\nNote: If you are using JIRA 4 you need to put your sort column names in the reverse order. The handling of this changed between JIRA 3 and JIRA 4. The current default value is suitable for JIRA 3. This may change in the future, so please configure your sort column names in an order that works for your own JIRA version.\n", 3 );
582                 append( sb, "", 0 );
583 
584                 append( sb, "statusIds (Default: Closed)", 2 );
585                 append( sb, "Sets the status(es) that you want to fetch from JIRA. Valid statuses are: Open, In Progress, Reopened, Resolved and Closed. Multiple values can be separated by commas.\nIf your installation of JIRA uses custom status IDs, you can reference them here by their numeric values. You can obtain them on the Statuses page (in 4.0.2 it\'s under Administration > Issue Settings > Statuses) - just hover over the Edit link for the status you want and you\'ll see something like <your JIRA URL>/secure/admin/EditStatus!default.jspa?id=12345; in this case the value is 12345.\n\nNote: In versions 2.0-beta-3 and earlier this parameter had no default value.\n", 3 );
586                 append( sb, "", 0 );
587 
588                 append( sb, "typeIds", 2 );
589                 append( sb, "Sets the types(s) that you want to limit your report to include. Valid types are: Bug, New Feature, Task, Improvement, Wish, Test and Sub-task. Multiple values can be separated by commas. If this is set to empty - that means all types will be included.", 3 );
590                 append( sb, "", 0 );
591 
592                 append( sb, "versionPrefix", 2 );
593                 append( sb, "The prefix used when naming versions in JIRA.\nIf you have a project in JIRA with several components that have different release cycles, it is an often used pattern to prefix the version with the name of the component, e.g. maven-filtering-1.0 etc. To fetch issues from JIRA for a release of the \'maven-filtering\' component you would need to set this parameter to \'maven-filtering-\'.\n", 3 );
594                 append( sb, "", 0 );
595 
596                 append( sb, "webPassword", 2 );
597                 append( sb, "Defines the http password for basic authentication into the JIRA webserver.", 3 );
598                 append( sb, "", 0 );
599 
600                 append( sb, "webUser", 2 );
601                 append( sb, "Defines the http user for basic authentication into the JIRA webserver.", 3 );
602                 append( sb, "", 0 );
603             }
604         }
605 
606         if ( goal == null || goal.length() <= 0 || "trac-report".equals( goal ) )
607         {
608             append( sb, "changes:trac-report", 0 );
609             append( sb, "Goal which downloads issues from the Issue Tracking System and generates a report.", 1 );
610             append( sb, "", 0 );
611             if ( detail )
612             {
613                 append( sb, "Available parameters:", 1 );
614                 append( sb, "", 0 );
615 
616                 append( sb, "columnNames (Default: Id,Type,Summary,Assignee,Reporter,Priority,Status,Resolution,Created,Updated)", 2 );
617                 append( sb, "Sets the column names that you want to show in the report. The columns will appear in the report in the same order as you specify them here. Multiple values can be separated by commas.\nValid columns are: Assignee, Component, Created, Fix Version, Id, Priority, Reporter, Resolution, Status, Summary, Type and Updated.\n", 3 );
618                 append( sb, "", 0 );
619 
620                 append( sb, "outputDirectory (Default: ${project.reporting.outputDirectory})", 2 );
621                 append( sb, "Report output directory. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output directory configured in the Maven Site Plugin is used instead.", 3 );
622                 append( sb, "", 0 );
623 
624                 append( sb, "outputEncoding (Default: ${project.reporting.outputEncoding})", 2 );
625                 append( sb, "Report output encoding. Note that this parameter is only relevant if the goal is run from the command line or from the default build lifecycle. If the goal is run indirectly as part of a site generation, the output encoding configured in the Maven Site Plugin is used instead.", 3 );
626                 append( sb, "Expression: ${outputEncoding}", 3 );
627                 append( sb, "", 0 );
628 
629                 append( sb, "query (Default: order=id)", 2 );
630                 append( sb, "Defines the Trac query for searching ticket.", 3 );
631                 append( sb, "", 0 );
632 
633                 append( sb, "tracPassword", 2 );
634                 append( sb, "Defines the Trac password for authentication into a private Trac installation.", 3 );
635                 append( sb, "", 0 );
636 
637                 append( sb, "tracUser", 2 );
638                 append( sb, "Defines the Trac username for authentication into a private Trac installation.", 3 );
639                 append( sb, "", 0 );
640             }
641         }
642 
643         if ( getLog().isInfoEnabled() )
644         {
645             getLog().info( sb.toString() );
646         }
647     }
648 
649     /**
650      * <p>Repeat a String <code>n</code> times to form a new string.</p>
651      *
652      * @param str String to repeat
653      * @param repeat number of times to repeat str
654      * @return String with repeated String
655      * @throws NegativeArraySizeException if <code>repeat < 0</code>
656      * @throws NullPointerException if str is <code>null</code>
657      */
658     private static String repeat( String str, int repeat )
659     {
660         StringBuffer buffer = new StringBuffer( repeat * str.length() );
661 
662         for ( int i = 0; i < repeat; i++ )
663         {
664             buffer.append( str );
665         }
666 
667         return buffer.toString();
668     }
669 
670     /** 
671      * Append a description to the buffer by respecting the indentSize and lineLength parameters.
672      * <b>Note</b>: The last character is always a new line.
673      * 
674      * @param sb The buffer to append the description, not <code>null</code>.
675      * @param description The description, not <code>null</code>.
676      * @param indent The base indentation level of each line, must not be negative.
677      */
678     private void append( StringBuffer sb, String description, int indent )
679     {
680         for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
681         {
682             sb.append( it.next().toString() ).append( '\n' );
683         }
684     }
685 
686     /** 
687      * Splits the specified text into lines of convenient display length.
688      * 
689      * @param text The text to split into lines, must not be <code>null</code>.
690      * @param indent The base indentation level of each line, must not be negative.
691      * @param indentSize The size of each indentation, must not be negative.
692      * @param lineLength The length of the line, must not be negative.
693      * @return The sequence of display lines, never <code>null</code>.
694      * @throws NegativeArraySizeException if <code>indent < 0</code>
695      */
696     private static List toLines( String text, int indent, int indentSize, int lineLength )
697     {
698         List<String> lines = new ArrayList<String>();
699 
700         String ind = repeat( "\t", indent );
701         String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
702         for ( int i = 0; i < plainLines.length; i++ )
703         {
704             toLines( lines, ind + plainLines[i], indentSize, lineLength );
705         }
706 
707         return lines;
708     }
709 
710     /** 
711      * Adds the specified line to the output sequence, performing line wrapping if necessary.
712      * 
713      * @param lines The sequence of display lines, must not be <code>null</code>.
714      * @param line The line to add, must not be <code>null</code>.
715      * @param indentSize The size of each indentation, must not be negative.
716      * @param lineLength The length of the line, must not be negative.
717      */
718     private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
719     {
720         int lineIndent = getIndentLevel( line );
721         StringBuffer buf = new StringBuffer( 256 );
722         String[] tokens = line.split( " +" );
723         for ( int i = 0; i < tokens.length; i++ )
724         {
725             String token = tokens[i];
726             if ( i > 0 )
727             {
728                 if ( buf.length() + token.length() >= lineLength )
729                 {
730                     lines.add( buf.toString() );
731                     buf.setLength( 0 );
732                     buf.append( repeat( " ", lineIndent * indentSize ) );
733                 }
734                 else
735                 {
736                     buf.append( ' ' );
737                 }
738             }
739             for ( int j = 0; j < token.length(); j++ )
740             {
741                 char c = token.charAt( j );
742                 if ( c == '\t' )
743                 {
744                     buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
745                 }
746                 else if ( c == '\u00A0' )
747                 {
748                     buf.append( ' ' );
749                 }
750                 else
751                 {
752                     buf.append( c );
753                 }
754             }
755         }
756         lines.add( buf.toString() );
757     }
758 
759     /** 
760      * Gets the indentation level of the specified line.
761      * 
762      * @param line The line whose indentation level should be retrieved, must not be <code>null</code>.
763      * @return The indentation level of the line.
764      */
765     private static int getIndentLevel( String line )
766     {
767         int level = 0;
768         for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
769         {
770             level++;
771         }
772         for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
773         {
774             if ( line.charAt( i ) == '\t' )
775             {
776                 level++;
777                 break;
778             }
779         }
780         return level;
781     }
782 }