org.codehaus.plexus
diff --git a/maven-plugin-report-plugin/src/it/mplugin-191/verify.groovy b/maven-plugin-report-plugin/src/it/mplugin-191/verify.groovy
index 5a33abdd5..24506b919 100644
--- a/maven-plugin-report-plugin/src/it/mplugin-191/verify.groovy
+++ b/maven-plugin-report-plugin/src/it/mplugin-191/verify.groovy
@@ -18,7 +18,7 @@
File pluginInfo = new File( basedir, "target/site/plugin-info.html" );
assert pluginInfo.isFile()
-File touchMojo = new File( basedir, "target/generated-site/xdoc/touch-mojo.xml" );
+File touchMojo = new File( basedir, "target/site/touch-mojo.html" );
assert touchMojo.isFile()
return true;
diff --git a/maven-plugin-report-plugin/src/it/mplugin-319_report-since/verify.groovy b/maven-plugin-report-plugin/src/it/mplugin-319_report-since/verify.groovy
index 21c533288..877d8f83b 100644
--- a/maven-plugin-report-plugin/src/it/mplugin-319_report-since/verify.groovy
+++ b/maven-plugin-report-plugin/src/it/mplugin-319_report-since/verify.groovy
@@ -16,11 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-assert new File( basedir, 'target/generated-site' ).exists()
+assert new File( basedir, 'target/site/noop-mojo.html' ).exists()
-content = new File( basedir, 'target/generated-site/xdoc/noop-mojo.xml' ).text
+content = new File( basedir, 'target/site/noop-mojo.html' ).text
-assert content.contains( 'Since version: 1.0
' )
+assert content.contains( 'Since version: 1.0
.' )
assert content.contains( '- | ' )
assert content.contains( '1.1 | ' )
assert content.contains( 'Since: 1.1
' )
diff --git a/maven-plugin-report-plugin/src/it/mplugin-394_report-encoding/verify.groovy b/maven-plugin-report-plugin/src/it/mplugin-394_report-encoding/verify.groovy
index f7699228c..e10b63081 100644
--- a/maven-plugin-report-plugin/src/it/mplugin-394_report-encoding/verify.groovy
+++ b/maven-plugin-report-plugin/src/it/mplugin-394_report-encoding/verify.groovy
@@ -17,7 +17,7 @@
* under the License.
*/
-generated = new File( basedir, "target/generated-site/xdoc/test-mojo.xml").getText("UTF-8")
+generated = new File( basedir, "target/site/test-mojo.html").getText("UTF-8")
assert generated.contains("Mojo-Description with some non-ASCII characters: €àáâãäåæòóôõöø")
assert generated.contains("Parameter-Description with some non-ASCII characters: ÈÉÊË€")
diff --git a/maven-plugin-report-plugin/src/it/plugin-report-with-javadoc-links/verify.groovy b/maven-plugin-report-plugin/src/it/plugin-report-with-javadoc-links/verify.groovy
index 5eb43a120..158ea3e8d 100644
--- a/maven-plugin-report-plugin/src/it/plugin-report-with-javadoc-links/verify.groovy
+++ b/maven-plugin-report-plugin/src/it/plugin-report-with-javadoc-links/verify.groovy
@@ -21,13 +21,13 @@ def mojoDoc = new File( basedir, 'target/site/test-mojo.html' )
assert mojoDoc.isFile()
-assert mojoDoc.text.contains('See also: java.util.Collections') // mojo description see javadoc tag
+assert mojoDoc.text.contains('See also: java.util.Collections') // mojo description see javadoc tag
assert mojoDoc.text.contains('beans parameter leveraging SimpleBean
.') // parameter description
-assert mojoDoc.text.contains('Collection<SimpleBean> | ') // type link in parameter overview
-assert mojoDoc.text.contains('Type: java.util.Collection<org.SimpleBean>
') // type link in parameter details
+assert mojoDoc.text.contains('Collection<SimpleBean> | ') // type link in parameter overview
+assert mojoDoc.text.contains('Type: java.util.Collection<org.SimpleBean>
') // type link in parameter details
-assert mojoDoc.text.contains('invalid javadoc reference org.apache.maven.artifact.Artifact
.
') // second parameter description with link being removed (as no javadoc site associated)
+assert mojoDoc.text.contains('invalid javadoc reference org.apache.maven.artifact.Artifact
') // second parameter description with link being removed (as no javadoc site associated)
// the third parameter contains an invalid link (as the internal link validation has been switched off)
-assert mojoDoc.text.contains(' org.internal.PrivateBean
')
+assert mojoDoc.text.contains(' org.internal.PrivateBean
')
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/AbstractPluginReportRenderer.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/AbstractPluginReportRenderer.java
new file mode 100644
index 000000000..d35634ec2
--- /dev/null
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/AbstractPluginReportRenderer.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.plugin.report;
+
+import java.util.Locale;
+
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReportRenderer;
+import org.codehaus.plexus.i18n.I18N;
+
+/** Base class for all reports generated by the plugin report plugin. */
+public abstract class AbstractPluginReportRenderer extends AbstractMavenReportRenderer {
+
+ private static final String RESOURCE_BASENAME = "plugin-report";
+
+ private final I18N i18n;
+
+ protected final Locale locale;
+
+ protected final MavenProject project;
+
+ protected AbstractPluginReportRenderer(Sink sink, Locale locale, I18N i18n, MavenProject project) {
+ super(sink);
+ this.i18n = i18n;
+ this.locale = locale;
+ this.project = project;
+ }
+
+ @Override
+ public String getTitle() {
+ return getI18nString("title");
+ }
+
+ /**
+ * Returns
+ * @param key The key .
+ * @return The translated string.
+ */
+ protected String getI18nString(String key) {
+ return getI18nString(getI18nSection(), key);
+ }
+
+ /**
+ * @param section The section.
+ * @param key The key to translate.
+ * @return the translated key.
+ */
+ protected String getI18nString(String section, String key) {
+ return i18n.getString(RESOURCE_BASENAME, locale, "report." + section + '.' + key);
+ }
+
+ /**
+ *
+ * @return the key prefix to be used with every key. Is prepended by {@code report.}.
+ */
+ protected abstract String getI18nSection();
+}
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/GoalRenderer.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/GoalRenderer.java
new file mode 100644
index 000000000..eac6c0c7d
--- /dev/null
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/GoalRenderer.java
@@ -0,0 +1,526 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.plugin.report;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.MessageFormat;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet.Semantics;
+import org.apache.maven.doxia.util.HtmlTools;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.tools.plugin.EnhancedParameterWrapper;
+import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
+import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator;
+import org.apache.maven.tools.plugin.util.PluginUtils;
+import org.codehaus.plexus.i18n.I18N;
+
+public class GoalRenderer extends AbstractPluginReportRenderer {
+
+ /** Regular expression matching an XHTML link with group 1 = link target, group 2 = link label. */
+ private static final Pattern HTML_LINK_PATTERN = Pattern.compile("(.*?)");
+
+ /** The directory where the generated site is written. Used for resolving relative links to javadoc. */
+ private final File reportOutputDirectory;
+
+ private final MojoDescriptor descriptor;
+ private final boolean disableInternalJavadocLinkValidation;
+
+ private final Log log;
+
+ public GoalRenderer(
+ Sink sink,
+ I18N i18n,
+ Locale locale,
+ MavenProject project,
+ MojoDescriptor descriptor,
+ File reportOutputDirectory,
+ boolean disableInternalJavadocLinkValidation,
+ Log log) {
+ super(sink, locale, i18n, project);
+ this.reportOutputDirectory = reportOutputDirectory;
+ this.descriptor = descriptor;
+ this.disableInternalJavadocLinkValidation = disableInternalJavadocLinkValidation;
+ this.log = log;
+ }
+
+ @Override
+ public String getTitle() {
+ return descriptor.getFullGoalName();
+ }
+
+ @Override
+ protected void renderBody() {
+ startSection(descriptor.getFullGoalName());
+ renderReportNotice();
+ renderDescription("fullname", descriptor.getPluginDescriptor().getId() + ":" + descriptor.getGoal(), false);
+
+ String context = "goal " + descriptor.getGoal();
+ if (StringUtils.isNotEmpty(descriptor.getDeprecated())) {
+ renderDescription("deprecated", getXhtmlWithValidatedLinks(descriptor.getDeprecated(), context), true);
+ }
+ if (StringUtils.isNotEmpty(descriptor.getDescription())) {
+ renderDescription("description", getXhtmlWithValidatedLinks(descriptor.getDescription(), context), true);
+ } else {
+ renderDescription("description", getI18nString("nodescription"), false);
+ }
+ renderAttributes();
+
+ List parameterList = filterParameters(
+ descriptor.getParameters() != null ? descriptor.getParameters() : Collections.emptyList());
+ if (parameterList.isEmpty()) {
+ startSection(getI18nString("parameters"));
+ sink.paragraph();
+ sink.text(getI18nString("noParameter"));
+ sink.paragraph_();
+ endSection();
+ } else {
+ renderParameterOverviewTable(
+ getI18nString("requiredParameters"),
+ parameterList.stream().filter(Parameter::isRequired).iterator());
+ renderParameterOverviewTable(
+ getI18nString("optionalParameters"),
+ parameterList.stream().filter(p -> !p.isRequired()).iterator());
+ renderParameterDetails(parameterList.iterator());
+ }
+ endSection();
+ }
+
+ /** Filter parameters to only retain those which must be documented, i.e. neither components nor read-only ones.
+ *
+ * @param parameterList not null
+ * @return the parameters list without components. */
+ private static List filterParameters(Collection parameterList) {
+ return parameterList.stream()
+ .filter(p -> p.isEditable()
+ && (p.getExpression() == null || !p.getExpression().startsWith("${component.")))
+ .collect(Collectors.toList());
+ }
+
+ private void renderReportNotice() {
+ if (PluginUtils.isMavenReport(descriptor.getImplementation(), project)) {
+ renderDescription("notice.prefix", getI18nString("notice.isMavenReport"), false);
+ }
+ }
+
+ /**
+ * A description consists of a term/prefix and the actual description text
+ */
+ private void renderDescription(String prefixKey, String description, boolean isHtmlMarkup) {
+ // TODO: convert to dt and dd elements
+ renderDescriptionPrefix(prefixKey);
+ sink.paragraph();
+ if (isHtmlMarkup) {
+ sink.rawText(description);
+ } else {
+ sink.text(description);
+ }
+ sink.paragraph_(); // p
+ }
+
+ private void renderDescriptionPrefix(String prefixKey) {
+ sink.paragraph();
+ sink.inline(Semantics.STRONG);
+ sink.text(getI18nString(prefixKey));
+ sink.inline_();
+ sink.text(":");
+ sink.paragraph_();
+ }
+
+ @SuppressWarnings("deprecation")
+ private void renderAttributes() {
+ renderDescriptionPrefix("attributes");
+ sink.list();
+
+ renderAttribute(descriptor.isProjectRequired(), "projectRequired");
+ renderAttribute(descriptor.isRequiresReports(), "reportingMojo");
+ renderAttribute(descriptor.isAggregator(), "aggregator");
+ renderAttribute(descriptor.isDirectInvocationOnly(), "directInvocationOnly");
+ renderAttribute(descriptor.isDependencyResolutionRequired(), "dependencyResolutionRequired");
+
+ if (descriptor instanceof ExtendedMojoDescriptor) {
+ ExtendedMojoDescriptor extendedDescriptor = (ExtendedMojoDescriptor) descriptor;
+ renderAttribute(extendedDescriptor.getDependencyCollectionRequired(), "dependencyCollectionRequired");
+ }
+
+ renderAttribute(descriptor.isThreadSafe(), "threadSafe");
+ renderAttribute(!descriptor.isThreadSafe(), "notThreadSafe");
+ renderAttribute(descriptor.getSince(), "since");
+ renderAttribute(descriptor.getPhase(), "phase");
+ renderAttribute(descriptor.getExecutePhase(), "executePhase");
+ renderAttribute(descriptor.getExecuteGoal(), "executeGoal");
+ renderAttribute(descriptor.getExecuteLifecycle(), "executeLifecycle");
+ renderAttribute(descriptor.isOnlineRequired(), "onlineRequired");
+ renderAttribute(!descriptor.isInheritedByDefault(), "notInheritedByDefault");
+
+ sink.list_();
+ }
+
+ private void renderAttribute(boolean condition, String attributeKey) {
+ renderAttribute(condition, attributeKey, Optional.empty());
+ }
+
+ private void renderAttribute(String conditionAndCodeArgument, String attributeKey) {
+ renderAttribute(
+ StringUtils.isNotEmpty(conditionAndCodeArgument),
+ attributeKey,
+ Optional.ofNullable(conditionAndCodeArgument));
+ }
+
+ private void renderAttribute(boolean condition, String attributeKey, Optional codeArgument) {
+ if (condition) {
+ sink.listItem();
+ linkPatternedText(getI18nString(attributeKey));
+ if (codeArgument.isPresent()) {
+ text(": ");
+ sink.inline(Semantics.CODE);
+ sink.text(codeArgument.get());
+ sink.inline_();
+ }
+ text(".");
+ sink.listItem_();
+ }
+ }
+
+ private void renderParameterOverviewTable(String title, Iterator parameters) {
+ // don't emit empty tables
+ if (!parameters.hasNext()) {
+ return;
+ }
+ startSection(title);
+ startTable();
+ tableHeader(new String[] {
+ getI18nString("parameter.name.header"),
+ getI18nString("parameter.type.header"),
+ getI18nString("parameter.since.header"),
+ getI18nString("parameter.description.header")
+ });
+ while (parameters.hasNext()) {
+ renderParameterOverviewTableRow(parameters.next());
+ }
+ endTable();
+ endSection();
+ }
+
+ private void renderTableCellWithCode(String text) {
+ renderTableCellWithCode(text, Optional.empty());
+ }
+
+ private void renderTableCellWithCode(String text, Optional link) {
+ sink.tableCell();
+ if (link.isPresent()) {
+ sink.link(link.get(), null);
+ }
+ sink.inline(Semantics.CODE);
+ sink.text(text);
+ sink.inline_();
+ if (link.isPresent()) {
+ sink.link_();
+ }
+ sink.tableCell_();
+ }
+
+ private void renderParameterOverviewTableRow(Parameter parameter) {
+ sink.tableRow();
+ // name
+ // link to appropriate section
+ renderTableCellWithCode(
+ format("parameter.name", parameter.getName()),
+ // no need for additional URI encoding as it returns only URI safe characters
+ Optional.of("#" + HtmlTools.encodeId(parameter.getName())));
+
+ // type
+ Map.Entry> type = getLinkedType(parameter, true);
+ renderTableCellWithCode(type.getKey(), type.getValue());
+
+ // since
+ String since = StringUtils.defaultIfEmpty(parameter.getSince(), "-");
+ renderTableCellWithCode(since);
+
+ // description
+ sink.tableCell();
+ String description;
+ String context = "Parameter " + parameter.getName() + " in goal " + descriptor.getGoal();
+ if (StringUtils.isNotEmpty(parameter.getDeprecated())) {
+ String deprecated = getXhtmlWithValidatedLinks(parameter.getDescription(), context);
+ description = format("parameter.deprecated", deprecated);
+ } else if (StringUtils.isNotEmpty(parameter.getDescription())) {
+ description = getXhtmlWithValidatedLinks(parameter.getDescription(), context);
+ } else {
+ description = getI18nString("nodescription");
+ }
+ sink.rawText(description);
+ renderTableCellDetail("parameter.defaultValue", parameter.getDefaultValue());
+ renderTableCellDetail("parameter.property", getPropertyFromExpression(parameter.getExpression()));
+ renderTableCellDetail("parameter.alias", parameter.getAlias());
+ sink.tableCell_();
+
+ sink.tableRow_();
+ }
+
+ private void renderParameterDetails(Iterator parameters) {
+
+ startSection(getI18nString("parameter.details"));
+
+ while (parameters.hasNext()) {
+ Parameter parameter = parameters.next();
+ // deprecated anchor for backwards-compatibility with XDoc (upper and lower case)
+ // TODO: remove once migrated to Doxia 2.x
+ sink.anchor(parameter.getName());
+
+ startSection(format("parameter.name", parameter.getName()));
+ sink.anchor_();
+ String context = "Parameter " + parameter.getName() + " in goal " + descriptor.getGoal();
+ if (StringUtils.isNotEmpty(parameter.getDeprecated())) {
+ sink.division();
+ String deprecated = getXhtmlWithValidatedLinks(parameter.getDeprecated(), context);
+ sink.rawText(format("parameter.deprecated", deprecated));
+ sink.division_();
+ }
+
+ sink.division();
+ if (StringUtils.isNotEmpty(parameter.getDescription())) {
+ sink.rawText(getXhtmlWithValidatedLinks(parameter.getDescription(), context));
+ } else {
+ sink.text(getI18nString("nodescription"));
+ }
+ sink.division_();
+
+ sink.list();
+ Map.Entry> typeAndLink = getLinkedType(parameter, false);
+ renderDetail(getI18nString("parameter.type"), typeAndLink.getKey(), typeAndLink.getValue());
+
+ if (StringUtils.isNotEmpty(parameter.getSince())) {
+ renderDetail(getI18nString("parameter.since"), parameter.getSince());
+ }
+
+ if (parameter.isRequired()) {
+ renderDetail(getI18nString("parameter.required"), getI18nString("yes"));
+ } else {
+ renderDetail(getI18nString("parameter.required"), getI18nString("no"));
+ }
+
+ String expression = parameter.getExpression();
+ String property = getPropertyFromExpression(expression);
+ if (property == null) {
+ renderDetail(getI18nString("parameter.expression"), expression);
+ } else {
+ renderDetail(getI18nString("parameter.property"), property);
+ }
+
+ renderDetail(getI18nString("parameter.defaultValue"), parameter.getDefaultValue());
+
+ renderDetail(getI18nString("parameter.alias"), parameter.getAlias());
+
+ sink.list_(); // ul
+
+ if (parameters.hasNext()) {
+ sink.horizontalRule();
+ }
+ endSection();
+ }
+ endSection();
+ }
+
+ private void renderTableCellDetail(String nameKey, String value) {
+ if (StringUtils.isNotEmpty(value)) {
+ sink.lineBreak();
+ sink.inline(Semantics.STRONG);
+ sink.text(getI18nString(nameKey));
+ sink.inline_();
+ sink.text(": ");
+ sink.inline(Semantics.CODE);
+ sink.text(value);
+ sink.inline_();
+ }
+ }
+
+ private void renderDetail(String param, String value) {
+ renderDetail(param, value, Optional.empty());
+ }
+
+ private void renderDetail(String param, String value, Optional valueLink) {
+ if (value != null && !value.isEmpty()) {
+ sink.listItem();
+ sink.inline(Semantics.STRONG);
+ sink.text(param);
+ sink.inline_();
+ sink.text(": ");
+ if (valueLink.isPresent()) {
+ sink.link(valueLink.get());
+ }
+ sink.inline(Semantics.CODE);
+ sink.text(value);
+ sink.inline_();
+ if (valueLink.isPresent()) {
+ sink.link_();
+ }
+ sink.listItem_();
+ }
+ }
+
+ private static String getPropertyFromExpression(String expression) {
+ if ((expression != null && !expression.isEmpty())
+ && expression.startsWith("${")
+ && expression.endsWith("}")
+ && !expression.substring(2).contains("${")) {
+ // expression="${xxx}" -> property="xxx"
+ return expression.substring(2, expression.length() - 1);
+ }
+ // no property can be extracted
+ return null;
+ }
+
+ static String getShortType(String type) {
+ // split into type arguments and main type
+ int startTypeArguments = type.indexOf('<');
+ if (startTypeArguments == -1) {
+ return getShortTypeOfSimpleType(type);
+ } else {
+ StringBuilder shortType = new StringBuilder();
+ shortType.append(getShortTypeOfSimpleType(type.substring(0, startTypeArguments)));
+ shortType
+ .append("<")
+ .append(getShortTypeOfTypeArgument(type.substring(startTypeArguments + 1, type.lastIndexOf(">"))))
+ .append(">");
+ return shortType.toString();
+ }
+ }
+
+ private static String getShortTypeOfTypeArgument(String type) {
+ String[] typeArguments = type.split(",\\s*");
+ StringBuilder shortType = new StringBuilder();
+ for (int i = 0; i < typeArguments.length; i++) {
+ String typeArgument = typeArguments[i];
+ if (typeArgument.contains("<")) {
+ // nested type arguments lead to ellipsis
+ return "...";
+ } else {
+ shortType.append(getShortTypeOfSimpleType(typeArgument));
+ if (i < typeArguments.length - 1) {
+ shortType.append(",");
+ }
+ }
+ }
+ return shortType.toString();
+ }
+
+ private static String getShortTypeOfSimpleType(String type) {
+ int index = type.lastIndexOf('.');
+ return type.substring(index + 1);
+ }
+
+ private Map.Entry> getLinkedType(Parameter parameter, boolean isShortType) {
+ final String typeValue;
+ if (isShortType) {
+ typeValue = getShortType(parameter.getType());
+ } else {
+ typeValue = parameter.getType();
+ }
+ URI uri = null;
+ if (parameter instanceof EnhancedParameterWrapper) {
+ EnhancedParameterWrapper enhancedParameter = (EnhancedParameterWrapper) parameter;
+ if (enhancedParameter.getTypeJavadocUrl() != null) {
+ URI javadocUrl = enhancedParameter.getTypeJavadocUrl();
+ // optionally check if link is valid
+ if (javadocUrl.isAbsolute()
+ || disableInternalJavadocLinkValidation
+ || JavadocLinkGenerator.isLinkValid(javadocUrl, reportOutputDirectory.toPath())) {
+ uri = enhancedParameter.getTypeJavadocUrl();
+ }
+ }
+ }
+ // rely on the encoded URI
+ return new SimpleEntry<>(typeValue, Optional.ofNullable(uri).map(URI::toASCIIString));
+ }
+
+ String getXhtmlWithValidatedLinks(String xhtmlText, String context) {
+ if (disableInternalJavadocLinkValidation) {
+ return xhtmlText;
+ }
+ StringBuffer sanitizedXhtmlText = new StringBuffer();
+ // find all links which are not absolute
+ Matcher matcher = HTML_LINK_PATTERN.matcher(xhtmlText);
+ while (matcher.find()) {
+ URI link;
+ try {
+ link = new URI(matcher.group(1));
+ if (!link.isAbsolute() && !JavadocLinkGenerator.isLinkValid(link, reportOutputDirectory.toPath())) {
+ matcher.appendReplacement(sanitizedXhtmlText, matcher.group(2));
+ log.debug(String.format("Removed invalid link %s in %s", link, context));
+ } else {
+ matcher.appendReplacement(sanitizedXhtmlText, matcher.group(0));
+ }
+ } catch (URISyntaxException e) {
+ log.warn(String.format(
+ "Invalid URI %s found in %s. Cannot validate, leave untouched", matcher.group(1), context));
+ matcher.appendReplacement(sanitizedXhtmlText, matcher.group(0));
+ }
+ }
+ matcher.appendTail(sanitizedXhtmlText);
+ return sanitizedXhtmlText.toString();
+ }
+
+ /** Convenience method.
+ *
+ * @param key not null
+ * @param arg1 not null
+ * @return Localized, formatted text identified by key
.
+ * @see #format(String, Object[]) */
+ private String format(String key, Object arg1) {
+ return format(key, new Object[] {arg1});
+ }
+
+ /** Looks up the value for key
in the ResourceBundle
, then formats that value for the specified
+ * Locale
using args
.
+ *
+ * @param key not null
+ * @param args not null
+ * @return Localized, formatted text identified by key
. */
+ private String format(String key, Object[] args) {
+ String pattern = getI18nString(key);
+ // we don't need quoting so spare us the confusion in the resource bundle to double them up in some keys
+ pattern = StringUtils.replace(pattern, "'", "''");
+
+ MessageFormat messageFormat = new MessageFormat(pattern, locale);
+ return messageFormat.format(args);
+ }
+
+ @Override
+ protected String getI18nSection() {
+ return "plugin.goal";
+ }
+}
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginOverviewRenderer.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginOverviewRenderer.java
new file mode 100644
index 000000000..5189357e4
--- /dev/null
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginOverviewRenderer.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.plugin.report;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.doxia.markup.Markup;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Prerequisites;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
+import org.apache.maven.tools.plugin.util.PluginUtils;
+import org.codehaus.plexus.i18n.I18N;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+/**
+ * Generates an overview page with the list of goals
+ * and a link to the goal's page.
+ */
+class PluginOverviewRenderer extends AbstractPluginReportRenderer {
+
+ private final List requirementsHistories;
+
+ private final PluginDescriptor pluginDescriptor;
+
+ private final boolean hasExtensionsToLoad;
+
+ /**
+ * @param sink not null
+ * @param i18n not null
+ * @param locale not null
+ * @param project not null
+ * @param requirementsHistories not null
+ * @param pluginDescriptor not null
+ */
+ PluginOverviewRenderer(
+ Sink sink,
+ I18N i18n,
+ Locale locale,
+ MavenProject project,
+ List requirementsHistories,
+ PluginDescriptor pluginDescriptor,
+ boolean hasExtensionsToLoad) {
+ super(sink, locale, i18n, project);
+
+ this.requirementsHistories = requirementsHistories;
+
+ this.pluginDescriptor = pluginDescriptor;
+
+ this.hasExtensionsToLoad = hasExtensionsToLoad;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void renderBody() {
+ startSection(getTitle());
+
+ if (!(pluginDescriptor.getMojos() != null && pluginDescriptor.getMojos().size() > 0)) {
+ paragraph(getI18nString("goals.nogoal"));
+ endSection();
+ return;
+ }
+
+ paragraph(getI18nString("goals.intro"));
+
+ boolean hasMavenReport = false;
+ for (MojoDescriptor mojo : pluginDescriptor.getMojos()) {
+ if (PluginUtils.isMavenReport(mojo.getImplementation(), project)) {
+ hasMavenReport = true;
+ }
+ }
+
+ startTable();
+
+ String goalColumnName = getI18nString("goals.column.goal");
+ String isMavenReport = getI18nString("goals.column.isMavenReport");
+ String descriptionColumnName = getI18nString("goals.column.description");
+ if (hasMavenReport) {
+ tableHeader(new String[] {goalColumnName, isMavenReport, descriptionColumnName});
+ } else {
+ tableHeader(new String[] {goalColumnName, descriptionColumnName});
+ }
+
+ List mojos = new ArrayList<>();
+ mojos.addAll(pluginDescriptor.getMojos());
+ PluginUtils.sortMojos(mojos);
+ for (MojoDescriptor mojo : mojos) {
+ sink.tableRow();
+
+ String goalName = mojo.getFullGoalName();
+ /*
+ * Added ./ to define a relative path
+ * @see AbstractMavenReportRenderer#getValidHref(java.lang.String)
+ */
+ String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html";
+ sink.tableCell();
+ link(goalDocumentationLink, goalName);
+ sink.tableCell_();
+
+ if (hasMavenReport) {
+ if (PluginUtils.isMavenReport(mojo.getImplementation(), project)) {
+ tableCell(getI18nString("isReport"));
+ } else {
+ tableCell(getI18nString("isNotReport"));
+ }
+ }
+
+ String description;
+ if (StringUtils.isNotEmpty(mojo.getDeprecated())) {
+ description = "" + getI18nString("goal.deprecated") + " " + mojo.getDeprecated();
+ } else if (StringUtils.isNotEmpty(mojo.getDescription())) {
+ description = mojo.getDescription();
+ } else {
+ description = getI18nString("goal.nodescription");
+ }
+ tableCell(description, true);
+ sink.tableRow_();
+ }
+
+ endTable();
+
+ startSection(getI18nString("systemrequirements"));
+
+ paragraph(getI18nString("systemrequirements.intro"));
+
+ startTable();
+
+ String maven = discoverMavenRequirement(project, pluginDescriptor);
+ sink.tableRow();
+ tableCell(getI18nString("systemrequirements.maven"));
+ tableCell((maven != null ? maven : getI18nString("systemrequirements.nominimum")));
+ sink.tableRow_();
+
+ String jdk = discoverJdkRequirement(project, pluginDescriptor);
+ sink.tableRow();
+ tableCell(getI18nString("systemrequirements.jdk"));
+ tableCell((jdk != null ? jdk : getI18nString("systemrequirements.nominimum")));
+ sink.tableRow_();
+
+ endTable();
+
+ endSection();
+
+ renderRequirementsHistories();
+
+ renderUsageSection(hasMavenReport);
+
+ endSection();
+ }
+
+ private void renderRequirementsHistories() {
+ if (requirementsHistories.isEmpty()) {
+ return;
+ }
+
+ startSection(getI18nString("systemrequirements.history"));
+ paragraph(getI18nString("systemrequirements.history.intro"));
+
+ startTable();
+ tableHeader(new String[] {
+ getI18nString("systemrequirements.history.version"),
+ getI18nString("systemrequirements.history.maven"),
+ getI18nString("systemrequirements.history.jdk")
+ });
+
+ requirementsHistories.forEach(requirementsHistory -> {
+ sink.tableRow();
+ tableCell(requirementsHistory.getVersion());
+ tableCell(requirementsHistory.getMaven());
+ tableCell(requirementsHistory.getJdk());
+ sink.tableRow_();
+ });
+ endTable();
+
+ endSection();
+ }
+
+ /**
+ * Render the section about the usage of the plugin.
+ *
+ * @param hasMavenReport If the plugin has a report or not
+ */
+ private void renderUsageSection(boolean hasMavenReport) {
+ startSection(getI18nString("usage"));
+
+ // Configuration
+ paragraph(getI18nString("usage.intro"));
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("").append(Markup.EOL);
+ sb.append(" ...").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ")
+ .append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getGroupId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getArtifactId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getVersion())
+ .append("")
+ .append(Markup.EOL);
+ if (hasExtensionsToLoad) {
+ sb.append(" true").append(Markup.EOL);
+ }
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ...").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getGroupId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getArtifactId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ...").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+
+ if (hasMavenReport) {
+ sb.append(" ...").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getGroupId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getArtifactId())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ")
+ .append(pluginDescriptor.getVersion())
+ .append("")
+ .append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ...").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ sb.append(" ").append(Markup.EOL);
+ }
+
+ sb.append(" ...").append(Markup.EOL);
+ sb.append("");
+
+ verbatimText(sb.toString());
+
+ sink.paragraph();
+ linkPatternedText(getI18nString("configuration.end"));
+ sink.paragraph_();
+
+ endSection();
+ }
+
+ /**
+ * Tries to determine the Maven requirement from either the plugin descriptor or (if not set) from the
+ * Maven prerequisites element in the POM.
+ *
+ * @param project not null
+ * @param pluginDescriptor the plugin descriptor (not null)
+ * @return the Maven version or null if not specified
+ */
+ private static String discoverMavenRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
+ if (StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) {
+ return pluginDescriptor.getRequiredMavenVersion();
+ }
+ return Optional.ofNullable(project.getPrerequisites())
+ .map(Prerequisites::getMaven)
+ .orElse(null);
+ }
+
+ /**
+ * Tries to determine the JDK requirement from the following sources (until one is found)
+ *
+ * - use JDK requirement from plugin descriptor
+ * - use {@code release} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}
+ * - use {@code maven.compiler.release<} property
+ * - use {@code target} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}
+ * - use {@code maven.compiler.target} property
+ *
+ *
+ * @param project not null
+ * @param pluginDescriptor the plugin descriptor (not null)
+ * @return the JDK version
+ */
+ private static String discoverJdkRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
+ String jdk = null;
+ if (pluginDescriptor instanceof ExtendedPluginDescriptor) {
+ ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
+ jdk = extPluginDescriptor.getRequiredJavaVersion();
+ }
+ if (jdk != null) {
+ return jdk;
+ }
+ Plugin compiler = getCompilerPlugin(project.getBuild().getPluginsAsMap());
+ if (compiler == null) {
+ compiler = getCompilerPlugin(project.getPluginManagement().getPluginsAsMap());
+ }
+
+ jdk = getPluginParameter(compiler, "release");
+ if (jdk != null) {
+ return jdk;
+ }
+
+ jdk = project.getProperties().getProperty("maven.compiler.release");
+ if (jdk != null) {
+ return jdk;
+ }
+
+ jdk = getPluginParameter(compiler, "target");
+ if (jdk != null) {
+ return jdk;
+ }
+
+ // default value
+ jdk = project.getProperties().getProperty("maven.compiler.target");
+ if (jdk != null) {
+ return jdk;
+ }
+
+ String version = (compiler == null) ? null : compiler.getVersion();
+
+ if (version != null) {
+ return "Default target for maven-compiler-plugin version " + version;
+ }
+
+ return null;
+ }
+
+ private static Plugin getCompilerPlugin(Map pluginsAsMap) {
+ return pluginsAsMap.get("org.apache.maven.plugins:maven-compiler-plugin");
+ }
+
+ private static String getPluginParameter(Plugin plugin, String parameter) {
+ if (plugin != null) {
+ Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
+
+ if (pluginConf != null) {
+ Xpp3Dom target = pluginConf.getChild(parameter);
+
+ if (target != null) {
+ return target.getValue();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected String getI18nSection() {
+ return "plugin";
+ }
+}
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
index c9a174061..1e63aa29f 100644
--- a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
@@ -25,14 +25,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
-import org.apache.maven.doxia.markup.Markup;
import org.apache.maven.doxia.sink.Sink;
-import org.apache.maven.doxia.tools.SiteTool;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.Prerequisites;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
@@ -42,23 +36,12 @@
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.plugin.descriptor.EnhancedPluginDescriptorBuilder;
-import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.AbstractMavenReport;
-import org.apache.maven.reporting.AbstractMavenReportRenderer;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.rtinfo.RuntimeInformation;
-import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
-import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
-import org.apache.maven.tools.plugin.PluginToolsRequest;
-import org.apache.maven.tools.plugin.generator.GeneratorException;
-import org.apache.maven.tools.plugin.generator.GeneratorUtils;
-import org.apache.maven.tools.plugin.generator.PluginXdocGenerator;
-import org.apache.maven.tools.plugin.util.PluginUtils;
import org.codehaus.plexus.configuration.PlexusConfigurationException;
import org.codehaus.plexus.i18n.I18N;
-import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.XmlStreamReader;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* Generates the Plugin's documentation report: plugin-info.html
plugin overview page,
@@ -72,13 +55,6 @@
@Mojo(name = "report", threadSafe = true)
@Execute(phase = LifecyclePhase.PROCESS_CLASSES)
public class PluginReport extends AbstractMavenReport {
- /**
- * Report output directory for mojos' documentation.
- *
- * @since 3.7.0
- */
- @Parameter(defaultValue = "${project.build.directory}/generated-site")
- private File generatedSiteDirectory;
/**
* Set this to "true" to skip generating the report.
@@ -147,15 +123,6 @@ public class PluginReport extends AbstractMavenReport {
@Parameter(property = "maven.plugin.report.disableInternalJavadocLinkValidation")
private boolean disableInternalJavadocLinkValidation;
- /**
- * {@inheritDoc}
- */
- @Override
- protected String getOutputDirectory() {
- // PLUGIN-191: output directory of plugin.html, not *-mojo.xml
- return project.getReporting().getOutputDirectory();
- }
-
/**
* {@inheritDoc}
*/
@@ -229,403 +196,36 @@ public String getOutputName() {
}
/**
- * Generate the mojos documentation, as xdoc files.
+ * Generate the mojos' documentation with the {@link #getSinkFactory()}
*
* @param pluginDescriptor not null
* @param locale not null
* @throws MavenReportException if any
+ * @throws IOException
*/
private void generateMojosDocumentation(PluginDescriptor pluginDescriptor, Locale locale)
throws MavenReportException {
- try {
- File outputDir;
- if (!locale.equals(SiteTool.DEFAULT_LOCALE)) {
- outputDir = new File(new File(generatedSiteDirectory, locale.toString()), "xdoc");
- } else {
- outputDir = new File(generatedSiteDirectory, "xdoc");
- }
- outputDir.mkdirs();
-
- PluginXdocGenerator generator = new PluginXdocGenerator(
- getProject(), locale, getReportOutputDirectory(), disableInternalJavadocLinkValidation);
- PluginToolsRequest pluginToolsRequest = new DefaultPluginToolsRequest(getProject(), pluginDescriptor);
- generator.execute(outputDir, pluginToolsRequest);
- } catch (GeneratorException e) {
- throw new MavenReportException("Error writing plugin documentation", e);
- }
- }
-
- /**
- * Generates an overview page with the list of goals
- * and a link to the goal's page.
- */
- static class PluginOverviewRenderer extends AbstractMavenReportRenderer {
- private final I18N i18n;
-
- private final Locale locale;
-
- private final MavenProject project;
-
- private final List requirementsHistories;
-
- private final PluginDescriptor pluginDescriptor;
-
- private final boolean hasExtensionsToLoad;
-
- /**
- * @param sink not null
- * @param i18n not null
- * @param locale not null
- * @param project not null
- * @param requirementsHistories not null
- * @param pluginDescriptor not null
- */
- PluginOverviewRenderer(
- Sink sink,
- I18N i18n,
- Locale locale,
- MavenProject project,
- List requirementsHistories,
- PluginDescriptor pluginDescriptor,
- boolean hasExtensionsToLoad) {
- super(sink);
-
- this.i18n = i18n;
-
- this.locale = locale;
-
- this.project = project;
-
- this.requirementsHistories = requirementsHistories;
-
- this.pluginDescriptor = pluginDescriptor;
-
- this.hasExtensionsToLoad = hasExtensionsToLoad;
- }
-
- @Override
- public String getTitle() {
- return getI18nString("title");
- }
-
- /**
- * @param key The key.
- * @return The translated string.
- */
- protected String getI18nString(String key) {
- return i18n.getString("plugin-report", locale, "report.plugin." + key);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void renderBody() {
- startSection(getTitle());
-
- if (!(pluginDescriptor.getMojos() != null
- && pluginDescriptor.getMojos().size() > 0)) {
- paragraph(getI18nString("goals.nogoal"));
- endSection();
- return;
- }
-
- paragraph(getI18nString("goals.intro"));
-
- boolean hasMavenReport = false;
- for (MojoDescriptor mojo : pluginDescriptor.getMojos()) {
- if (GeneratorUtils.isMavenReport(mojo.getImplementation(), project)) {
- hasMavenReport = true;
- }
- }
-
- startTable();
-
- String goalColumnName = getI18nString("goals.column.goal");
- String isMavenReport = getI18nString("goals.column.isMavenReport");
- String descriptionColumnName = getI18nString("goals.column.description");
- if (hasMavenReport) {
- tableHeader(new String[] {goalColumnName, isMavenReport, descriptionColumnName});
- } else {
- tableHeader(new String[] {goalColumnName, descriptionColumnName});
- }
-
- List mojos = new ArrayList<>();
- mojos.addAll(pluginDescriptor.getMojos());
- PluginUtils.sortMojos(mojos);
- for (MojoDescriptor mojo : mojos) {
- String goalName = mojo.getFullGoalName();
-
- /*
- * Added ./ to define a relative path
- * @see AbstractMavenReportRenderer#getValidHref(java.lang.String)
- */
- String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html";
-
- String description;
- if (StringUtils.isNotEmpty(mojo.getDeprecated())) {
- description = "" + getI18nString("goal.deprecated") + " " + mojo.getDeprecated();
- } else if (StringUtils.isNotEmpty(mojo.getDescription())) {
- description = mojo.getDescription();
- } else {
- description = getI18nString("goal.nodescription");
- }
-
- sink.tableRow();
- tableCell(createLinkPatternedText(goalName, goalDocumentationLink));
- if (hasMavenReport) {
- if (GeneratorUtils.isMavenReport(mojo.getImplementation(), project)) {
- tableCell(getI18nString("isReport"));
- } else {
- tableCell(getI18nString("isNotReport"));
- }
- }
- tableCell(description, true);
- sink.tableRow_();
- }
-
- endTable();
-
- startSection(getI18nString("systemrequirements"));
- paragraph(getI18nString("systemrequirements.intro"));
-
- startTable();
-
- String maven = discoverMavenRequirement(project, pluginDescriptor);
- sink.tableRow();
- tableCell(getI18nString("systemrequirements.maven"));
- tableCell((maven != null ? maven : getI18nString("systemrequirements.nominimum")));
- sink.tableRow_();
-
- String jdk = discoverJdkRequirement(project, pluginDescriptor);
- sink.tableRow();
- tableCell(getI18nString("systemrequirements.jdk"));
- tableCell((jdk != null ? jdk : getI18nString("systemrequirements.nominimum")));
- sink.tableRow_();
-
- endTable();
-
- endSection();
-
- renderRequirementsHistories();
-
- renderUsageSection(hasMavenReport);
-
- endSection();
- }
-
- private void renderRequirementsHistories() {
- if (requirementsHistories.isEmpty()) {
- return;
- }
-
- startSection(getI18nString("systemrequirements.history"));
- paragraph(getI18nString("systemrequirements.history.intro"));
-
- startTable();
- tableHeader(new String[] {
- getI18nString("systemrequirements.history.version"),
- getI18nString("systemrequirements.history.maven"),
- getI18nString("systemrequirements.history.jdk")
- });
-
- requirementsHistories.forEach(requirementsHistory -> {
- sink.tableRow();
- tableCell(requirementsHistory.getVersion());
- tableCell(requirementsHistory.getMaven());
- tableCell(requirementsHistory.getJdk());
- sink.tableRow_();
- });
- endTable();
-
- endSection();
- }
-
- /**
- * Render the section about the usage of the plugin.
- *
- * @param hasMavenReport If the plugin has a report or not
- */
- private void renderUsageSection(boolean hasMavenReport) {
- startSection(getI18nString("usage"));
-
- // Configuration
- paragraph(getI18nString("usage.intro"));
-
- StringBuilder sb = new StringBuilder();
- sb.append("").append(Markup.EOL);
- sb.append(" ...").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ")
- .append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getGroupId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getArtifactId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getVersion())
- .append("")
- .append(Markup.EOL);
- if (hasExtensionsToLoad) {
- sb.append(" true").append(Markup.EOL);
- }
- sb.append(" ").append(Markup.EOL);
- sb.append(" ...").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getGroupId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getArtifactId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ...").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
-
- if (hasMavenReport) {
- sb.append(" ...").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getGroupId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getArtifactId())
- .append("")
- .append(Markup.EOL);
- sb.append(" ")
- .append(pluginDescriptor.getVersion())
- .append("")
- .append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ...").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- sb.append(" ").append(Markup.EOL);
- }
-
- sb.append(" ...").append(Markup.EOL);
- sb.append("");
-
- verbatimText(sb.toString());
-
- sink.paragraph();
- linkPatternedText(getI18nString("configuration.end"));
- sink.paragraph_();
-
- endSection();
- }
-
- /**
- * Tries to determine the Maven requirement from either the plugin descriptor or (if not set) from the
- * Maven prerequisites element in the POM.
- *
- * @param project not null
- * @param pluginDescriptor the plugin descriptor (not null)
- * @return the Maven version or null if not specified
- */
- private static String discoverMavenRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
- if (StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) {
- return pluginDescriptor.getRequiredMavenVersion();
- }
- return Optional.ofNullable(project.getPrerequisites())
- .map(Prerequisites::getMaven)
- .orElse(null);
- }
-
- /**
- * Tries to determine the JDK requirement from the following sources (until one is found)
- *
- * - use JDK requirement from plugin descriptor
- * - use {@code release} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}
- * - use {@code maven.compiler.release<} property
- * - use {@code target} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}
- * - use {@code maven.compiler.target} property
- *
- *
- * @param project not null
- * @param pluginDescriptor the plugin descriptor (not null)
- * @return the JDK version
- */
- private static String discoverJdkRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
- String jdk = null;
- if (pluginDescriptor instanceof ExtendedPluginDescriptor) {
- ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
- jdk = extPluginDescriptor.getRequiredJavaVersion();
- }
- if (jdk != null) {
- return jdk;
- }
- Plugin compiler = getCompilerPlugin(project.getBuild().getPluginsAsMap());
- if (compiler == null) {
- compiler = getCompilerPlugin(project.getPluginManagement().getPluginsAsMap());
- }
-
- jdk = getPluginParameter(compiler, "release");
- if (jdk != null) {
- return jdk;
- }
-
- jdk = project.getProperties().getProperty("maven.compiler.release");
- if (jdk != null) {
- return jdk;
- }
-
- jdk = getPluginParameter(compiler, "target");
- if (jdk != null) {
- return jdk;
- }
-
- // default value
- jdk = project.getProperties().getProperty("maven.compiler.target");
- if (jdk != null) {
- return jdk;
- }
-
- String version = (compiler == null) ? null : compiler.getVersion();
-
- if (version != null) {
- return "Default target for maven-compiler-plugin version " + version;
- }
-
- return null;
- }
-
- private static Plugin getCompilerPlugin(Map pluginsAsMap) {
- return pluginsAsMap.get("org.apache.maven.plugins:maven-compiler-plugin");
- }
-
- private static String getPluginParameter(Plugin plugin, String parameter) {
- if (plugin != null) {
- Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
-
- if (pluginConf != null) {
- Xpp3Dom target = pluginConf.getChild(parameter);
-
- if (target != null) {
- return target.getValue();
- }
+ if (pluginDescriptor.getMojos() != null) {
+ for (MojoDescriptor descriptor : pluginDescriptor.getMojos()) {
+ GoalRenderer renderer;
+ try {
+ String filename = descriptor.getGoal() + "-mojo.html";
+ Sink sink = getSinkFactory().createSink(outputDirectory, filename);
+ renderer = new GoalRenderer(
+ sink,
+ i18n,
+ locale,
+ project,
+ descriptor,
+ outputDirectory,
+ disableInternalJavadocLinkValidation,
+ getLog());
+ } catch (IOException e) {
+ throw new MavenReportException("Can not generate sink for mojo " + descriptor.getGoal(), e);
}
+ renderer.render();
}
-
- return null;
}
}
}
diff --git a/maven-plugin-report-plugin/src/main/resources/plugin-report.properties b/maven-plugin-report-plugin/src/main/resources/plugin-report.properties
index a483e7a02..fa0989cbd 100644
--- a/maven-plugin-report-plugin/src/main/resources/plugin-report.properties
+++ b/maven-plugin-report-plugin/src/main/resources/plugin-report.properties
@@ -26,8 +26,49 @@ report.plugin.goals.intro=Goals available for this plugin:
report.plugin.goals.column.goal=Goal
report.plugin.goals.column.isMavenReport=Report?
report.plugin.goals.column.description=Description
+
report.plugin.goal.nodescription=No description.
report.plugin.goal.deprecated=Deprecated.
+report.plugin.goal.notice.prefix=Note
+report.plugin.goal.notice.isMavenReport=This goal should be used as a Maven report.
+report.plugin.goal.fullname=Full name
+report.plugin.goal.description=Description
+report.plugin.goal.attributes=Attributes
+report.plugin.goal.projectRequired=Requires a Maven project to be executed
+report.plugin.goal.aggregator=Executes as an aggregator goal
+report.plugin.goal.directInvocationOnly=Executes by direct invocation only
+report.plugin.goal.reportingMojo=Executes only as a reportSet (reporting goal)
+report.plugin.goal.dependencyResolutionRequired=Requires dependency resolution of artifacts in scope
+report.plugin.goal.dependencyCollectionRequired=Requires dependency collection of artifacts in scope
+report.plugin.goal.since=Since version
+report.plugin.goal.phase=Binds by default to the {lifecycle phase, https://maven.apache.org/ref/current/maven-core/lifecycles.html}
+report.plugin.goal.threadSafe=The goal is thread-safe and supports parallel builds
+report.plugin.goal.notThreadSafe=The goal is not marked as thread-safe and thus does not support parallel builds
+report.plugin.goal.executePhase=Invokes the execution of the following {lifecycle phase, https://maven.apache.org/ref/current/maven-core/lifecycles.html} prior to executing itself
+report.plugin.goal.executeGoal=Invokes the execution of the following plugin's goal prior to executing itself
+report.plugin.goal.executeLifecycle=Executes in its own lifecycle
+report.plugin.goal.onlineRequired=Requires that Maven runs in online mode
+report.plugin.goal.notInheritedByDefault=Is NOT inherited by default in multi-project builds
+
+report.plugin.goal.parameters=Parameters
+report.plugin.goal.noParameter=(no parameters)
+report.plugin.goal.requiredParameters=Required Parameters
+report.plugin.goal.optionalParameters=Optional Parameters
+
+report.plugin.goal.parameter.name.header=Name
+report.plugin.goal.parameter.description.header=Description
+report.plugin.goal.parameter.type.header=Type
+report.plugin.goal.parameter.since.header=Since
+report.plugin.goal.parameter.name=<{0}>
+report.plugin.goal.parameter.defaultValue=Default
+report.plugin.goal.parameter.property=User Property
+report.plugin.goal.parameter.alias=Alias
+report.plugin.goal.parameter.deprecated=Deprecated. {0}
+report.plugin.goal.parameter.type=Type
+report.plugin.goal.parameter.required=Required
+report.plugin.goal.parameter.expression=Expression
+report.plugin.goal.parameter.details=Parameter Details
+report.plugin.goal.parameter.since=Since
report.plugin.systemrequirements=System Requirements
report.plugin.systemrequirements.intro=The following specifies the minimum requirements to run this Maven plugin:
@@ -49,3 +90,5 @@ report.plugin.configuration.end=For more information, see {"Guide to Configuring
report.plugin.isReport=Yes
report.plugin.isNotReport=No
+report.plugin.yes=Yes
+report.plugin.no=No
diff --git a/maven-plugin-report-plugin/src/test/java/org/apache/maven/plugin/plugin/report/GoalRendererTest.java b/maven-plugin-report-plugin/src/test/java/org/apache/maven/plugin/plugin/report/GoalRendererTest.java
new file mode 100644
index 000000000..0801d71e3
--- /dev/null
+++ b/maven-plugin-report-plugin/src/test/java/org/apache/maven/plugin/plugin/report/GoalRendererTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.plugin.report;
+
+import java.io.File;
+import java.util.Locale;
+
+import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class GoalRendererTest {
+
+ @Test
+ void testGetShortType() {
+ assertEquals("String", GoalRenderer.getShortType("java.lang.String"));
+ assertEquals("List", GoalRenderer.getShortType("java.util.List"));
+ assertEquals(
+ "Map", GoalRenderer.getShortType("java.util.Map"));
+ assertEquals("List<...>", GoalRenderer.getShortType("java.util.List>"));
+ }
+
+ @Test
+ void testGetXhtmlWithValidatedLinks() {
+ File baseDir = new File(this.getClass().getResource("").getFile());
+ GoalRenderer renderer =
+ new GoalRenderer(null, null, Locale.ROOT, null, null, baseDir, false, new SystemStreamLog());
+ GoalRenderer rendererWithDisabledLinkValidator =
+ new GoalRenderer(null, null, Locale.ROOT, null, null, baseDir, true, new SystemStreamLog());
+ String externalLink =
+ "testExternal Link..and a secondlinkend";
+ assertEquals(externalLink, renderer.getXhtmlWithValidatedLinks(externalLink, "test"));
+ assertEquals(externalLink, renderer.getXhtmlWithValidatedLinks(externalLink, "test"));
+ String validInternalLink =
+ "testInternal Link..and a secondlinkend";
+ assertEquals(validInternalLink, renderer.getXhtmlWithValidatedLinks(validInternalLink, "test"));
+ assertEquals(validInternalLink, renderer.getXhtmlWithValidatedLinks(validInternalLink, "test"));
+ String invalidInternalLink =
+ "testInternal Link..and a secondlinkend";
+ String sanitizedInvalidInternalLink =
+ "testInternal Link..and a secondlinkend";
+ assertEquals(sanitizedInvalidInternalLink, renderer.getXhtmlWithValidatedLinks(invalidInternalLink, "test"));
+ assertEquals(
+ invalidInternalLink,
+ rendererWithDisabledLinkValidator.getXhtmlWithValidatedLinks(invalidInternalLink, "test"));
+ }
+}
diff --git a/maven-plugin-tools-api/pom.xml b/maven-plugin-tools-api/pom.xml
index 520255a99..247b3dc7a 100644
--- a/maven-plugin-tools-api/pom.xml
+++ b/maven-plugin-tools-api/pom.xml
@@ -53,6 +53,10 @@
org.slf4j
slf4j-api
+