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 org.apache.maven.doxia.sink.Sink;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.apache.maven.plugin.logging.Log;
25  import org.apache.maven.reporting.MavenReportException;
26  
27  import java.io.File;
28  import java.util.ArrayList;
29  import java.util.List;
30  import java.util.ResourceBundle;
31  
32  /**
33   * Generates a JIRA report.
34   *
35   * @version $Id: JiraReportGenerator.html 816588 2012-05-08 12:37:27Z hboutemy $
36   */
37  public class JiraReportGenerator
38  {
39      private static final int COLUMN_KEY = 0;
40      private static final int COLUMN_SUMMARY = 1;
41      private static final int COLUMN_STATUS = 2;
42      private static final int COLUMN_RESOLUTION = 3;
43      private static final int COLUMN_ASSIGNEE = 4;
44      private static final int COLUMN_REPORTER = 5;
45      private static final int COLUMN_TYPE = 6;
46      private static final int COLUMN_PRIORITY = 7;
47      private static final int COLUMN_VERSION = 8;
48      private static final int COLUMN_FIX_VERSION = 9;
49      private static final int COLUMN_COMPONENT = 10;
50  
51      private static final String[] JIRA_COLUMNS = new String[] {
52          /* 0  */ "Key",
53          /* 1  */ "Summary",
54          /* 2  */ "Status",
55          /* 3  */ "Resolution",
56          /* 4  */ "Assignee",
57          /* 5  */ "Reporter",
58          /* 6  */ "Type",
59          /* 7  */ "Priority",
60          /* 8  */ "Version",
61          /* 9  */ "Fix Version",
62          /* 10 */ "Component"
63      };
64  
65      private static final String SNAPSHOT_SUFFIX = "-SNAPSHOT";
66  
67      private int[] columnOrder;
68  
69      private String currentVersion = null;
70  
71      private JiraXML jira;
72  
73      private boolean onlyCurrentVersion = false;
74  
75      public JiraReportGenerator()
76      {
77  
78      }
79  
80      /**
81       *
82       * @param xmlFile An xml file containing issues from JIRA
83       * @param columnNames The names of the columns to include in the report
84       * @param currentVersion The current version of the project
85       * @param onlyCurrentVersion If only issues for the current version will be included in the report
86       */
87      public JiraReportGenerator( File xmlFile, String columnNames, String currentVersion, boolean onlyCurrentVersion )
88          throws MavenReportException
89      {
90          this.currentVersion = currentVersion;
91          this.onlyCurrentVersion = onlyCurrentVersion;
92  
93          jira = new JiraXML( xmlFile );
94  
95          String[] columnNamesArray = columnNames.split( "," );
96          int validColumnNames = 0;
97          columnOrder = new int[columnNamesArray.length];
98          for ( int i = 0; i < columnOrder.length; i++ )
99          {
100             // Default to -1, indicating that the column should not be included in the report
101             columnOrder[i] = -1;
102             for ( int columnIndex = 0; columnIndex < JIRA_COLUMNS.length; columnIndex++ )
103             {
104                 String columnName = columnNamesArray[i].trim();
105                 if ( JIRA_COLUMNS[columnIndex].equalsIgnoreCase( columnName ) )
106                 {
107                     // Found a valid column name - add it
108                     columnOrder[i] = columnIndex;
109                     validColumnNames++;
110                     break;
111                 }
112             }
113         }
114         if ( validColumnNames == 0 )
115         {
116             // This can happen if the user has configured column names and they are all invalid
117             throw new MavenReportException(
118                 "maven-changes-plugin: None of the configured columnNames '" + columnNames + "' are valid." );
119         }
120     }
121 
122     public void doGenerateEmptyReport( ResourceBundle bundle, Sink sink )
123     {
124         sinkBeginReport( sink, bundle );
125 
126         sink.text( bundle.getString( "report.jira.error" ) );
127 
128         sinkEndReport( sink );
129     }
130 
131     public void doGenerateReport( ResourceBundle bundle, Sink sink, Log log )
132         throws MojoExecutionException
133     {
134         List issueList = jira.getIssueList();
135 
136         if ( onlyCurrentVersion )
137         {
138             issueList = getIssuesForCurrentRelease( issueList );
139             log.info( "The JIRA Report will contain issues only for the current version." );
140         }
141 
142         sinkBeginReport( sink, bundle );
143 
144         constructHeaderRow( sink, issueList, bundle );
145 
146         constructDetailRows( sink, issueList );
147 
148         sinkEndReport( sink );
149     }
150 
151     private void constructHeaderRow( Sink sink, List issueList, ResourceBundle bundle )
152     {
153         if ( issueList == null )
154         {
155             return;
156         }
157 
158         sink.table();
159 
160         sink.tableRow();
161 
162         for ( int columnIndex = 0; columnIndex < columnOrder.length; columnIndex++ )
163         {
164             switch ( columnOrder[columnIndex] )
165             {
166                 case COLUMN_KEY:
167                     sinkHeader( sink, bundle.getString( "report.jira.label.key" ) );
168                     break;
169 
170                 case COLUMN_SUMMARY:
171                     sinkHeader( sink, bundle.getString( "report.jira.label.summary" ) );
172                     break;
173 
174                 case COLUMN_STATUS:
175                     sinkHeader( sink, bundle.getString( "report.jira.label.status" ) );
176                     break;
177 
178                 case COLUMN_RESOLUTION:
179                     sinkHeader( sink, bundle.getString( "report.jira.label.resolution" ) );
180                     break;
181 
182                 case COLUMN_ASSIGNEE:
183                     sinkHeader( sink, bundle.getString( "report.jira.label.by" ) );
184                     break;
185 
186                 case COLUMN_REPORTER:
187                     sinkHeader( sink, bundle.getString( "report.jira.label.reporter" ) );
188                     break;
189 
190                 case COLUMN_TYPE:
191                     sinkHeader( sink, bundle.getString( "report.jira.label.type" ) );
192                     break;
193 
194                 case COLUMN_PRIORITY:
195                     sinkHeader( sink, bundle.getString( "report.jira.label.priority" ) );
196                     break;
197 
198                 case COLUMN_VERSION:
199                     sinkHeader( sink, bundle.getString( "report.jira.label.version" ) );
200                     break;
201 
202                 case COLUMN_FIX_VERSION:
203                     sinkHeader( sink, bundle.getString( "report.jira.label.fixVersion" ) );
204                     break;
205 
206                 case COLUMN_COMPONENT:
207                     sinkHeader( sink, bundle.getString( "report.jira.label.component" ) );
208                     break;
209 
210                 default:
211                     // Do not add a header for this column
212                     break;
213             }
214 
215         }
216 
217         sink.tableRow_();
218     }
219 
220     private void constructDetailRows( Sink sink, List issueList )
221     {
222         if ( issueList == null )
223         {
224             return;
225         }
226 
227         for ( int idx = 0; idx < issueList.size(); idx++ )
228         {
229             JiraIssue issue = (JiraIssue) issueList.get( idx );
230 
231             sink.tableRow();
232 
233             for ( int columnIndex = 0; columnIndex < columnOrder.length; columnIndex++ )
234             {
235                 switch ( columnOrder[columnIndex] )
236                 {
237                     case COLUMN_KEY:
238                         sink.tableCell();
239                         sink.link( issue.getLink() );
240                         sink.text( issue.getKey() );
241                         sink.link_();
242                         sink.tableCell_();
243                         break;
244 
245                     case COLUMN_SUMMARY:
246                         sinkCell( sink, issue.getSummary() );
247                         break;
248 
249                     case COLUMN_STATUS:
250                         sinkCell( sink, issue.getStatus() );
251                         break;
252 
253                     case COLUMN_RESOLUTION:
254                         sinkCell( sink, issue.getResolution() );
255                         break;
256 
257                     case COLUMN_ASSIGNEE:
258                         sinkCell( sink, issue.getAssignee() );
259                         break;
260 
261                     case COLUMN_REPORTER:
262                         sinkCell( sink, issue.getReporter() );
263                         break;
264 
265                     case COLUMN_TYPE:
266                         sinkCell( sink, issue.getType() );
267                         break;
268 
269                     case COLUMN_PRIORITY:
270                         sinkCell( sink, issue.getPriority() );
271                         break;
272 
273                     case COLUMN_VERSION:
274                         sinkCell( sink, issue.getVersion() );
275                         break;
276 
277                     case COLUMN_FIX_VERSION:
278                         sinkCell( sink, issue.getFixVersion() );
279                         break;
280 
281                     case COLUMN_COMPONENT:
282                         sinkCell( sink, issue.getComponent() );
283                         break;
284 
285                     default:
286                         // Do not add a cell for this column
287                         break;
288                 }
289             }
290 
291             sink.tableRow_();
292         }
293 
294         sink.table_();
295     }
296 
297     private void sinkBeginReport( Sink sink, ResourceBundle bundle )
298     {
299         sink.head();
300 
301         sink.title();
302         sink.text( bundle.getString( "report.jira.header" ) );
303         sink.title_();
304 
305         sink.head_();
306 
307         sink.body();
308 
309         sinkSectionTitle1( sink, bundle.getString( "report.jira.header" ) );
310 
311     }
312 
313     private void sinkEndReport( Sink sink )
314     {
315         sink.body_();
316 
317         sink.flush();
318 
319         sink.close();
320     }
321 
322     private void sinkFigure( Sink sink, String image )
323     {
324         sink.figure();
325 
326         sink.figureGraphics( image );
327 
328         sink.figure_();
329     }
330 
331     private void sinkHeader( Sink sink, String header )
332     {
333         sink.tableHeaderCell();
334 
335         sink.text( header );
336 
337         sink.tableHeaderCell_();
338     }
339 
340     private void sinkCell( Sink sink, String text )
341     {
342         sink.tableCell();
343 
344         if ( text != null )
345         {
346             sink.rawText( text );
347         }
348         else
349         {
350             sink.rawText( "&nbsp;" );
351         }
352 
353         sink.tableCell_();
354     }
355 
356     private void sinkSectionTitle1( Sink sink, String text )
357     {
358         sink.sectionTitle1();
359 
360         sink.text( text );
361 
362         sink.sectionTitle1_();
363     }
364 
365     /**
366      * Find the issues for only the current release, by matching the "Fix for"
367      * version in the supplied list of issues with the current version from the
368      * pom. If the current version is a SNAPSHOT, then that part of the version
369      * will be removed prior to the matching.
370      *
371      * @param allIssues A list of all issues from JIRA
372      * @return A <code>List</code> of issues for the current release of the current project
373      * @throws org.apache.maven.plugin.MojoExecutionException
374      *          If no issues could be found for the current release
375      */
376     public List getIssuesForCurrentRelease( List allIssues )
377         throws MojoExecutionException
378     {
379         List currentReleaseIssues = new ArrayList();
380         boolean isFound = false;
381         JiraIssue issue = null;
382         String releaseVersion = currentVersion;
383 
384         // Remove "-SNAPSHOT" from the end of the version, if it's there
385         if ( currentVersion != null && currentVersion.endsWith( SNAPSHOT_SUFFIX ) )
386         {
387             releaseVersion = currentVersion.substring( 0, currentVersion.length() - SNAPSHOT_SUFFIX.length() );
388         }
389 
390         for ( int i = 0; i < allIssues.size(); i++ )
391         {
392             issue = (JiraIssue) allIssues.get( i );
393 
394             if ( issue.getFixVersion() != null && issue.getFixVersion().equals( releaseVersion ) )
395             {
396                 isFound = true;
397                 currentReleaseIssues.add( issue );
398             }
399         }
400 
401         if ( !isFound )
402         {
403             throw new MojoExecutionException(
404                 "Couldn't find any issues for the version '" + releaseVersion + "' among the supplied issues." );
405         }
406         return currentReleaseIssues;
407     }
408 }