View Javadoc

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.Locale;
29  import java.util.Map;
30  import java.util.Properties;
31  import java.util.ResourceBundle;
32  
33  import org.apache.maven.execution.MavenSession;
34  import org.apache.maven.reporting.MavenReportException;
35  import org.apache.maven.shared.filtering.MavenFileFilter;
36  import org.apache.maven.shared.filtering.MavenFileFilterRequest;
37  import org.apache.maven.shared.filtering.MavenFilteringException;
38  import org.codehaus.plexus.util.FileUtils;
39  import org.codehaus.plexus.util.IOUtil;
40  import org.codehaus.plexus.util.ReaderFactory;
41  import org.codehaus.plexus.util.xml.XmlStreamReader;
42  
43  /**
44   * Goal which creates a nicely formatted Changes Report in html format from a changes.xml file.
45   *
46   * @goal changes-report
47   * @author <a href="mailto:jruiz@exist.com">Johnny R. Ruiz III</a>
48   * @version $Id: ChangesMojo.html 816592 2012-05-08 12:40:21Z hboutemy $
49   */
50  public class ChangesMojo
51      extends AbstractChangesReport
52  {
53      /**
54       * The path of the <code>changes.xml</code> file that will be converted into an HTML report.
55       *
56       * @parameter expression="${changes.xmlPath}" default-value="src/changes/changes.xml"
57       */
58      private File xmlPath;
59  
60      /**
61       * Template string that is used to discover the URL to use to display an issue report.
62       * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the
63       * <code>&lt;issueManagement&gt;/&lt;url&gt;</code> value from the POM, and removing the last '/'
64       * and everything that comes after it. <code>%ISSUE%</code>: this is the issue number.
65       * <p>
66       * <strong>Note:</strong> In versions of this plugin prior to 2.0-beta-2 this parameter was called
67       * <code>link_template</code>.
68       * </p>
69       *
70       * @parameter expression="${changes.issueLinkTemplate}" default-value="%URL%/ViewIssue.jspa?key=%ISSUE%"
71       * @since 2.0-beta-2
72       * @deprecated As of 2.1 use issueLinkTemplatePerSystem : this one will be with system default
73       */
74      private String issueLinkTemplate;
75      
76      /**
77       * Template strings per system that is used to discover the URL to use to display an issue report. Each key in this
78       * map denotes the (case-sensitive) identifier of the issue tracking system and its value gives the URL template.
79       * <p>
80       * There are 2 template tokens you can use. <code>%URL%</code>: this is computed by getting the
81       * <code>&lt;issueManagement&gt;/&lt;url&gt;</code> value from the POM, and removing the last '/'
82       * and everything that comes after it. <code>%ISSUE%</code>: this is the issue number.
83       * </p>
84       * <p>
85       * <strong>Note:</strong> The deprecated issueLinkTemplate will be used for a system called "default".
86       * </p>
87       *
88       * @parameter
89       * @since 2.1
90       */
91      private Map issueLinkTemplatePerSystem;
92  
93      /**
94       * @parameter default-value="${project.issueManagement.url}"
95       * @readonly
96       */
97      private String url;
98  
99      /**
100      * A flag whether the report should also include the dates of individual actions. If set to <code>false</code>, only
101      * the dates of releases will be written to the report.
102      *
103      * @parameter expression="${changes.addActionDate}" default-value="false"
104      * @since 2.1
105      */
106     private boolean addActionDate;
107     
108     /**
109      *
110      * @component
111      *
112      * @since 2.2
113      */
114     private MavenFileFilter mavenFileFilter;
115     
116     /**
117      * @parameter expression="${session}"
118      * @readonly
119      * @required
120      *
121      * @since 2.2
122      *
123      */
124     protected MavenSession session;
125     
126     /**
127      * applying filtering filtering "a la" resources plugin
128      *
129      * @parameter default-value="false"
130      *
131      * @since 2.2
132      */
133     private boolean filteringChanges;
134     
135     /**
136      * The directory for interpolated changes.xml.
137      *
138      * @parameter expression="${project.build.directory}/changes"
139      * @required
140      * @readonly
141      *
142      * @since 2.2
143      *
144      */
145     private File filteredOutputDirectory;    
146     
147     /**
148      *
149      * Format to use for publishDate. The value will be available with the following expression ${publishDate}
150      *
151      * @see SimpleDateFormat
152      *
153      * @parameter default-value="yyyy-MM-dd"
154      *
155      * @since 2.2
156      *
157      */
158     private String publishDateFormat;
159     
160     /**
161     *
162     * Locale to use for publishDate when formatting
163     *
164     * @see Locale
165     *
166     * @parameter default-value="en"
167     *
168     * @since 2.2
169     *
170     */
171     private String publishDateLocale;
172     
173     
174     public boolean canGenerateReport()
175     {
176         return xmlPath.isFile();
177     }
178 
179     private void copyStaticResources()
180         throws MavenReportException
181     {
182         final String pluginResourcesBase = "org/apache/maven/plugin/changes";
183         String resourceNames[] = {
184             "images/add.gif",
185             "images/fix.gif",
186             "images/icon_help_sml.gif",
187             "images/remove.gif",
188             "images/rss.png",
189             "images/update.gif" };
190         try
191         {
192             getLog().debug( "Copying static resources." );
193             for ( int i = 0; i < resourceNames.length; i++ )
194             {
195                 URL url = this.getClass().getClassLoader().getResource( pluginResourcesBase + "/" + resourceNames[i] );
196                 FileUtils.copyURLToFile( url, new File( getReportOutputDirectory(), resourceNames[i] ) );
197             }
198         }
199         catch ( IOException e )
200         {
201             throw new MavenReportException( "Unable to copy static resources." );
202         }
203     }
204 
205     public void executeReport( Locale locale )
206         throws MavenReportException
207     {
208         
209         if ( !xmlPath.exists() )
210         {
211             getLog().warn( "changes.xml file " + xmlPath.getAbsolutePath() + " does not exist." );
212             return;
213         }
214         if ( filteringChanges )
215         {
216             if ( !filteredOutputDirectory.exists() )
217             {
218                 filteredOutputDirectory.mkdirs();
219             }
220             XmlStreamReader xmlStreamReader = null;
221             try
222             {
223                 // so we get encoding from the file itself
224                 xmlStreamReader = ReaderFactory.newXmlReader( xmlPath );
225                 String encoding = xmlStreamReader.getEncoding();
226                 File resultFile = new File( filteredOutputDirectory, "changes.xml" );
227                 Date now = new Date();
228                 SimpleDateFormat simpleDateFormat =
229                     new SimpleDateFormat( publishDateFormat, new Locale( publishDateLocale ) );
230                 Properties additionnalProperties = new Properties();
231                 additionnalProperties.put( "publishDate", simpleDateFormat.format( now ) );
232                 MavenFileFilterRequest mavenFileFilterRequest =
233                     new MavenFileFilterRequest( xmlPath, resultFile, true, project, Collections.EMPTY_LIST, false,
234                                                 encoding, session, additionnalProperties );
235                 mavenFileFilter.copyFile( mavenFileFilterRequest );
236                 xmlPath = resultFile;
237             }
238             catch ( IOException e )
239             {
240                 throw new MavenReportException( "Exception during filtering changes file : " + e.getMessage(), e );
241             }
242             catch ( MavenFilteringException e )
243             {
244                 throw new MavenReportException( "Exception during filtering changes file : " + e.getMessage(), e );
245             }
246             finally
247             {
248                 if ( xmlStreamReader != null )
249                 {
250                     IOUtil.close( xmlStreamReader );
251                 }
252             }
253 
254         }
255 
256         ChangesReportGenerator report = new ChangesReportGenerator( xmlPath, getLog() );
257         
258         report.setIssueLinksPerSystem( issueLinkTemplatePerSystem );
259         report.setIssueLink( issueLinkTemplate );
260         
261         report.setUrl( url );
262 
263         report.setAddActionDate( addActionDate );
264         
265         if ( !report.canGenerateIssueLinks() )
266         {
267             getLog().warn( "No issue management URL defined in POM. Links to your issues will not work correctly." );
268         }
269 
270         report.doGenerateReport( getBundle( locale ), getSink() );
271 
272         // Copy the images
273         copyStaticResources();
274     }
275 
276     public String getName( Locale locale )
277     {
278         return getBundle( locale ).getString( "report.changes.name" );
279     }
280 
281     public String getDescription( Locale locale )
282     {
283         return getBundle( locale ).getString( "report.changes.description" );
284     }
285 
286     public String getOutputName()
287     {
288         return "changes-report";
289     }
290 
291     private ResourceBundle getBundle( Locale locale )
292     {
293         return ResourceBundle.getBundle( "changes-report", locale, this.getClass().getClassLoader() );
294     }
295 }