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