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 getLog().info("Maven Plugin Plugin Report generation skipped.");
167 return false;
168 }
169
170 if (!(enhancedPluginXmlFile != null && enhancedPluginXmlFile.isFile() && enhancedPluginXmlFile.canRead())) {
171 return false;
172 }
173
174 return true;
175 }
176
177
178
179
180 @Override
181 protected void executeReport(Locale locale) throws MavenReportException {
182 PluginDescriptor pluginDescriptor = extractPluginDescriptor();
183
184
185 generateMojosDocumentation(pluginDescriptor, locale);
186
187 if (requirementsHistories.isEmpty()) {
188
189 String v = null;
190 try {
191 List<Version> versions = discoverVersions(requirementsHistoryDetectionRange);
192 if (versions.isEmpty()) {
193 getLog().info("No plugin history found for range " + requirementsHistoryDetectionRange);
194 } else {
195 getLog().info("Detecting plugin requirements history for range "
196 + requirementsHistoryDetectionRange + ": "
197 + versions.size() + " releases, from " + versions.get(0) + " to "
198 + versions.get(versions.size() - 1));
199 }
200
201 Collections.reverse(versions);
202 for (Version version : versions) {
203 v = version.toString();
204 MavenProject versionProject = buildMavenProject(v);
205 RequirementsHistory requirements = RequirementsHistory.discoverRequirements(versionProject);
206 requirementsHistories.add(requirements);
207 getLog().info(" - " + requirements);
208 }
209 } catch (VersionRangeResolutionException vrre) {
210 throw new MavenReportException(
211 "Cannot resolve past versions " + requirementsHistoryDetectionRange, vrre);
212 } catch (ProjectBuildingException pbe) {
213 throw new MavenReportException("Cannot resolve MavenProject for version " + v, pbe);
214 }
215 }
216
217
218 PluginOverviewRenderer r = new PluginOverviewRenderer(
219 getSink(), i18n, locale, getProject(), requirementsHistories, pluginDescriptor, hasExtensionsToLoad);
220 r.render();
221 }
222
223 private PluginDescriptor extractPluginDescriptor() throws MavenReportException {
224 PluginDescriptorBuilder builder = new EnhancedPluginDescriptorBuilder(rtInfo);
225
226 try (Reader input = new XmlStreamReader(Files.newInputStream(enhancedPluginXmlFile.toPath()))) {
227 return builder.build(input);
228 } catch (IOException | PlexusConfigurationException e) {
229 throw new MavenReportException("Error extracting plugin descriptor from " + enhancedPluginXmlFile, e);
230 }
231 }
232
233
234
235
236
237
238 private String getI18nString(Locale locale, String key) {
239 return i18n.getString("plugin-report", locale, "report.plugin." + key);
240 }
241
242
243
244
245 @Override
246 public String getName(Locale locale) {
247 return getI18nString(locale, "name");
248 }
249
250
251
252
253 @Override
254 public String getDescription(Locale locale) {
255 return getI18nString(locale, "description");
256 }
257
258
259
260
261 @Override
262 public String getOutputName() {
263 return "plugin-info";
264 }
265
266
267
268
269
270
271
272
273
274 private void generateMojosDocumentation(PluginDescriptor pluginDescriptor, Locale locale)
275 throws MavenReportException {
276
277 if (pluginDescriptor.getMojos() != null) {
278 for (MojoDescriptor descriptor : pluginDescriptor.getMojos()) {
279 GoalRenderer renderer;
280 try {
281 String filename = descriptor.getGoal() + "-mojo.html";
282 Sink sink = getSinkFactory().createSink(getReportOutputDirectory(), filename);
283 renderer = new GoalRenderer(
284 sink,
285 i18n,
286 locale,
287 project,
288 descriptor,
289 getReportOutputDirectory(),
290 disableInternalJavadocLinkValidation,
291 getLog());
292 } catch (IOException e) {
293 throw new MavenReportException("Cannot generate sink for mojo " + descriptor.getGoal(), e);
294 }
295 renderer.render();
296 }
297 }
298 }
299
300 private List<Version> discoverVersions(String range) throws VersionRangeResolutionException {
301 MavenProject currentProject = mavenSession.getCurrentProject();
302 VersionRangeRequest rangeRequest = new VersionRangeRequest();
303 rangeRequest.setArtifact(
304 new DefaultArtifact(currentProject.getGroupId() + ":" + currentProject.getArtifactId() + ":" + range));
305 rangeRequest.setRepositories(
306 RepositoryUtils.toRepos(mavenSession.getCurrentProject().getRemoteArtifactRepositories()));
307 VersionRangeResult rangeResult =
308 repositorySystem.resolveVersionRange(mavenSession.getRepositorySession(), rangeRequest);
309 return rangeResult.getVersions().stream()
310 .filter(version -> !ArtifactUtils.isSnapshot(version.toString()))
311 .collect(Collectors.toList());
312 }
313
314 private MavenProject buildMavenProject(String version) throws ProjectBuildingException {
315 MavenProject currentProject = mavenSession.getCurrentProject();
316 ProjectBuildingRequest buildRequest = new DefaultProjectBuildingRequest();
317 buildRequest.setLocalRepository(mavenSession.getLocalRepository());
318 buildRequest.setRemoteRepositories(mavenSession.getCurrentProject().getRemoteArtifactRepositories());
319 buildRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
320 buildRequest.setProcessPlugins(false);
321 buildRequest.setRepositoryMerging(ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT);
322 buildRequest.setSystemProperties(mavenSession.getSystemProperties());
323 buildRequest.setUserProperties(mavenSession.getUserProperties());
324 buildRequest.setRepositorySession(mavenSession.getRepositorySession());
325 return projectBuilder
326 .build(
327 RepositoryUtils.toArtifact(new DefaultArtifact(currentProject.getGroupId() + ":"
328 + currentProject.getArtifactId() + ":pom:" + version)),
329 buildRequest)
330 .getProject();
331 }
332 }