Coverage Report - org.apache.maven.plugin.changes.ChangesMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
ChangesMojo
0%
0/107
0%
0/34
3,364
 
 1  
 package org.apache.maven.plugin.changes;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.net.URL;
 25  
 import java.text.SimpleDateFormat;
 26  
 import java.util.Collections;
 27  
 import java.util.Date;
 28  
 import java.util.Iterator;
 29  
 import java.util.List;
 30  
 import java.util.Locale;
 31  
 import java.util.Map;
 32  
 import java.util.Properties;
 33  
 import java.util.ResourceBundle;
 34  
 
 35  
 import org.apache.commons.collections.map.CaseInsensitiveMap;
 36  
 import org.apache.maven.execution.MavenSession;
 37  
 import org.apache.maven.plugins.annotations.Component;
 38  
 import org.apache.maven.plugins.annotations.Mojo;
 39  
 import org.apache.maven.plugins.annotations.Parameter;
 40  
 import org.apache.maven.project.MavenProject;
 41  
 import org.apache.maven.reporting.MavenReportException;
 42  
 import org.apache.maven.shared.filtering.MavenFileFilter;
 43  
 import org.apache.maven.shared.filtering.MavenFileFilterRequest;
 44  
 import org.apache.maven.shared.filtering.MavenFilteringException;
 45  
 import org.codehaus.plexus.util.FileUtils;
 46  
 import org.codehaus.plexus.util.IOUtil;
 47  
 import org.codehaus.plexus.util.ReaderFactory;
 48  
 import org.codehaus.plexus.util.StringUtils;
 49  
 import org.codehaus.plexus.util.xml.XmlStreamReader;
 50  
 
 51  
 /**
 52  
  * Goal which creates a nicely formatted Changes Report in html format from a changes.xml file.
 53  
  *
 54  
  * @author <a href="mailto:jruiz@exist.com">Johnny R. Ruiz III</a>
 55  
  * @version $Id: ChangesMojo.java 1379909 2012-09-02 00:10:27Z dennisl $
 56  
  */
 57  
 @Mojo( name = "changes-report", threadSafe = true )
 58  0
 public class ChangesMojo
 59  
     extends AbstractChangesReport
 60  
 {
 61  
     /**
 62  
      * A flag whether the report should also include changes from child modules. If set to <code>false</code>, only
 63  
      * the changes from current project will be written to the report.
 64  
      *
 65  
      * @since 2.5
 66  
      */
 67  
     @Parameter( defaultValue = "false" )
 68  
     private boolean aggregated;
 69  
 
 70  
     /**
 71  
      * A flag whether the report should also include the dates of individual actions. If set to <code>false</code>, only
 72  
      * the dates of releases will be written to the report.
 73  
      *
 74  
      * @since 2.1
 75  
      */
 76  
     @Parameter( property = "changes.addActionDate", defaultValue = "false" )
 77  
     private boolean addActionDate;
 78  
 
 79  
     /**
 80  
      * Whether HTML code within an action should be escaped. By changing this to
 81  
      * <code>false</code> you can restore the behavior that was in version 2.2
 82  
      * of this plugin, allowing you to use HTML code to format the content of an
 83  
      * action.
 84  
      * <p>
 85  
      * <strong>Note:</strong> If you use HTML code in an action you need to
 86  
      * place it inside a CDATA section.
 87  
      * </p>
 88  
      * <strong>Note:</strong> Putting any kind of markup inside a CDATA section
 89  
      * might mess up the Changes Report or other generated documents, such as
 90  
      * PDFs, that are based on your <code>changes.xml</code> file if you are not
 91  
      * careful.
 92  
      *
 93  
      * @since 2.4
 94  
      * @deprecated using markup inside CDATA sections does not work for all output formats!
 95  
      */
 96  
     @Parameter( defaultValue = "true" )
 97  
     private boolean escapeHTML;
 98  
 
 99  
     /**
 100  
      * The directory for interpolated changes.xml.
 101  
      *
 102  
      * @since 2.2
 103  
      */
 104  
     @Parameter( defaultValue = "${project.build.directory}/changes", required = true, readonly = true )
 105  
     private File filteredOutputDirectory;
 106  
 
 107  
     /**
 108  
      * applying filtering filtering "a la" resources plugin
 109  
      *
 110  
      * @since 2.2
 111  
      */
 112  
     @Parameter( defaultValue = "false" )
 113  
     private boolean filteringChanges;
 114  
 
 115  
     /**
 116  
      * Template string that is used to discover the URL to use to display an issue report.
 117  
      * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the
 118  
      * <code>&lt;issueManagement&gt;/&lt;url&gt;</code> value from the POM, and removing the last '/'
 119  
      * and everything that comes after it. <code>%ISSUE%</code>: this is the issue number.
 120  
      * <p>
 121  
      * <strong>Note:</strong> In versions of this plugin prior to 2.0-beta-2 this parameter was called
 122  
      * <code>link_template</code>.
 123  
      * </p>
 124  
      *
 125  
      * @since 2.0-beta-2
 126  
      * @deprecated As of 2.1 use issueLinkTemplatePerSystem : this one will be with system default
 127  
      */
 128  
     @Parameter( property = "changes.issueLinkTemplate", defaultValue = "%URL%/ViewIssue.jspa?key=%ISSUE%" )
 129  
     private String issueLinkTemplate;
 130  
 
 131  
     /**
 132  
      * Template strings per system that is used to discover the URL to use to display an issue report. Each key in this
 133  
      * map denotes the (case-insensitive) identifier of the issue tracking system and its value gives the URL template.
 134  
      * <p>
 135  
      * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the
 136  
      * <code>&lt;issueManagement&gt;/&lt;url&gt;</code> value from the POM, and removing the last '/'
 137  
      * and everything that comes after it. <code>%ISSUE%</code>: this is the issue number.
 138  
      * </p>
 139  
      * <p>
 140  
      * <strong>Note:</strong> The deprecated issueLinkTemplate will be used for a system called "default".
 141  
      * </p>
 142  
      * <p>
 143  
      * <strong>Note:</strong> Starting with version 2.4 you usually don't need
 144  
      * to specify this, unless you need to link to an issue management system in
 145  
      * your Changes report that isn't supported out of the box. See the
 146  
      * <a href="./usage.html">Usage page</a> for more
 147  
      * information.
 148  
      * </p>
 149  
      *
 150  
      * @since 2.1
 151  
      */
 152  
     @Parameter
 153  
     private Map issueLinkTemplatePerSystem;
 154  
 
 155  
     /**
 156  
      * @since 2.2
 157  
      */
 158  
     @Component
 159  
     private MavenFileFilter mavenFileFilter;
 160  
 
 161  
     /**
 162  
      * Format to use for publishDate. The value will be available with the following expression ${publishDate}
 163  
      *
 164  
      * @see java.text.SimpleDateFormat
 165  
      * @since 2.2
 166  
      */
 167  
     @Parameter( defaultValue = "yyyy-MM-dd" )
 168  
     private String publishDateFormat;
 169  
 
 170  
     /**
 171  
      * Locale to use for publishDate when formatting
 172  
      *
 173  
      * @see java.util.Locale
 174  
      * @since 2.2
 175  
      */
 176  
     @Parameter( defaultValue = "en" )
 177  
     private String publishDateLocale;
 178  
 
 179  
     /**
 180  
      * @since 2.2
 181  
      */
 182  
     @Component
 183  
     protected MavenSession session;
 184  
 
 185  
     /**
 186  
      * @since 2.4
 187  
      */
 188  
     @Parameter( defaultValue = "${project.issueManagement.system}", readonly = true )
 189  
     private String system;
 190  
 
 191  
     /**
 192  
      * The URI of a file containing all the team members. If this is set to the
 193  
      * special value "none", no links will be generated for the team members.
 194  
      *
 195  
      * @since 2.4
 196  
      */
 197  
     @Parameter( defaultValue = "team-list.html" )
 198  
     private String teamlist;
 199  
 
 200  
     /**
 201  
      */
 202  
     @Parameter( defaultValue = "${project.issueManagement.url}", readonly = true )
 203  
     private String url;
 204  
 
 205  
     /**
 206  
      * The path of the <code>changes.xml</code> file that will be converted into an HTML report.
 207  
      */
 208  
     @Parameter( property = "changes.xmlPath", defaultValue = "src/changes/changes.xml" )
 209  
     private File xmlPath;
 210  
 
 211  0
     private ReleaseUtils releaseUtils = new ReleaseUtils( getLog() );
 212  
 
 213  
     private CaseInsensitiveMap caseInsensitiveIssueLinkTemplatePerSystem;
 214  
 
 215  
     /* --------------------------------------------------------------------- */
 216  
     /* Public methods                                                        */
 217  
     /* --------------------------------------------------------------------- */
 218  
 
 219  
     public boolean canGenerateReport()
 220  
     {
 221  0
         return xmlPath.isFile();
 222  
     }
 223  
 
 224  
     public void executeReport( Locale locale )
 225  
         throws MavenReportException
 226  
     {
 227  0
         Date now = new Date();
 228  0
         SimpleDateFormat simpleDateFormat =
 229  
                 new SimpleDateFormat(publishDateFormat, new Locale(publishDateLocale));
 230  0
         Properties additionalProperties = new Properties();
 231  0
         additionalProperties.put("publishDate", simpleDateFormat.format(now));
 232  
 
 233  0
         ChangesXML changesXml = getChangesFromFile( xmlPath, project, additionalProperties);
 234  0
         if ( changesXml == null ) return;
 235  
 
 236  0
         if ( aggregated )
 237  
         {
 238  0
             final String basePath = project.getBasedir().getAbsolutePath();
 239  0
             final String absolutePath = xmlPath.getAbsolutePath();
 240  0
             if ( !absolutePath.startsWith( basePath ) )
 241  
             {
 242  0
                 getLog().warn( "xmlPath should be within the project dir for aggregated changes report." );
 243  0
                 return;
 244  
             }
 245  0
             final String relativePath = absolutePath.substring( basePath.length() );
 246  
 
 247  0
             List releaseList = changesXml.getReleaseList();
 248  0
             for ( Iterator iterator = project.getCollectedProjects().iterator(); iterator.hasNext(); )
 249  
             {
 250  0
                 final MavenProject childProject = (MavenProject) iterator.next();
 251  0
                 final File changesFile = new File( childProject.getBasedir(), relativePath );
 252  0
                 final ChangesXML childXml = getChangesFromFile( changesFile, childProject, additionalProperties );
 253  0
                 if ( childXml != null )
 254  
                 {
 255  0
                     releaseList = releaseUtils.mergeReleases( releaseList, childProject.getName(), childXml.getReleaseList() );
 256  
                 }
 257  0
             }
 258  0
             changesXml.setReleaseList( releaseList );
 259  
         }
 260  
 
 261  0
         ChangesReportGenerator report = new ChangesReportGenerator( changesXml.getReleaseList() );
 262  
 
 263  0
         report.setAuthor( changesXml.getAuthor() );
 264  0
         report.setTitle( changesXml.getTitle() );
 265  
 
 266  0
         report.setEscapeHTML ( escapeHTML );
 267  
 
 268  
         // Create a case insensitive version of issueLinkTemplatePerSystem
 269  
         // We need something case insensitive to maintain backward compatibility
 270  0
         if ( issueLinkTemplatePerSystem == null )
 271  
         {
 272  0
             caseInsensitiveIssueLinkTemplatePerSystem = new CaseInsensitiveMap();
 273  
         }
 274  
         else
 275  
         {
 276  0
             caseInsensitiveIssueLinkTemplatePerSystem = new CaseInsensitiveMap( issueLinkTemplatePerSystem );
 277  
         }
 278  
 
 279  
         // Set good default values for issue management systems here, but only
 280  
         // if they have not been configured already by the user
 281  0
         addIssueLinkTemplate( ChangesReportGenerator.DEFAULT_ISSUE_SYSTEM_KEY, issueLinkTemplate );
 282  0
         addIssueLinkTemplate( "Bitbucket", "%URL%/issue/%ISSUE%" );
 283  0
         addIssueLinkTemplate( "Bugzilla", "%URL%/show_bug.cgi?id=%ISSUE%" );
 284  0
         addIssueLinkTemplate( "GitHub", "%URL%/%ISSUE%" );
 285  0
         addIssueLinkTemplate( "GoogleCode", "%URL%/detail?id=%ISSUE%" );
 286  0
         addIssueLinkTemplate( "JIRA", "%URL%/%ISSUE%" );
 287  0
         addIssueLinkTemplate( "Mantis", "%URL%/view.php?id=%ISSUE%" );
 288  0
         addIssueLinkTemplate( "MKS", "%URL%/viewissue?selection=%ISSUE%" );
 289  0
         addIssueLinkTemplate( "Redmine", "%URL%/issues/show/%ISSUE%" );
 290  0
         addIssueLinkTemplate( "Scarab", "%URL%/issues/id/%ISSUE%" );
 291  0
         addIssueLinkTemplate( "SourceForge", "http://sourceforge.net/support/tracker.php?aid=%ISSUE%" );
 292  0
         addIssueLinkTemplate( "SourceForge2", "%URL%/%ISSUE%" );
 293  0
         addIssueLinkTemplate( "Trac", "%URL%/ticket/%ISSUE%" );
 294  0
         addIssueLinkTemplate( "Trackplus", "%URL%/printItem.action?key=%ISSUE%" );
 295  0
         addIssueLinkTemplate( "YouTrack", "%URL%/issue/%ISSUE%" );
 296  
         // @todo Add more issue management systems here
 297  
         // Remember to also add documentation in usage.apt.vm
 298  
 
 299  
         // Show the current issueLinkTemplatePerSystem configuration
 300  0
         logIssueLinkTemplatePerSystem( caseInsensitiveIssueLinkTemplatePerSystem );
 301  
 
 302  0
         report.setIssueLinksPerSystem( caseInsensitiveIssueLinkTemplatePerSystem );
 303  
 
 304  0
         report.setSystem( system );
 305  
 
 306  0
         report.setTeamlist ( teamlist );
 307  
 
 308  0
         report.setUrl( url );
 309  
 
 310  0
         report.setAddActionDate( addActionDate );
 311  
 
 312  0
         if ( StringUtils.isEmpty( url ) )
 313  
         {
 314  0
             getLog().warn( "No issue management URL defined in POM. Links to your issues will not work correctly." );
 315  
         }
 316  
 
 317  0
         report.doGenerateReport( getBundle( locale ), getSink() );
 318  
 
 319  
         // Copy the images
 320  0
         copyStaticResources();
 321  0
     }
 322  
 
 323  
     public String getDescription( Locale locale )
 324  
     {
 325  0
         return getBundle( locale ).getString( "report.issues.description" );
 326  
     }
 327  
 
 328  
     public String getName( Locale locale )
 329  
     {
 330  0
         return getBundle( locale ).getString( "report.issues.name" );
 331  
     }
 332  
 
 333  
     public String getOutputName()
 334  
     {
 335  0
         return "changes-report";
 336  
     }
 337  
 
 338  
     /* --------------------------------------------------------------------- */
 339  
     /* Private methods                                                       */
 340  
     /* --------------------------------------------------------------------- */
 341  
 
 342  
     /**
 343  
      * Parses specified changes.xml file. It also makes filtering if needed. If specified file doesn't exist
 344  
      * it will log warning and return <code>null</code>.
 345  
      *
 346  
      * @param changesXml changes xml file to parse
 347  
      * @param project maven project to parse changes for
 348  
      * @param additionalProperties additional properties used for filtering
 349  
      * @return parsed <code>ChangesXML</code> instance or null if file doesn't exist
 350  
      * @throws MavenReportException if any errors occurs while parsing
 351  
      */
 352  
     private ChangesXML getChangesFromFile( File changesXml, MavenProject project, Properties additionalProperties )
 353  
         throws MavenReportException
 354  
     {
 355  0
         if ( !changesXml.exists() )
 356  
         {
 357  0
             getLog().warn( "changes.xml file " + changesXml.getAbsolutePath() + " does not exist." );
 358  0
             return null;
 359  
         }
 360  
 
 361  0
         if ( filteringChanges )
 362  
         {
 363  0
             if ( !filteredOutputDirectory.exists() )
 364  
             {
 365  0
                 filteredOutputDirectory.mkdirs();
 366  
             }
 367  0
             XmlStreamReader xmlStreamReader = null;
 368  
             try
 369  
             {
 370  
                 // so we get encoding from the file itself
 371  0
                 xmlStreamReader = ReaderFactory.newXmlReader( changesXml );
 372  0
                 String encoding = xmlStreamReader.getEncoding();
 373  0
                 File resultFile = new File( filteredOutputDirectory, project.getGroupId() + "." + project.getArtifactId() + "-changes.xml" );
 374  
 
 375  0
                 final MavenFileFilterRequest mavenFileFilterRequest =
 376  
                         new MavenFileFilterRequest( changesXml, resultFile, true, project, Collections.EMPTY_LIST, false,
 377  
                                 encoding, session, additionalProperties );
 378  0
                 mavenFileFilter.copyFile( mavenFileFilterRequest );
 379  0
                 changesXml = resultFile;
 380  
             }
 381  0
             catch ( IOException e )
 382  
             {
 383  0
                 throw new MavenReportException( "Exception during filtering changes file : " + e.getMessage(), e );
 384  
             }
 385  0
             catch ( MavenFilteringException e )
 386  
             {
 387  0
                 throw new MavenReportException( "Exception during filtering changes file : " + e.getMessage(), e );
 388  
             }
 389  
             finally
 390  
             {
 391  0
                 if ( xmlStreamReader != null )
 392  
                 {
 393  0
                     IOUtil.close( xmlStreamReader );
 394  
                 }
 395  
             }
 396  
 
 397  
         }
 398  0
         return new ChangesXML( changesXml, getLog() );
 399  
     }
 400  
 
 401  
     /**
 402  
      * Add the issue link template for the given issue management system,
 403  
      * but only if it has not already been configured.
 404  
      *
 405  
      * @param system The issue management system
 406  
      * @param issueLinkTemplate The issue link template to use
 407  
      * @since 2.4
 408  
      */
 409  
     private void addIssueLinkTemplate( String system, String issueLinkTemplate )
 410  
     {
 411  0
         if ( caseInsensitiveIssueLinkTemplatePerSystem == null )
 412  
         {
 413  0
             caseInsensitiveIssueLinkTemplatePerSystem = new CaseInsensitiveMap();
 414  
         }
 415  0
         if ( !caseInsensitiveIssueLinkTemplatePerSystem.containsKey( system ) )
 416  
         {
 417  0
             caseInsensitiveIssueLinkTemplatePerSystem.put( system, issueLinkTemplate );
 418  
         }
 419  0
     }
 420  
 
 421  
     private void copyStaticResources()
 422  
         throws MavenReportException
 423  
     {
 424  0
         final String pluginResourcesBase = "org/apache/maven/plugin/changes";
 425  0
         String resourceNames[] = {
 426  
             "images/add.gif",
 427  
             "images/fix.gif",
 428  
             "images/icon_help_sml.gif",
 429  
             "images/remove.gif",
 430  
             "images/rss.png",
 431  
             "images/update.gif" };
 432  
         try
 433  
         {
 434  0
             getLog().debug( "Copying static resources." );
 435  0
             for ( int i = 0; i < resourceNames.length; i++ )
 436  
             {
 437  0
                 URL url = this.getClass().getClassLoader().getResource( pluginResourcesBase + "/" + resourceNames[i] );
 438  0
                 FileUtils.copyURLToFile( url, new File( getReportOutputDirectory(), resourceNames[i] ) );
 439  
             }
 440  
         }
 441  0
         catch ( IOException e )
 442  
         {
 443  0
             throw new MavenReportException( "Unable to copy static resources." );
 444  0
         }
 445  0
     }
 446  
 
 447  
     private ResourceBundle getBundle( Locale locale )
 448  
     {
 449  0
         return ResourceBundle.getBundle( "changes-report", locale, this.getClass().getClassLoader() );
 450  
     }
 451  
 
 452  
     protected String getTeamlist()
 453  
     {
 454  0
         return teamlist;
 455  
     }
 456  
 
 457  
     private void logIssueLinkTemplatePerSystem( Map issueLinkTemplatePerSystem )
 458  
     {
 459  0
         if ( getLog().isDebugEnabled() )
 460  
         {
 461  0
             if ( issueLinkTemplatePerSystem == null )
 462  
             {
 463  0
                 getLog().debug( "No issueLinkTemplatePerSystem configuration was found" );
 464  
             }
 465  
             else
 466  
             {
 467  0
                 Iterator iterator = issueLinkTemplatePerSystem.entrySet().iterator();
 468  0
                 while ( iterator.hasNext() )
 469  
                 {
 470  0
                     Map.Entry entry = (Map.Entry) iterator.next();
 471  0
                     getLog().debug( "issueLinkTemplatePerSystem[" + entry.getKey() + "] = " + entry.getValue() );
 472  0
                 }
 473  
             }
 474  
         }
 475  0
     }
 476  
 }