1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.plugin.report;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.nio.file.Files;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.stream.Collectors;
30
31 import org.apache.maven.RepositoryUtils;
32 import org.apache.maven.artifact.ArtifactUtils;
33 import org.apache.maven.doxia.sink.Sink;
34 import org.apache.maven.execution.MavenSession;
35 import org.apache.maven.model.building.ModelBuildingRequest;
36 import org.apache.maven.plugin.descriptor.MojoDescriptor;
37 import org.apache.maven.plugin.descriptor.PluginDescriptor;
38 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
39 import org.apache.maven.plugins.annotations.Component;
40 import org.apache.maven.plugins.annotations.Execute;
41 import org.apache.maven.plugins.annotations.LifecyclePhase;
42 import org.apache.maven.plugins.annotations.Mojo;
43 import org.apache.maven.plugins.annotations.Parameter;
44 import org.apache.maven.plugins.plugin.descriptor.EnhancedPluginDescriptorBuilder;
45 import org.apache.maven.project.DefaultProjectBuildingRequest;
46 import org.apache.maven.project.MavenProject;
47 import org.apache.maven.project.ProjectBuilder;
48 import org.apache.maven.project.ProjectBuildingException;
49 import org.apache.maven.project.ProjectBuildingRequest;
50 import org.apache.maven.reporting.AbstractMavenReport;
51 import org.apache.maven.reporting.MavenReportException;
52 import org.apache.maven.rtinfo.RuntimeInformation;
53 import org.codehaus.plexus.configuration.PlexusConfigurationException;
54 import org.codehaus.plexus.i18n.I18N;
55 import org.codehaus.plexus.util.xml.XmlStreamReader;
56 import org.eclipse.aether.RepositorySystem;
57 import org.eclipse.aether.artifact.DefaultArtifact;
58 import org.eclipse.aether.resolution.VersionRangeRequest;
59 import org.eclipse.aether.resolution.VersionRangeResolutionException;
60 import org.eclipse.aether.resolution.VersionRangeResult;
61 import org.eclipse.aether.version.Version;
62
63
64
65
66
67
68
69
70
71
72 @Mojo(name = "report", threadSafe = true)
73 @Execute(phase = LifecyclePhase.PROCESS_CLASSES)
74 public class PluginReport extends AbstractMavenReport {
75
76
77
78
79
80
81 @Parameter(defaultValue = "false", property = "maven.plugin.report.skip")
82 private boolean skip;
83
84
85
86
87
88
89
90 @Parameter(defaultValue = "false", property = "maven.plugin.report.hasExtensionsToLoad")
91 private boolean hasExtensionsToLoad;
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 @Parameter
111 private List<RequirementsHistory> requirementsHistories = new ArrayList<>();
112
113
114
115
116
117
118 @Parameter(defaultValue = "[0,)")
119 private String requirementsHistoryDetectionRange;
120
121 @Component
122 private RuntimeInformation rtInfo;
123
124
125
126
127 @Component
128 private I18N i18n;
129
130
131
132
133
134
135 @Parameter(defaultValue = "${project.build.directory}/plugin-enhanced.xml", required = true, readonly = true)
136 private File enhancedPluginXmlFile;
137
138
139
140
141
142
143
144
145
146
147
148 @Parameter(property = "maven.plugin.report.disableInternalJavadocLinkValidation")
149 private boolean disableInternalJavadocLinkValidation;
150
151 @Component
152 private MavenSession mavenSession;
153
154 @Component
155 private RepositorySystem repositorySystem;
156
157 @Component
158 private ProjectBuilder projectBuilder;
159
160
161
162
163 @Override
164 public boolean canGenerateReport() {
165 if (skip) {
166 return false;
167 }
168
169 if (!(enhancedPluginXmlFile != null && enhancedPluginXmlFile.isFile() && enhancedPluginXmlFile.canRead())) {
170 return false;
171 }
172
173 return true;
174 }
175
176
177
178
179 @Override
180 protected void executeReport(Locale locale) throws MavenReportException {
181 PluginDescriptor pluginDescriptor = extractPluginDescriptor();
182
183
184 generateMojosDocumentation(pluginDescriptor, locale);
185
186 if (requirementsHistories.isEmpty()) {
187
188 String v = null;
189 try {
190 List<Version> versions = discoverVersions(requirementsHistoryDetectionRange);
191 if (versions.isEmpty()) {
192 getLog().info("No plugin history found for range " + requirementsHistoryDetectionRange);
193 } else {
194 getLog().info("Detecting plugin requirements history for range "
195 + requirementsHistoryDetectionRange + ": "
196 + versions.size() + " releases, from " + versions.get(0) + " to "
197 + versions.get(versions.size() - 1));
198 }
199
200 Collections.reverse(versions);
201 for (Version version : versions) {
202 v = version.toString();
203 MavenProject versionProject = buildMavenProject(v);
204 RequirementsHistory requirements = RequirementsHistory.discoverRequirements(versionProject);
205 requirementsHistories.add(requirements);
206 getLog().debug(" - " + requirements);
207 }
208 } catch (VersionRangeResolutionException vrre) {
209 throw new MavenReportException(
210 "Cannot resolve past versions " + requirementsHistoryDetectionRange, vrre);
211 } catch (ProjectBuildingException pbe) {
212 throw new MavenReportException("Cannot resolve MavenProject for version " + v, pbe);
213 }
214 }
215
216
217 PluginOverviewRenderer r = new PluginOverviewRenderer(
218 getSink(), i18n, locale, getProject(), requirementsHistories, pluginDescriptor, hasExtensionsToLoad);
219 r.render();
220 }
221
222 private PluginDescriptor extractPluginDescriptor() throws MavenReportException {
223 PluginDescriptorBuilder builder = new EnhancedPluginDescriptorBuilder(rtInfo);
224
225 try (Reader input = new XmlStreamReader(Files.newInputStream(enhancedPluginXmlFile.toPath()))) {
226 return builder.build(input);
227 } catch (IOException | PlexusConfigurationException e) {
228 throw new MavenReportException("Error extracting plugin descriptor from " + enhancedPluginXmlFile, e);
229 }
230 }
231
232
233
234
235
236
237 private String getI18nString(Locale locale, String key) {
238 return i18n.getString("plugin-report", locale, "report.plugin." + key);
239 }
240
241
242
243
244 @Override
245 public String getName(Locale locale) {
246 return getI18nString(locale, "name");
247 }
248
249
250
251
252 @Override
253 public String getDescription(Locale locale) {
254 return getI18nString(locale, "description");
255 }
256
257
258
259
260 @Override
261 public String getOutputName() {
262 return "plugin-info";
263 }
264
265
266
267
268
269
270
271
272
273 private void generateMojosDocumentation(PluginDescriptor pluginDescriptor, Locale locale)
274 throws MavenReportException {
275 if (pluginDescriptor.getMojos() != null) {
276 for (MojoDescriptor descriptor : pluginDescriptor.getMojos()) {
277 GoalRenderer renderer;
278 try {
279 String filename = descriptor.getGoal() + "-mojo.html";
280 Sink sink = getSinkFactory().createSink(getReportOutputDirectory(), filename);
281 renderer = new GoalRenderer(
282 sink,
283 i18n,
284 locale,
285 project,
286 descriptor,
287 getReportOutputDirectory(),
288 disableInternalJavadocLinkValidation,
289 getLog());
290 } catch (IOException e) {
291 throw new MavenReportException("Cannot generate sink for mojo " + descriptor.getGoal(), e);
292 }
293 renderer.render();
294 }
295 }
296 }
297
298 private List<Version> discoverVersions(String range) throws VersionRangeResolutionException {
299 MavenProject currentProject = mavenSession.getCurrentProject();
300 VersionRangeRequest rangeRequest = new VersionRangeRequest();
301 rangeRequest.setArtifact(
302 new DefaultArtifact(currentProject.getGroupId() + ":" + currentProject.getArtifactId() + ":" + range));
303 rangeRequest.setRepositories(
304 RepositoryUtils.toRepos(mavenSession.getCurrentProject().getRemoteArtifactRepositories()));
305 VersionRangeResult rangeResult =
306 repositorySystem.resolveVersionRange(mavenSession.getRepositorySession(), rangeRequest);
307 return rangeResult.getVersions().stream()
308 .filter(version -> !ArtifactUtils.isSnapshot(version.toString()))
309 .collect(Collectors.toList());
310 }
311
312 private MavenProject buildMavenProject(String version) throws ProjectBuildingException {
313 MavenProject currentProject = mavenSession.getCurrentProject();
314 ProjectBuildingRequest buildRequest = new DefaultProjectBuildingRequest();
315 buildRequest.setLocalRepository(mavenSession.getLocalRepository());
316 buildRequest.setRemoteRepositories(mavenSession.getCurrentProject().getRemoteArtifactRepositories());
317 buildRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
318 buildRequest.setProcessPlugins(false);
319 buildRequest.setRepositoryMerging(ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT);
320 buildRequest.setSystemProperties(mavenSession.getSystemProperties());
321 buildRequest.setUserProperties(mavenSession.getUserProperties());
322 buildRequest.setRepositorySession(mavenSession.getRepositorySession());
323 return projectBuilder
324 .build(
325 RepositoryUtils.toArtifact(new DefaultArtifact(currentProject.getGroupId() + ":"
326 + currentProject.getArtifactId() + ":pom:" + version)),
327 buildRequest)
328 .getProject();
329 }
330 }