View Javadoc

1   package org.apache.maven.plugin.jira;
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.util.HashMap;
24  import java.util.List;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.ResourceBundle;
28  
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.maven.plugin.changes.AbstractChangesReport;
31  import org.apache.maven.plugin.changes.ProjectUtils;
32  import org.apache.maven.plugin.issues.IssueUtils;
33  import org.apache.maven.plugin.issues.IssuesReportGenerator;
34  import org.apache.maven.plugin.issues.IssuesReportHelper;
35  import org.apache.maven.reporting.MavenReportException;
36  import org.apache.maven.settings.Settings;
37  
38  /**
39   * Goal which downloads issues from the Issue Tracking System and generates a report.
40   *
41   * @goal jira-report
42   * @author <a href="mailto:jruiz@exist.com">Johnny R. Ruiz III</a>
43   * @version $Id: JiraMojo.html 816598 2012-05-08 12:46:49Z hboutemy $
44   * @threadSafe
45   */
46  public class JiraMojo
47      extends AbstractChangesReport
48  {
49      /**
50       * Valid JIRA columns.
51       */
52      private static final Map JIRA_COLUMNS = new HashMap( 16 );
53  
54      static
55      {
56          JIRA_COLUMNS.put( "Assignee", new Integer( IssuesReportHelper.COLUMN_ASSIGNEE ) );
57          JIRA_COLUMNS.put( "Component", new Integer( IssuesReportHelper.COLUMN_COMPONENT ) );
58          JIRA_COLUMNS.put( "Created", new Integer( IssuesReportHelper.COLUMN_CREATED ) );
59          JIRA_COLUMNS.put( "Fix Version", new Integer( IssuesReportHelper.COLUMN_FIX_VERSION ) );
60          JIRA_COLUMNS.put( "Id", new Integer( IssuesReportHelper.COLUMN_ID ) );
61          JIRA_COLUMNS.put( "Key", new Integer( IssuesReportHelper.COLUMN_KEY ) );
62          JIRA_COLUMNS.put( "Priority", new Integer( IssuesReportHelper.COLUMN_PRIORITY ) );
63          JIRA_COLUMNS.put( "Reporter", new Integer( IssuesReportHelper.COLUMN_REPORTER ) );
64          JIRA_COLUMNS.put( "Resolution", new Integer( IssuesReportHelper.COLUMN_RESOLUTION ) );
65          JIRA_COLUMNS.put( "Status", new Integer( IssuesReportHelper.COLUMN_STATUS ) );
66          JIRA_COLUMNS.put( "Summary", new Integer( IssuesReportHelper.COLUMN_SUMMARY ) );
67          JIRA_COLUMNS.put( "Type", new Integer( IssuesReportHelper.COLUMN_TYPE ) );
68          JIRA_COLUMNS.put( "Updated", new Integer( IssuesReportHelper.COLUMN_UPDATED ) );
69          JIRA_COLUMNS.put( "Version", new Integer( IssuesReportHelper.COLUMN_VERSION ) );
70      }
71  
72      /**
73       * Sets the names of the columns that you want in the report. The columns
74       * will appear in the report in the same order as you specify them here.
75       * Multiple values can be separated by commas.
76       * <p>
77       * Valid columns are: <code>Assignee</code>, <code>Component</code>,
78       * <code>Created</code>, <code>Fix Version</code>, <code>Id</code>,
79       * <code>Key</code>, <code>Priority</code>, <code>Reporter</code>,
80       * <code>Resolution</code>, <code>Status</code>, <code>Summary</code>,
81       * <code>Type</code>, <code>Updated</code> and <code>Version</code>.
82       * </p>
83       *
84       * @parameter default-value="Key,Summary,Status,Resolution,Assignee"
85       * @since 2.0
86       */
87      private String columnNames;
88  
89      /**
90       * Sets the component(s) that you want to limit your report to include.
91       * Multiple values can be separated by commas (such as 10011,10012).
92       * If this is set to empty - that means all components will be included.
93       *
94       * @parameter default-value=""
95       */
96      private String component;
97  
98      /**
99       * Defines the filter parameters to restrict which issues are retrieved
100      * from JIRA. The filter parameter uses the same format of url
101      * parameters that is used in a JIRA search.
102      *
103      * @parameter default-value=""
104      */
105     private String filter;
106 
107     /**
108      * Sets the fix version id(s) that you want to limit your report to include.
109      * These are JIRA's internal version ids, <b>NOT</b> the human readable display ones.
110      * Multiple fix versions can be separated by commas.
111      * If this is set to empty - that means all fix versions will be included.
112      *
113      * @parameter default-value=""
114      * @since 2.0
115      */
116     private String fixVersionIds;
117 
118     /**
119      * The pattern used by dates in the JIRA XML-file. This is used to parse
120      * the Created and Updated fields.
121      *
122      * @parameter default-value="EEE, d MMM yyyy HH:mm:ss Z"
123      * @since 2.4
124      */
125     private String jiraDatePattern;
126 
127     /**
128      * Defines the JIRA password for authentication into a private JIRA installation.
129      *
130      * @parameter default-value=""
131      */
132     private String jiraPassword;
133 
134     /**
135      * Defines the JIRA username for authentication into a private JIRA installation.
136      *
137      * @parameter default-value=""
138      */
139     private String jiraUser;
140 
141     /**
142      * Path to the JIRA XML file, which will be parsed.
143      *
144      * @parameter expression="${project.build.directory}/jira-results.xml"
145      * @required
146      * @readonly
147      */
148     private File jiraXmlPath;
149 
150     /**
151      * Maximum number of entries to be fetched from JIRA.
152      *
153      * @parameter default-value=100
154      *
155      */
156     private int maxEntries;
157 
158     /**
159      * If you only want to show issues for the current version in the report.
160      * The current version being used is <code>${project.version}</code> minus
161      * any "-SNAPSHOT" suffix.
162      *
163      * @parameter default-value="false"
164      * @since 2.0
165      */
166     private boolean onlyCurrentVersion;
167 
168     /**
169      * Sets the priority(s) that you want to limit your report to include.
170      * Valid statuses are <code>Blocker</code>, <code>Critical</code>,
171      * <code>Major</code>, <code>Minor</code> and <code>Trivial</code>.
172      * Multiple values can be separated by commas.
173      * If this is set to empty - that means all priorities will be included.
174      *
175      * @parameter default-value=""
176      */
177     private String priorityIds;
178 
179     /**
180      * Sets the resolution(s) that you want to fetch from JIRA.
181      * Valid resolutions are: <code>Unresolved</code>, <code>Fixed</code>,
182      * <code>Won't Fix</code>, <code>Duplicate</code>, <code>Incomplete</code>
183      * and <code>Cannot Reproduce</code>.
184      * Multiple values can be separated by commas.
185      * <p>
186      * <b>Note:</b> In versions 2.0-beta-3 and earlier this parameter had no
187      * default value.
188      * </p>
189      *
190      * @parameter default-value="Fixed"
191      */
192     private String resolutionIds;
193 
194     /**
195      * Settings XML configuration.
196      *
197      * @parameter expression="${settings}"
198      * @required
199      * @readonly
200      */
201     private Settings settings;
202 
203     /**
204      * Sets the column names that you want to sort the report by. Add
205      * <code>DESC</code> following the column name
206      * to specify <i>descending</i> sequence. For
207      * example <code>Fix Version DESC, Type</code> sorts first by
208      * the Fix Version in descending order and then by Type in
209      * ascending order. By default sorting is done in ascending order, but is
210      * possible to specify <code>ASC</code> for consistency. The previous
211      * example would then become <code>Fix Version DESC, Type ASC</code>.
212      * <p>
213      * Valid columns are: <code>Assignee</code>, <code>Component</code>,
214      * <code>Created</code>, <code>Fix Version</code>, <code>Id</code>,
215      * <code>Key</code>, <code>Priority</code>, <code>Reporter</code>,
216      * <code>Resolution</code>, <code>Status</code>, <code>Summary</code>,
217      * <code>Type</code>, <code>Updated</code> and <code>Version</code>.
218      * </p>
219      * <p>
220      * <strong>Note:</strong> If you are using JIRA 4 you need to put your
221      * sort column names in the reverse order. The handling of this changed
222      * between JIRA 3 and JIRA 4. The current default value is suitable for
223      * JIRA 3. This may change in the future, so please configure your sort
224      * column names in an order that works for your own JIRA version. 
225      * </p>
226      *
227      * @parameter default-value="Priority DESC, Created DESC"
228      * @since 2.0
229      */
230     private String sortColumnNames;
231 
232     /**
233      * Sets the status(es) that you want to fetch from JIRA.
234      * Valid statuses are: <code>Open</code>, <code>In Progress</code>,
235      * <code>Reopened</code>, <code>Resolved</code> and <code>Closed</code>.
236      * Multiple values can be separated by commas.
237      * <p>
238      * <b>Note:</b> In versions 2.0-beta-3 and earlier this parameter had no
239      * default value.
240      * </p>
241      *
242      * @parameter default-value="Closed"
243      */
244     private String statusIds;
245 
246     /**
247      * Sets the types(s) that you want to limit your report to include.
248      * Valid types are: <code>Bug</code>, <code>New Feature</code>,
249      * <code>Task</code>, <code>Improvement</code>, <code>Wish</code>,
250      * <code>Test</code> and <code>Sub-task</code>.
251      * Multiple values can be separated by commas.
252      * If this is set to empty - that means all types will be included.
253      *
254      * @parameter default-value=""
255      * @since 2.0
256      */
257     private String typeIds;
258 
259     /**
260      * The prefix used when naming versions in JIRA.
261      * <p>
262      * If you have a project in JIRA with several components that have different
263      * release cycles, it is an often used pattern to prefix the version with
264      * the name of the component, e.g. maven-filtering-1.0 etc. To fetch issues
265      * from JIRA for a release of the "maven-filtering" component you would need
266      * to set this parameter to "maven-filtering-".
267      * </p>
268      *
269      * @parameter default-value=""
270      * @since 2.4
271      */
272     private String versionPrefix;
273 
274     /**
275      * Defines the http password for basic authentication into the JIRA webserver.
276      *
277      * @parameter default-value=""
278      */
279     private String webPassword;
280 
281     /**
282      * Defines the http user for basic authentication into the JIRA webserver.
283      *
284      * @parameter default-value=""
285      */
286     private String webUser;
287 
288     /* --------------------------------------------------------------------- */
289     /* Public methods                                                        */
290     /* --------------------------------------------------------------------- */
291 
292     /**
293      * @see org.apache.maven.reporting.AbstractMavenReport#canGenerateReport()
294      */
295     public boolean canGenerateReport()
296     {
297         return ProjectUtils.validateIfIssueManagementComplete( project, "JIRA", "JIRA Report", getLog() );
298     }
299 
300     public void executeReport( Locale locale )
301         throws MavenReportException
302     {
303         // Validate parameters
304         List columnIds = IssuesReportHelper.getColumnIds( columnNames, JIRA_COLUMNS );
305         if ( columnIds.isEmpty() )
306         {
307             // This can happen if the user has configured column names and they are all invalid
308             throw new MavenReportException(
309                 "maven-changes-plugin: None of the configured columnNames '" + columnNames + "' are valid." );
310         }
311 
312         try
313         {
314             // Download issues
315             JiraDownloader issueDownloader = new JiraDownloader();
316             configureIssueDownloader( issueDownloader );
317             issueDownloader.doExecute();
318 
319             List issueList = issueDownloader.getIssueList();
320 
321             if ( StringUtils.isNotEmpty( versionPrefix ) )
322             {
323                 int originalNumberOfIssues = issueList.size();
324                 issueList = IssueUtils.filterIssuesWithVersionPrefix( issueList, versionPrefix );
325                 getLog().debug( "Filtered out " + issueList.size() + " issues of " + originalNumberOfIssues
326                     + " that matched the versionPrefix '" + versionPrefix + "'." );
327             }
328 
329             if ( onlyCurrentVersion )
330             {
331                 String version = ( versionPrefix == null ? "" : versionPrefix ) + project.getVersion();
332                 issueList = IssueUtils.getIssuesForVersion( issueList, version );
333                 getLog().info( "The JIRA Report will contain issues only for the current version." );
334             }
335 
336             // Generate the report
337             IssuesReportGenerator report = new IssuesReportGenerator( IssuesReportHelper.toIntArray( columnIds ) );
338 
339             if ( issueList.isEmpty() )
340             {
341                 report.doGenerateEmptyReport( getBundle( locale ), getSink() );
342             }
343             else
344             {
345                 report.doGenerateReport( getBundle( locale ), getSink(), issueList );
346             }
347         }
348         catch ( Exception e )
349         {
350             getLog().warn( e );
351         }
352     }
353 
354     public String getDescription( Locale locale )
355     {
356         return getBundle( locale ).getString( "report.issues.description" );
357     }
358 
359     public String getName( Locale locale )
360     {
361         return getBundle( locale ).getString( "report.issues.name" );
362     }
363 
364     public String getOutputName()
365     {
366         return "jira-report";
367     }
368 
369     /* --------------------------------------------------------------------- */
370     /* Private methods                                                       */
371     /* --------------------------------------------------------------------- */
372 
373     private ResourceBundle getBundle( Locale locale )
374     {
375         return ResourceBundle.getBundle( "jira-report", locale, this.getClass().getClassLoader() );
376     }
377 
378     private void configureIssueDownloader( JiraDownloader issueDownloader )
379     {
380         issueDownloader.setLog( getLog() );
381 
382         issueDownloader.setMavenProject( project );
383 
384         issueDownloader.setOutput( jiraXmlPath );
385 
386         issueDownloader.setNbEntries( maxEntries );
387 
388         issueDownloader.setComponent( component );
389 
390         issueDownloader.setFixVersionIds( fixVersionIds );
391 
392         issueDownloader.setStatusIds( statusIds );
393 
394         issueDownloader.setResolutionIds( resolutionIds );
395 
396         issueDownloader.setPriorityIds( priorityIds );
397 
398         issueDownloader.setSortColumnNames( sortColumnNames );
399 
400         issueDownloader.setFilter( filter );
401 
402         issueDownloader.setJiraDatePattern( jiraDatePattern );
403 
404         issueDownloader.setJiraUser( jiraUser );
405 
406         issueDownloader.setJiraPassword( jiraPassword );
407 
408         issueDownloader.setTypeIds( typeIds );
409 
410         issueDownloader.setWebUser( webUser );
411 
412         issueDownloader.setWebPassword( webPassword );
413 
414         issueDownloader.setSettings( settings );
415     }
416 }