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><issueManagement>/<url></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><issueManagement>/<url></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 }