[Git][java-team/maven-reporting-impl][upstream] New upstream version 4.0.0

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Thu Oct 24 11:50:08 BST 2024



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / maven-reporting-impl


Commits:
ab2d2d7b by Emmanuel Bourg at 2024-10-22T11:37:54+02:00
New upstream version 4.0.0
- - - - -


27 changed files:

- .asf.yaml
- + .github/dependabot.yml
- + .github/workflows/maven-verify.yml
- .gitignore
- README.md
- pom.xml
- src/it/setup-reporting-plugin/pom.xml
- src/it/setup-reporting-plugin/src/main/java/org/apache/maven/reporting/its/custom/CustomReportRenderer.java
- src/it/setup-reporting-plugin/src/main/java/org/apache/maven/reporting/its/custom/ExternalReport.java
- + src/it/use-as-direct-mojo-2/invoker.properties
- + src/it/use-as-direct-mojo-2/pom.xml
- + src/it/use-as-direct-mojo-2/verify.groovy
- + src/it/use-as-direct-mojo-markup-2/invoker.properties
- + src/it/use-as-direct-mojo-markup-2/pom.xml
- + src/it/use-as-direct-mojo-markup-2/verify.groovy
- + src/it/use-as-direct-mojo-markup/invoker.properties
- + src/it/use-as-direct-mojo-markup/pom.xml
- + src/it/use-as-direct-mojo-markup/verify.groovy
- src/it/use-as-direct-mojo/invoker.properties
- src/it/use-as-direct-mojo/pom.xml
- src/it/use-as-direct-mojo/verify.groovy
- src/it/use-as-site-report/pom.xml
- src/it/use-as-site-report/verify.groovy
- src/main/java/org/apache/maven/reporting/AbstractMavenReport.java
- src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java
- src/site/apt/index.apt.vm
- src/test/java/org/apache/maven/reporting/AbstractMavenReportRendererTest.java


Changes:

=====================================
.asf.yaml
=====================================
@@ -23,3 +23,14 @@ github:
     - build-management
     - maven-shared
     - maven
+  enabled_merge_buttons:
+    squash: true
+    merge: false
+    rebase: true
+  autolink_jira:
+    - MSHARED
+notifications:
+  commits: commits at maven.apache.org
+  issues: issues at maven.apache.org
+  pullrequests: issues at maven.apache.org
+  jira_options: link label comment


=====================================
.github/dependabot.yml
=====================================
@@ -0,0 +1,27 @@
+# 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.
+
+version: 2
+updates:
+  - package-ecosystem: "maven"
+    directory: "/"
+    schedule:
+      interval: "daily"
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"


=====================================
.github/workflows/maven-verify.yml
=====================================
@@ -0,0 +1,27 @@
+# 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.
+
+name: Verify
+
+on:
+  push:
+  pull_request:
+
+jobs:
+  build:
+    name: Verify
+    uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml at v4


=====================================
.gitignore
=====================================
@@ -13,3 +13,4 @@ out/
 /bootstrap
 /dependencies.xml
 .java-version
+.checkstyle
\ No newline at end of file


=====================================
README.md
=====================================
@@ -20,6 +20,7 @@ Contributing to [Apache Maven Reporting Implementation](https://maven.apache.org
 [![ASF Jira](https://img.shields.io/endpoint?url=https%3A%2F%2Fmaven.apache.org%2Fbadges%2Fasf_jira-MSHARED.json)][jira]
 [![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/apache/maven.svg?label=License)][license]
 [![Maven Central](https://img.shields.io/maven-central/v/org.apache.maven.reporting/maven-reporting-impl.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.maven.reporting/maven-reporting-impl)
+[![Reproducible Builds](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/org/apache/maven/reporting/maven-reporting-impl/badge.json)](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/org/apache/maven/reporting/maven-reporting-impl/README.md)
 [![Jenkins Status](https://img.shields.io/jenkins/s/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven-reporting-impl/job/master.svg)][build]
 [![Jenkins tests](https://img.shields.io/jenkins/t/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven-reporting-impl/job/master.svg)][test-results]
 


=====================================
pom.xml
=====================================
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
@@ -23,34 +23,22 @@
   <parent>
     <groupId>org.apache.maven.shared</groupId>
     <artifactId>maven-shared-components</artifactId>
-    <version>34</version>
+    <version>43</version>
     <relativePath />
   </parent>
 
   <groupId>org.apache.maven.reporting</groupId>
   <artifactId>maven-reporting-impl</artifactId>
-  <version>3.2.0</version>
+  <version>4.0.0</version>
 
   <name>Apache Maven Reporting Implementation</name>
   <description>Abstract classes to manage report generation.</description>
 
-  <developers>
-    <developer>
-      <id>vsiveton</id>
-      <name>Vincent Siveton</name>
-      <email>vincent.siveton at gmail.com</email>
-      <roles>
-        <role>Java Developer</role>
-      </roles>
-      <timezone>-5</timezone>
-    </developer>
-  </developers>
-
   <scm>
     <connection>scm:git:https://gitbox.apache.org/repos/asf/maven-reporting-impl.git</connection>
     <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/maven-reporting-impl.git</developerConnection>
+    <tag>maven-reporting-impl-4.0.0</tag>
     <url>https://github.com/apache/maven-reporting-impl/tree/${project.scm.tag}</url>
-    <tag>maven-reporting-impl-3.2.0</tag>
   </scm>
   <issueManagement>
     <system>jira</system>
@@ -68,14 +56,28 @@
   </distributionManagement>
 
   <properties>
-    <javaVersion>7</javaVersion>
-    <mavenVersion>3.1.0</mavenVersion>
-    <doxiaVersion>1.11.1</doxiaVersion>
-    <doxiaSitetoolsVersion>1.11.1</doxiaSitetoolsVersion>
-    <reportingApiVersion>3.1.1</reportingApiVersion>
-    <project.build.outputTimestamp>2022-08-06T21:51:47Z</project.build.outputTimestamp>
+    <javaVersion>8</javaVersion>
+    <mavenVersion>3.6.3</mavenVersion>
+    <resolverVersion>1.4.1</resolverVersion>
+    <doxiaVersion>2.0.0</doxiaVersion>
+    <doxiaSitetoolsVersion>2.0.0</doxiaSitetoolsVersion>
+    <reportingApiVersion>4.0.0</reportingApiVersion>
+    <pluginToolsVersion>3.15.0</pluginToolsVersion>
+    <project.build.outputTimestamp>2024-10-12T19:41:46Z</project.build.outputTimestamp>
   </properties>
 
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.junit</groupId>
+        <artifactId>junit-bom</artifactId>
+        <version>5.11.2</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.maven.reporting</groupId>
@@ -88,21 +90,30 @@
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-core</artifactId>
       <version>${mavenVersion}</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-artifact</artifactId>
       <version>${mavenVersion}</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-plugin-api</artifactId>
       <version>${mavenVersion}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-model</artifactId>
+      <version>${mavenVersion}</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.shared</groupId>
       <artifactId>maven-shared-utils</artifactId>
-      <version>3.3.4</version>
+      <version>3.4.2</version>
     </dependency>
 
     <!-- Doxia -->
@@ -111,9 +122,10 @@
       <artifactId>doxia-sink-api</artifactId>
       <version>${doxiaVersion}</version>
     </dependency>
+    <!-- Doxia site rendering -->
     <dependency>
       <groupId>org.apache.maven.doxia</groupId>
-      <artifactId>doxia-decoration-model</artifactId>
+      <artifactId>doxia-site-model</artifactId>
       <version>${doxiaSitetoolsVersion}</version>
     </dependency>
     <dependency>
@@ -131,6 +143,19 @@
       <artifactId>doxia-site-renderer</artifactId>
       <version>${doxiaSitetoolsVersion}</version>
     </dependency>
+    <!-- Doxia markup rendering -->
+    <dependency>
+      <groupId>org.apache.maven.doxia</groupId>
+      <artifactId>doxia-module-apt</artifactId>
+      <version>${doxiaVersion}</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.doxia</groupId>
+      <artifactId>doxia-module-xdoc</artifactId>
+      <version>${doxiaVersion}</version>
+      <scope>runtime</scope>
+    </dependency>
 
     <!-- misc -->
     <dependency>
@@ -141,20 +166,31 @@
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-utils</artifactId>
-      <version>3.3.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-archiver</artifactId>
+      <version>3.6.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.resolver</groupId>
+      <artifactId>maven-resolver-api</artifactId>
+      <version>${resolverVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.sisu</groupId>
+      <artifactId>org.eclipse.sisu.plexus</artifactId>
     </dependency>
 
     <!-- test -->
     <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.13.2</version>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-api</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>junit-addons</groupId>
-      <artifactId>junit-addons</artifactId>
-      <version>1.4</version>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
       <scope>test</scope>
     </dependency>
   </dependencies>
@@ -178,8 +214,6 @@
           <properties>
             <maven.compiler.source>${maven.compiler.source}</maven.compiler.source>
             <maven.compiler.target>${maven.compiler.target}</maven.compiler.target>
-            <!-- e.g. ensure that Java7 picks up TLSv1.2 when connecting with Central -->
-            <https.protocols>${https.protocols}</https.protocols>
           </properties>
         </configuration>
         <executions>


=====================================
src/it/setup-reporting-plugin/pom.xml
=====================================
@@ -30,7 +30,8 @@ under the License.
 
   <name>maven-reporting-impl IT: custom reporting plugin based on maven-reporting-impl</name>
   <description>
-    Demo to show how to write a reporting plugin based on maven-reporting-impl.
+    Demo to show how to write a reporting plugin based on maven-reporting-impl: 3 ways to write a report are provided = external (like javadoc), direct, and using a renderer.
+    The ITs will then test it works in the different situations that maven-reporting-impl supports: run as a goal or run as a site report.
   </description>
 
   <properties>
@@ -54,18 +55,19 @@ under the License.
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-plugin-api</artifactId>
       <version>@mavenVersion@</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.plugin-tools</groupId>
       <artifactId>maven-plugin-annotations</artifactId>
-      <version>3.6.4</version>
+      <version>@pluginToolsVersion@</version>
       <scope>provided</scope>
     </dependency>
 
     <dependency>
       <groupId>org.apache.maven.shared</groupId>
       <artifactId>maven-shared-utils</artifactId>
-      <version>3.3.4</version>
+      <version>3.4.2</version>
     </dependency>
   </dependencies>
 
@@ -73,16 +75,16 @@ under the License.
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.1</version>
+        <version>3.13.0</version>
       </plugin>
       <plugin>
         <artifactId>maven-install-plugin</artifactId>
-        <version>2.5.2</version>
+        <version>3.1.3</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-plugin-plugin</artifactId>
-        <version>3.6.4</version>
+        <version>@pluginToolsVersion@</version>
         <executions>
           <execution>
             <id>default-descriptor</id>
@@ -95,6 +97,9 @@ under the License.
             </goals>
           </execution>
         </executions>
+        <configuration>
+          <goalPrefix>custom-reporting</goalPrefix>
+        </configuration>
       </plugin>
     </plugins>
   </build>


=====================================
src/it/setup-reporting-plugin/src/main/java/org/apache/maven/reporting/its/custom/CustomReportRenderer.java
=====================================
@@ -38,12 +38,16 @@ public class CustomReportRenderer
         return "Custom Report Renderer Title";
     }
 
-    public void renderBody()
+    protected void renderBody()
     {
         startSection( "section" );
 
         text( "Custom Maven Report with Renderer content." );
 
+        verbatimText( "Custom verbatim text." );
+
+        verbatimSource( "var custom_code = true;" );
+
         endSection();
     }
 }


=====================================
src/it/setup-reporting-plugin/src/main/java/org/apache/maven/reporting/its/custom/ExternalReport.java
=====================================
@@ -38,14 +38,14 @@ public class ExternalReport
     extends AbstractMavenReport
 {
     /**
-     * The name of the destination directory inside the site.
+     * The name of the output directory inside the reports.
      */
-    @Parameter( property = "destDir", defaultValue = "external" )
-    private String destDir;
+    @Parameter( property = "outputDirName", defaultValue = "external" )
+    private String outputDirName;
 
     public String getOutputName()
     {
-        return destDir + "/report";
+        return outputDirName + "/report";
     }
 
     public String getName( Locale locale )
@@ -69,7 +69,7 @@ public class ExternalReport
     {
         try
         {
-            executeExternalTool( getOutputDirectory() + '/' + destDir );
+            executeExternalTool( new File( getReportOutputDirectory(), outputDirName ) );
         }
         catch ( IOException ioe )
         {
@@ -80,17 +80,17 @@ public class ExternalReport
     /**
      * Invoke the external tool to generate report.
      *
-     * @param destination destination directory
+     * @param destDir destination directory
      */
-    private void executeExternalTool( String destination )
+    private void executeExternalTool( File destDir )
         throws IOException
     {
-        // demo implementation, to be replaced with effective tool
-        File dest = new File( destination );
+        getLog().info( "Running external tool to " + destDir );
 
-        dest.mkdirs();
+        // demo implementation, to be replaced with effective tool
+        destDir.mkdirs();
 
-        File report = new File( dest, "report.html" );
-        FileUtils.fileWrite( report, "UTF-8", "<html><body><h1>External Report</h1></body></html>" );
+        File reportFile = new File( destDir, "report.html" );
+        FileUtils.fileWrite( reportFile, "UTF-8", "<html><body><h1>External Report</h1></body></html>" );
     }
 }


=====================================
src/it/use-as-direct-mojo-2/invoker.properties
=====================================
@@ -0,0 +1,20 @@
+# 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.
+
+invoker.goals.1 = custom-reporting:custom
+invoker.goals.2 = custom-reporting:custom-renderer
+invoker.goals.3 = custom-reporting:external


=====================================
src/it/use-as-direct-mojo-2/pom.xml
=====================================
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.reporting.its</groupId>
+  <artifactId>use-as-direct-mojo-2</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Use report as direct mojo</name>
+  <description>Use report directly as mojo: "mvn my-plugin:my-report"</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.reporting.its</groupId>
+        <artifactId>custom-reporting-plugin</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <configuration>
+          <outputDirectory>${project.build.directory}/custom-reports</outputDirectory>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>


=====================================
src/it/use-as-direct-mojo-2/verify.groovy
=====================================
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+File outputDir = new File( basedir, 'target/custom-reports/' )
+
+File f = new File( outputDir, 'custom-report.html' );
+assert f.exists();
+assert f.text.contains( 'Custom Maven Report content.' );
+
+f = new File( outputDir, 'custom-report-with-renderer.html' );
+assert f.exists();
+text = f.text.normalize();
+assert text.contains( 'Custom Maven Report with Renderer content.' );
+assert text.contains( '<pre>Custom verbatim text.</pre>' );
+assert text.contains( '<pre class="prettyprint"><code>var custom_code = true;</code></pre>' );
+
+f = new File( outputDir, 'external/report.html' );
+assert f.exists();
+assert f.text.contains( '<h1>External Report</h1>' );
+
+return true;


=====================================
src/it/use-as-direct-mojo-markup-2/invoker.properties
=====================================
@@ -0,0 +1,20 @@
+# 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.
+
+invoker.goals.1 = custom-reporting:custom -Doutput.format=xdoc
+invoker.goals.2 = custom-reporting:custom-renderer -Doutput.format=apt
+invoker.goals.3 = custom-reporting:external -Doutput.format=anything


=====================================
src/it/use-as-direct-mojo-markup-2/pom.xml
=====================================
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.reporting.its</groupId>
+  <artifactId>use-as-direct-mojo-markup-2</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Use report as direct mojo to markup</name>
+  <description>Use report directly as mojo to markup: "mvn my-plugin:my-report"</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.reporting.its</groupId>
+        <artifactId>custom-reporting-plugin</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <configuration>
+          <outputDirectory>${project.build.directory}/custom-reports</outputDirectory>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>


=====================================
src/it/use-as-direct-mojo-markup-2/verify.groovy
=====================================
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+File outputDir = new File( basedir, 'target/custom-reports/' )
+
+File f = new File( outputDir, 'custom-report.xdoc' );
+assert f.exists();
+assert f.text.contains( 'Custom Maven Report content.' );
+
+f = new File( outputDir, 'custom-report-with-renderer.apt' );
+assert f.exists();
+assert f.text.contains( 'Custom Maven Report with Renderer content.' );
+
+f = new File( outputDir, 'external/report.html' );
+assert f.exists();
+assert f.text.contains( '<h1>External Report</h1>' );
+
+return true;


=====================================
src/it/use-as-direct-mojo-markup/invoker.properties
=====================================
@@ -0,0 +1,20 @@
+# 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.
+
+invoker.goals.1 = custom-reporting:custom -Doutput.format=xdoc
+invoker.goals.2 = custom-reporting:custom-renderer -Doutput.format=apt
+invoker.goals.3 = custom-reporting:external -Doutput.format=anything


=====================================
src/it/use-as-direct-mojo-markup/pom.xml
=====================================
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.reporting.its</groupId>
+  <artifactId>use-as-direct-mojo-markup</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>Use report as direct mojo to markup</name>
+  <description>Use report directly as mojo to markup: "mvn my-plugin:my-report"</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.reporting.its</groupId>
+        <artifactId>custom-reporting-plugin</artifactId>
+        <version>1.0-SNAPSHOT</version>
+      </plugin>
+    </plugins>
+  </build>
+</project>


=====================================
src/it/use-as-direct-mojo-markup/verify.groovy
=====================================
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+File outputDir = new File( basedir, 'target/reports/' )
+
+File f = new File( outputDir, 'custom-report.xdoc' );
+assert f.exists();
+assert f.text.contains( 'Custom Maven Report content.' );
+
+f = new File( outputDir, 'custom-report-with-renderer.apt' );
+assert f.exists();
+assert f.text.contains( 'Custom Maven Report with Renderer content.' );
+
+f = new File( outputDir, 'external/report.html' );
+assert f.exists();
+assert f.text.contains( '<h1>External Report</h1>' );
+
+return true;


=====================================
src/it/use-as-direct-mojo/invoker.properties
=====================================
@@ -15,6 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-invoker.goals.1 = org.apache.maven.reporting.its:custom-reporting-plugin:1.0-SNAPSHOT:custom
-invoker.goals.2 = org.apache.maven.reporting.its:custom-reporting-plugin:1.0-SNAPSHOT:custom-renderer
-invoker.goals.3 = org.apache.maven.reporting.its:custom-reporting-plugin:1.0-SNAPSHOT:external
+invoker.goals.1 = custom-reporting:custom
+invoker.goals.2 = custom-reporting:custom-renderer
+invoker.goals.3 = custom-reporting:external


=====================================
src/it/use-as-direct-mojo/pom.xml
=====================================
@@ -30,4 +30,14 @@ under the License.
 
   <name>Use report as direct mojo</name>
   <description>Use report directly as mojo: "mvn my-plugin:my-report"</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.reporting.its</groupId>
+        <artifactId>custom-reporting-plugin</artifactId>
+        <version>1.0-SNAPSHOT</version>
+      </plugin>
+    </plugins>
+  </build>
 </project>


=====================================
src/it/use-as-direct-mojo/verify.groovy
=====================================
@@ -17,18 +17,21 @@
  * under the License.
  */
 
-File site = new File( basedir, 'target/site/' )
+File outputDir = new File( basedir, 'target/reports/' )
 
-File f = new File( site, 'custom-report.html' );
+File f = new File( outputDir, 'custom-report.html' );
 assert f.exists();
 assert f.text.contains( 'Custom Maven Report content.' );
 
-f = new File( site, 'custom-report-with-renderer.html' );
+f = new File( outputDir, 'custom-report-with-renderer.html' );
 assert f.exists();
-assert f.text.contains( 'Custom Maven Report with Renderer content.' );
+text = f.text.normalize();
+assert text.contains( 'Custom Maven Report with Renderer content.' );
+assert text.contains( '<pre>Custom verbatim text.</pre>' );
+assert text.contains( '<pre class="prettyprint"><code>var custom_code = true;</code></pre>' );
 
-f = new File( site, 'external/report.html' );
+f = new File( outputDir, 'external/report.html' );
 assert f.exists();
 assert f.text.contains( '<h1>External Report</h1>' );
 
-return true;
\ No newline at end of file
+return true;


=====================================
src/it/use-as-site-report/pom.xml
=====================================
@@ -37,7 +37,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-site-plugin</artifactId>
-        <version>3.11.0</version>
+        <version>3.20.0</version>
       </plugin>
     </plugins>
   </build>
@@ -47,7 +47,7 @@ under the License.
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-project-info-reports-plugin</artifactId>
-        <version>3.4.0</version>
+        <version>3.7.0</version>
         <reportSets>
           <reportSet>
             <reports>


=====================================
src/it/use-as-site-report/verify.groovy
=====================================
@@ -25,10 +25,13 @@ assert f.text.contains( 'Custom Maven Report content.' );
 
 f = new File( site, 'custom-report-with-renderer.html' );
 assert f.exists();
-assert f.text.contains( 'Custom Maven Report with Renderer content.' );
+text = f.text.normalize();
+assert text.contains( 'Custom Maven Report with Renderer content.' );
+assert text.contains( '<pre>Custom verbatim text.</pre>' );
+assert text.contains( '<pre class="prettyprint"><code>var custom_code = true;</code></pre>' );
 
 f = new File( site, 'external/report.html' );
 assert f.exists();
 assert f.text.contains( '<h1>External Report</h1>' );
 
-return true;
\ No newline at end of file
+return true;


=====================================
src/main/java/org/apache/maven/reporting/AbstractMavenReport.java
=====================================
@@ -1,5 +1,3 @@
-package org.apache.maven.reporting;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@ package org.apache.maven.reporting;
  * "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
+ *   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
@@ -18,39 +16,50 @@ package org.apache.maven.reporting;
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.reporting;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
+import org.apache.maven.archiver.MavenArchiver;
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.doxia.sink.Sink;
 import org.apache.maven.doxia.sink.SinkFactory;
-import org.apache.maven.doxia.site.decoration.DecorationModel;
+import org.apache.maven.doxia.site.SiteModel;
+import org.apache.maven.doxia.siterenderer.DocumentRenderingContext;
 import org.apache.maven.doxia.siterenderer.Renderer;
 import org.apache.maven.doxia.siterenderer.RendererException;
-import org.apache.maven.doxia.siterenderer.RenderingContext;
 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
 import org.apache.maven.doxia.tools.SiteTool;
 import org.apache.maven.doxia.tools.SiteToolException;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.Reporting;
 import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.shared.utils.WriterFactory;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.util.PathTool;
 import org.codehaus.plexus.util.ReaderFactory;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.RemoteRepository;
 
 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
 /**
  * The basis for a Maven report which can be generated both as part of a site generation or
  * as a direct standalone goal invocation.
@@ -67,47 +76,85 @@ import java.util.Map;
  *  from maven-reporting-api
  * @see #executeReport(Locale) <code>abstract executeReport( Locale )</code>
  */
-public abstract class AbstractMavenReport
-    extends AbstractMojo
-    implements MavenMultiPageReport
-{
+public abstract class AbstractMavenReport extends AbstractMojo implements MavenMultiPageReport {
     /**
-     * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
-     * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
-     * the Maven Site Plugin is used instead.
+     * The shared output directory for the report. Note that this parameter is only evaluated if the goal is run
+     * directly from the command line. If the goal is run indirectly as part of a site generation, the shared
+     * output directory configured in the
+     * <a href="https://maven.apache.org/plugins/maven-site-plugin/site-mojo.html#outputDirectory">Maven Site Plugin</a>
+     * is used instead.
+     *<p>
+     * A plugin may use any subdirectory structure (either using a hard-coded name or, ideally, an additional
+     * user-defined mojo parameter with a default value) to generate multi-page reports or external reports with the
+     * main output file (entry point) denoted by {@link #getOutputName()}.
      */
-    @Parameter( defaultValue = "${project.reporting.outputDirectory}", readonly = true, required = true )
+    @Parameter(defaultValue = "${project.build.directory}/reports", required = true)
     protected File outputDirectory;
 
     /**
      * The Maven Project.
      */
-    @Parameter( defaultValue = "${project}", readonly = true, required = true )
+    @Parameter(defaultValue = "${project}", readonly = true, required = true)
     protected MavenProject project;
 
+    /**
+     * The mojo execution
+     */
+    @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
+    protected MojoExecution mojoExecution;
+
+    /**
+     * The reactor projects.
+     */
+    @Parameter(defaultValue = "${reactorProjects}", required = true, readonly = true)
+    protected List<MavenProject> reactorProjects;
+
     /**
      * Specifies the input encoding.
      */
-    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}", readonly = true )
+    @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}", readonly = true)
     private String inputEncoding;
 
     /**
      * Specifies the output encoding.
      */
-    @Parameter( property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}", readonly = true )
+    @Parameter(property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}", readonly = true)
     private String outputEncoding;
 
     /**
-     * The local repository.
+     * The repository system session.
+     */
+    @Parameter(defaultValue = "${repositorySystemSession}", readonly = true, required = true)
+    protected RepositorySystemSession repoSession;
+
+    /**
+     * Remote project repositories used for the project.
      */
-    @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
-    protected ArtifactRepository localRepository;
+    @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true)
+    protected List<RemoteRepository> remoteProjectRepositories;
 
     /**
-     * Remote repositories used for the project.
+     * Directory containing the <code>site.xml</code> file.
      */
-    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
-    protected List<ArtifactRepository> remoteRepositories;
+    @Parameter(defaultValue = "${basedir}/src/site")
+    protected File siteDirectory;
+
+    /**
+     * The locale to use  when the report generation is invoked directly as a standalone Mojo.
+     *
+     * @see SiteTool#DEFAULT_LOCALE
+     * @see SiteTool#getSiteLocales(String)
+     */
+    @Parameter(defaultValue = "default")
+    protected String locale;
+
+    /**
+     * Timestamp for reproducible output archive entries, either formatted as ISO 8601
+     * <code>yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds since the epoch (like
+     * <a href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
+     */
+    @Parameter(defaultValue = "${project.build.outputTimestamp}")
+    protected String outputTimestamp;
 
     /**
      * SiteTool.
@@ -127,107 +174,156 @@ public abstract class AbstractMavenReport
     /** The sink factory to use */
     private SinkFactory sinkFactory;
 
-    /** The current report output directory to use */
+    /** The current shared report output directory to use */
     private File reportOutputDirectory;
 
+    /**
+     * The report output format: null by default, to represent a site, but can be configured to a Doxia Sink id.
+     */
+    @Parameter(property = "output.format")
+    protected String outputFormat;
+
+    @Component
+    private PlexusContainer container;
+
     /**
      * This method is called when the report generation is invoked directly as a standalone Mojo.
+     * This implementation is now marked {@code final} as it is not expected to be overridden:
+     * {@code maven-reporting-impl} provides all necessary plumbing.
      *
      * @throws MojoExecutionException if an error occurs when generating the report
      * @see org.apache.maven.plugin.Mojo#execute()
      */
     @Override
-    public void execute()
-        throws MojoExecutionException
-    {
-        if ( !canGenerateReport() )
-        {
-            return;
+    public final void execute() throws MojoExecutionException {
+        try {
+            if (!canGenerateReport()) {
+                String reportMojoInfo = mojoExecution.getPlugin().getId() + ":" + mojoExecution.getGoal();
+                getLog().info("Skipping " + reportMojoInfo + " report goal");
+                return;
+            }
+        } catch (MavenReportException e) {
+            throw new MojoExecutionException("Failed to determine whether report can be generated", e);
+        }
+
+        if (outputFormat != null) {
+            reportToMarkup();
+        } else {
+            reportToSite();
         }
+    }
 
-        File outputDirectory = new File( getOutputDirectory() );
+    private void reportToMarkup() throws MojoExecutionException {
+        getLog().info("Rendering to " + outputFormat + " markup");
+
+        if (!isExternalReport()) {
+            File outputDirectory = new File(getOutputDirectory());
+            String filename = getOutputName() + '.' + outputFormat;
+            try {
+                sinkFactory = container.lookup(SinkFactory.class, outputFormat);
+                sink = sinkFactory.createSink(outputDirectory, filename);
+            } catch (ComponentLookupException cle) {
+                throw new MojoExecutionException(
+                        "Cannot find SinkFactory for Doxia output format: " + outputFormat, cle);
+            } catch (IOException ioe) {
+                throw new MojoExecutionException("Cannot create sink to " + new File(outputDirectory, filename), ioe);
+            }
+        }
+
+        try {
+            Locale locale = getLocale();
+            generate(sink, sinkFactory, locale);
+        } catch (MavenReportException e) {
+            throw new MojoExecutionException(
+                    "An error has occurred in " + getName(Locale.ENGLISH) + " report generation.", e);
+        } finally {
+            if (sink != null) {
+                sink.close();
+            }
+        }
+    }
+
+    private void reportToSite() throws MojoExecutionException {
+        File outputDirectory = new File(getOutputDirectory());
 
         String filename = getOutputName() + ".html";
 
-        Locale locale = Locale.getDefault();
+        Locale locale = getLocale();
 
-        try
-        {
-            SiteRenderingContext siteContext = createSiteRenderingContext( locale );
+        try {
+            SiteRenderingContext siteContext = createSiteRenderingContext(locale);
 
             // copy resources
-            getSiteRenderer().copyResources( siteContext, outputDirectory );
+            getSiteRenderer().copyResources(siteContext, outputDirectory);
 
-            // TODO Replace null with real value
-            RenderingContext docRenderingContext = new RenderingContext( outputDirectory, filename, null );
+            String reportMojoInfo = mojoExecution.getPlugin().getId() + ":" + mojoExecution.getGoal();
+            DocumentRenderingContext docRenderingContext =
+                    new DocumentRenderingContext(outputDirectory, getOutputName(), reportMojoInfo);
 
-            SiteRendererSink sink = new SiteRendererSink( docRenderingContext );
+            SiteRendererSink sink = new SiteRendererSink(docRenderingContext);
 
-            generate( sink, null, locale );
+            // TODO Compared to Maven Site Plugin multipage reports will not work and fail with an NPE
+            generate(sink, null, locale);
 
-            if ( !isExternalReport() ) // MSHARED-204: only render Doxia sink if not an external report
+            if (!isExternalReport()) // MSHARED-204: only render Doxia sink if not an external report
             {
                 outputDirectory.mkdirs();
 
-                try ( Writer writer =
-                      new OutputStreamWriter( new FileOutputStream( new File( outputDirectory, filename ) ),
-                                              getOutputEncoding() ) )
-                {
+                try (Writer writer = new OutputStreamWriter(
+                        new FileOutputStream(new File(outputDirectory, filename)), getOutputEncoding())) {
                     // render report
-                    getSiteRenderer().mergeDocumentIntoSite( writer, sink, siteContext );
+                    getSiteRenderer().mergeDocumentIntoSite(writer, sink, siteContext);
                 }
             }
 
             // copy generated resources also
-            getSiteRenderer().copyResources( siteContext, outputDirectory );
-        }
-        catch ( RendererException | IOException | MavenReportException e )
-        {
+            getSiteRenderer().copyResources(siteContext, outputDirectory);
+        } catch (RendererException | IOException | MavenReportException | SiteToolException e) {
             throw new MojoExecutionException(
-                "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation.", e );
+                    "An error has occurred in " + getName(Locale.ENGLISH) + " report generation.", e);
         }
     }
 
-    private SiteRenderingContext createSiteRenderingContext( Locale locale )
-        throws MavenReportException, IOException
-    {
-        DecorationModel decorationModel = new DecorationModel();
+    private SiteRenderingContext createSiteRenderingContext(Locale locale)
+            throws MavenReportException, IOException, SiteToolException {
+        SiteModel siteModel = siteTool.getSiteModel(
+                siteDirectory, locale, project, reactorProjects, repoSession, remoteProjectRepositories);
 
         Map<String, Object> templateProperties = new HashMap<>();
         // We tell the skin that we are rendering in standalone mode
-        templateProperties.put( "standalone", Boolean.TRUE );
-        templateProperties.put( "project", getProject() );
-        templateProperties.put( "inputEncoding", getInputEncoding() );
-        templateProperties.put( "outputEncoding", getOutputEncoding() );
+        templateProperties.put("standalone", Boolean.TRUE);
+        templateProperties.put("project", getProject());
+        templateProperties.put("inputEncoding", getInputEncoding());
+        templateProperties.put("outputEncoding", getOutputEncoding());
         // Put any of the properties in directly into the Velocity context
-        for ( Map.Entry<Object, Object> entry : getProject().getProperties().entrySet() )
-        {
-            templateProperties.put( (String) entry.getKey(), entry.getValue() );
+        for (Map.Entry<Object, Object> entry : getProject().getProperties().entrySet()) {
+            templateProperties.put((String) entry.getKey(), entry.getValue());
         }
 
         SiteRenderingContext context;
-        try
-        {
-           Artifact skinArtifact =
-               siteTool.getSkinArtifactFromRepository( localRepository, remoteRepositories, decorationModel );
-
-           getLog().info( buffer().a( "Rendering content with " ).strong( skinArtifact.getId()
-               + " skin" ).a( '.' ).toString() );
-
-            context = siteRenderer.createContextForSkin( skinArtifact, templateProperties, decorationModel,
-                                                         project.getName(), locale );
-        }
-        catch ( SiteToolException e )
-        {
-            throw new MavenReportException( "Failed to retrieve skin artifact", e );
-        }
-        catch ( RendererException e )
-        {
-            throw new MavenReportException( "Failed to create context for skin", e );
+        try {
+            Artifact skinArtifact =
+                    siteTool.getSkinArtifactFromRepository(repoSession, remoteProjectRepositories, siteModel.getSkin());
+
+            getLog().info(buffer().a("Rendering content with ")
+                    .strong(skinArtifact.getId() + " skin")
+                    .toString());
+
+            context = siteRenderer.createContextForSkin(
+                    skinArtifact, templateProperties, siteModel, project.getName(), locale);
+        } catch (SiteToolException e) {
+            throw new MavenReportException("Failed to retrieve skin artifact", e);
+        } catch (RendererException e) {
+            throw new MavenReportException("Failed to create context for skin", e);
         }
 
+        // Add publish date
+        MavenArchiver.parseBuildOutputTimestamp(outputTimestamp).ifPresent(v -> {
+            context.setPublishDate(Date.from(v));
+        });
+
         // Generate static site
-        context.setRootDirectory( project.getBasedir() );
+        context.setRootDirectory(project.getBasedir());
 
         return context;
     }
@@ -242,25 +338,8 @@ public abstract class AbstractMavenReport
      */
     @Deprecated
     @Override
-    public void generate( org.codehaus.doxia.sink.Sink sink, Locale locale )
-        throws MavenReportException
-    {
-        generate( sink, null, locale );
-    }
-
-    /**
-     * Generate a report.
-     *
-     * @param sink
-     * @param locale
-     * @throws MavenReportException
-     * @deprecated use {@link #generate(Sink, SinkFactory, Locale)} instead.
-     */
-    @Deprecated
-    public void generate( Sink sink, Locale locale )
-        throws MavenReportException
-    {
-        generate( sink, null, locale );
+    public void generate(Sink sink, Locale locale) throws MavenReportException {
+        generate(sink, null, locale);
     }
 
     /**
@@ -272,22 +351,11 @@ public abstract class AbstractMavenReport
      * @throws MavenReportException
      */
     @Override
-    public void generate( Sink sink, SinkFactory sinkFactory, Locale locale )
-        throws MavenReportException
-    {
-        if ( !canGenerateReport() )
-        {
-            getLog().info( "This report cannot be generated as part of the current build. "
-                           + "The report name should be referenced in this line of output." );
-            return;
-        }
-
+    public void generate(Sink sink, SinkFactory sinkFactory, Locale locale) throws MavenReportException {
         this.sink = sink;
-
         this.sinkFactory = sinkFactory;
 
-        executeReport( locale );
-
+        executeReport(locale);
         closeReport();
     }
 
@@ -295,41 +363,34 @@ public abstract class AbstractMavenReport
      * @return CATEGORY_PROJECT_REPORTS
      */
     @Override
-    public String getCategoryName()
-    {
+    public String getCategoryName() {
         return CATEGORY_PROJECT_REPORTS;
     }
 
     @Override
-    public File getReportOutputDirectory()
-    {
-        if ( reportOutputDirectory == null )
-        {
-            reportOutputDirectory = new File( getOutputDirectory() );
+    public File getReportOutputDirectory() {
+        if (reportOutputDirectory == null) {
+            reportOutputDirectory = new File(getOutputDirectory());
         }
 
         return reportOutputDirectory;
     }
 
     @Override
-    public void setReportOutputDirectory( File reportOutputDirectory )
-    {
+    public void setReportOutputDirectory(File reportOutputDirectory) {
         this.reportOutputDirectory = reportOutputDirectory;
         this.outputDirectory = reportOutputDirectory;
     }
 
-    protected String getOutputDirectory()
-    {
+    protected String getOutputDirectory() {
         return outputDirectory.getAbsolutePath();
     }
 
-    protected MavenProject getProject()
-    {
+    protected MavenProject getProject() {
         return project;
     }
 
-    protected Renderer getSiteRenderer()
-    {
+    protected Renderer getSiteRenderer() {
         return siteRenderer;
     }
 
@@ -338,9 +399,8 @@ public abstract class AbstractMavenReport
      *
      * @return The input files encoding, never <code>null</code>.
      */
-    protected String getInputEncoding()
-    {
-        return ( inputEncoding == null ) ? ReaderFactory.FILE_ENCODING : inputEncoding;
+    protected String getInputEncoding() {
+        return (inputEncoding == null) ? ReaderFactory.FILE_ENCODING : inputEncoding;
     }
 
     /**
@@ -348,32 +408,39 @@ public abstract class AbstractMavenReport
      *
      * @return The effective reporting output file encoding, never <code>null</code>.
      */
-    protected String getOutputEncoding()
-    {
-        return ( outputEncoding == null ) ? WriterFactory.UTF_8 : outputEncoding;
+    protected String getOutputEncoding() {
+        return (outputEncoding == null) ? WriterFactory.UTF_8 : outputEncoding;
+    }
+
+    /**
+     * Gets the locale
+     *
+     * @return the locale for this standalone report
+     */
+    protected Locale getLocale() {
+        return siteTool.getSiteLocales(locale).get(0);
     }
 
     /**
      * Actions when closing the report.
      */
-    protected void closeReport()
-    {
-        getSink().close();
+    protected void closeReport() {
+        if (getSink() != null) {
+            getSink().close();
+        }
     }
 
     /**
      * @return the sink used
      */
-    public Sink getSink()
-    {
+    public Sink getSink() {
         return sink;
     }
 
     /**
      * @return the sink factory used
      */
-    public SinkFactory getSinkFactory()
-    {
+    public SinkFactory getSinkFactory() {
         return sinkFactory;
     }
 
@@ -382,14 +449,12 @@ public abstract class AbstractMavenReport
      * @return {@code false} by default.
      */
     @Override
-    public boolean isExternalReport()
-    {
+    public boolean isExternalReport() {
         return false;
     }
 
     @Override
-    public boolean canGenerateReport()
-    {
+    public boolean canGenerateReport() throws MavenReportException {
         return true;
     }
 
@@ -399,6 +464,57 @@ public abstract class AbstractMavenReport
      * @param locale the wanted locale to return the report's description, could be <code>null</code>.
      * @throws MavenReportException if any
      */
-    protected abstract void executeReport( Locale locale )
-        throws MavenReportException;
+    protected abstract void executeReport(Locale locale) throws MavenReportException;
+
+    /**
+     * Returns the (Test) Source XRef location as passthrough if provided, otherwise returns the
+     * default value.
+     *
+     * @param location the XRef location provided via plugin parameter, if any
+     * @param test whether it is test source
+     * @return the actual (Test) Source XRef location
+     */
+    protected File getXrefLocation(File location, boolean test) {
+        return location != null ? location : new File(getReportOutputDirectory(), test ? "xref-test" : "xref");
+    }
+
+    /**
+     * Contructs the (Test) Source XRef location relative to the {@link #getReportOutputDirectory()}
+     * with {@link #getXrefLocation(File, boolean)}.
+     *
+     * @param location the XRef location provided via plugin parameter, if any
+     * @param test whether it is test source
+     * @return the constructed (Test) Source XRef location
+     */
+    protected String constructXrefLocation(File location, boolean test) {
+        String constructedLocation = null;
+        File xrefLocation = getXrefLocation(location, test);
+
+        String relativePath =
+                PathTool.getRelativePath(getReportOutputDirectory().getAbsolutePath(), xrefLocation.getAbsolutePath());
+        if (relativePath == null || relativePath.isEmpty()) {
+            relativePath = ".";
+        }
+        relativePath = relativePath + "/" + xrefLocation.getName();
+        if (xrefLocation.exists()) {
+            // XRef was already generated by manual execution of a lifecycle binding
+            constructedLocation = relativePath;
+        } else {
+            // Not yet generated - check if the report is on its way
+            Reporting reporting = project.getModel().getReporting();
+            List<ReportPlugin> reportPlugins =
+                    reporting != null ? reporting.getPlugins() : Collections.<ReportPlugin>emptyList();
+            for (ReportPlugin plugin : reportPlugins) {
+                String artifactId = plugin.getArtifactId();
+                if ("maven-jxr-plugin".equals(artifactId)) {
+                    constructedLocation = relativePath;
+                }
+            }
+        }
+
+        if (constructedLocation == null) {
+            getLog().warn("Unable to locate" + (test ? " Test" : "") + " Source XRef to link to -- DISABLED");
+        }
+        return constructedLocation;
+    }
 }


=====================================
src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java
=====================================
@@ -1,5 +1,3 @@
-package org.apache.maven.reporting;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@ package org.apache.maven.reporting;
  * "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
+ *   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
@@ -18,12 +16,7 @@ package org.apache.maven.reporting;
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.doxia.sink.Sink;
-import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
-import org.apache.maven.doxia.util.HtmlTools;
-
-import org.apache.maven.shared.utils.StringUtils;
+package org.apache.maven.reporting;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -32,6 +25,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.maven.doxia.markup.Markup;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.apache.maven.shared.utils.StringUtils;
+
 /**
  * <p>An abstract class to manage report generation, with many helper methods to ease the job: you just need to
  * implement getTitle() and renderBody().</p>
@@ -47,9 +45,7 @@ import java.util.Properties;
  * @see #getTitle()
  * @see #renderBody()
  */
-public abstract class AbstractMavenReportRenderer
-    implements MavenReportRenderer
-{
+public abstract class AbstractMavenReportRenderer implements MavenReportRenderer {
     /** The current sink to use */
     protected Sink sink;
 
@@ -61,19 +57,17 @@ public abstract class AbstractMavenReportRenderer
      *
      * @param sink the sink to use.
      */
-    public AbstractMavenReportRenderer( Sink sink )
-    {
+    public AbstractMavenReportRenderer(Sink sink) {
         this.sink = sink;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void render()
-    {
+    public void render() {
         sink.head();
 
         sink.title();
-        text( getTitle() );
+        text(getTitle());
         sink.title_();
 
         sink.head_();
@@ -92,127 +86,51 @@ public abstract class AbstractMavenReportRenderer
     // ----------------------------------------------------------------------
 
     /**
-     * Convenience method to wrap section creation in the current sink. An anchor will be add for the name.
+     * Convenience method to wrap section creation in the current sink.
+     * An anchor will be derived from the name.
      *
      * @param name the name of this section, could be null.
      * @see #text(String)
-     * @see Sink#section1()
-     * @see Sink#sectionTitle1()
-     * @see Sink#sectionTitle1_()
-     * @see Sink#section2()
-     * @see Sink#sectionTitle2()
-     * @see Sink#sectionTitle2_()
-     * @see Sink#section3()
-     * @see Sink#sectionTitle3()
-     * @see Sink#sectionTitle3_()
-     * @see Sink#section4()
-     * @see Sink#sectionTitle4()
-     * @see Sink#sectionTitle4_()
-     * @see Sink#section5()
-     * @see Sink#sectionTitle5()
-     * @see Sink#sectionTitle5_()
+     * @see Sink#section(int, org.apache.maven.doxia.sink.SinkEventAttributes)
+     * @see Sink#sectionTitle(int, org.apache.maven.doxia.sink.SinkEventAttributes)
+     * @see Sink#sectionTitle_(int)
      */
-    protected void startSection( String name )
-    {
-        section = section + 1;
-
-        switch ( section )
-        {
-            case 1:
-                sink.section1();
-                sink.sectionTitle1();
-                break;
-            case 2:
-                sink.section2();
-                sink.sectionTitle2();
-                break;
-            case 3:
-                sink.section3();
-                sink.sectionTitle3();
-                break;
-            case 4:
-                sink.section4();
-                sink.sectionTitle4();
-                break;
-            case 5:
-                sink.section5();
-                sink.sectionTitle5();
-                break;
-
-            default:
-                // TODO: warning - just don't start a section
-                break;
-        }
-
-        text( name );
-
-        switch ( section )
-        {
-            case 1:
-                sink.sectionTitle1_();
-                break;
-            case 2:
-                sink.sectionTitle2_();
-                break;
-            case 3:
-                sink.sectionTitle3_();
-                break;
-            case 4:
-                sink.sectionTitle4_();
-                break;
-            case 5:
-                sink.sectionTitle5_();
-                break;
-
-            default:
-                // TODO: warning - just don't start a section
-                break;
-        }
+    protected void startSection(String name) {
+        startSection(name, name);
+    }
 
-        sink.anchor( HtmlTools.encodeId( name ) );
+    /**
+     * Convenience method to wrap section creation in the current sink.
+     *
+     * @param name the name of this section, could be null.
+     * @param anchor the anchor of this section, could be null.
+     * @see #text(String)
+     * @see Sink#section(int, org.apache.maven.doxia.sink.SinkEventAttributes)
+     * @see Sink#sectionTitle(int, org.apache.maven.doxia.sink.SinkEventAttributes)
+     * @see Sink#sectionTitle_(int)
+     */
+    protected void startSection(String name, String anchor) {
+        section++;
+        sink.section(section, null);
+        sink.anchor(anchor);
         sink.anchor_();
+        sink.sectionTitle(section, null);
+        text(name);
+        sink.sectionTitle_(section);
     }
 
     /**
      * Convenience method to wrap section ending in the current sink.
      *
-     * @see Sink#section1_()
-     * @see Sink#section2_()
-     * @see Sink#section3_()
-     * @see Sink#section4_()
-     * @see Sink#section5_()
+     * @see Sink#section_(int)
      * @throws IllegalStateException if too many closing sections.
      */
-    protected void endSection()
-    {
-        switch ( section )
-        {
-            case 1:
-                sink.section1_();
-                break;
-            case 2:
-                sink.section2_();
-                break;
-            case 3:
-                sink.section3_();
-                break;
-            case 4:
-                sink.section4_();
-                break;
-            case 5:
-                sink.section5_();
-                break;
-
-            default:
-                // TODO: warning - just don't start a section
-                break;
-        }
+    protected void endSection() {
+        sink.section_(section);
+        section--;
 
-        section = section - 1;
-
-        if ( section < 0 )
-        {
-            throw new IllegalStateException( "Too many closing sections" );
+        if (section < 0) {
+            throw new IllegalStateException("Too many closing sections");
         }
     }
 
@@ -225,9 +143,8 @@ public abstract class AbstractMavenReportRenderer
      *
      * @see Sink#table()
      */
-    protected void startTable()
-    {
-        startTable( new int[] {Sink.JUSTIFY_LEFT}, false );
+    protected void startTable() {
+        startTable(null, false);
     }
 
     /**
@@ -240,10 +157,9 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableRows(int[],boolean)
      * @since 2.1
      */
-    protected void startTable( int[] justification, boolean grid )
-    {
+    protected void startTable(int[] justification, boolean grid) {
         sink.table();
-        sink.tableRows( justification, grid );
+        sink.tableRows(justification, grid);
     }
 
     /**
@@ -251,8 +167,7 @@ public abstract class AbstractMavenReportRenderer
      *
      * @see Sink#table_()
      */
-    protected void endTable()
-    {
+    protected void endTable() {
         sink.tableRows_();
         sink.table_();
     }
@@ -265,11 +180,10 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableHeaderCell()
      * @see Sink#tableHeaderCell_()
      */
-    protected void tableHeaderCell( String text )
-    {
+    protected void tableHeaderCell(String text) {
         sink.tableHeaderCell();
 
-        text( text );
+        text(text);
 
         sink.tableHeaderCell_();
     }
@@ -282,9 +196,8 @@ public abstract class AbstractMavenReportRenderer
      * @see #linkPatternedText(String)
      * @see #tableCell(String)
      */
-    protected void tableCell( String text )
-    {
-        tableCell( text, false );
+    protected void tableCell(String text) {
+        tableCell(text, false);
     }
 
     /**
@@ -299,17 +212,13 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableCell_()
      * @see Sink#rawText(String)
      */
-    protected void tableCell( String text, boolean asHtml )
-    {
+    protected void tableCell(String text, boolean asHtml) {
         sink.tableCell();
 
-        if ( asHtml )
-        {
-            sink.rawText( text );
-        }
-        else
-        {
-            linkPatternedText( text );
+        if (asHtml) {
+            sink.rawText(text);
+        } else {
+            linkPatternedText(text);
         }
 
         sink.tableCell_();
@@ -324,15 +233,12 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableRow()
      * @see Sink#tableRow_()
      */
-    protected void tableRow( String[] content )
-    {
+    protected void tableRow(String[] content) {
         sink.tableRow();
 
-        if ( content != null )
-        {
-            for ( int i = 0; i < content.length; i++ )
-            {
-                tableCell( content[i] );
+        if (content != null) {
+            for (int i = 0; i < content.length; i++) {
+                tableCell(content[i]);
             }
         }
 
@@ -347,15 +253,12 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableRow()
      * @see Sink#tableRow_()
      */
-    protected void tableHeader( String[] content )
-    {
+    protected void tableHeader(String[] content) {
         sink.tableRow();
 
-        if ( content != null )
-        {
-            for ( int i = 0; i < content.length; i++ )
-            {
-                tableHeaderCell( content[i] );
+        if (content != null) {
+            for (int i = 0; i < content.length; i++) {
+                tableHeaderCell(content[i]);
             }
         }
 
@@ -370,11 +273,10 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#tableCaption()
      * @see Sink#tableCaption_()
      */
-    protected void tableCaption( String caption )
-    {
+    protected void tableCaption(String caption) {
         sink.tableCaption();
 
-        text( caption );
+        text(caption);
 
         sink.tableCaption_();
     }
@@ -391,11 +293,10 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#paragraph()
      * @see Sink#paragraph_()
      */
-    protected void paragraph( String paragraph )
-    {
+    protected void paragraph(String paragraph) {
         sink.paragraph();
 
-        text( paragraph );
+        text(paragraph);
 
         sink.paragraph_();
     }
@@ -409,31 +310,27 @@ public abstract class AbstractMavenReportRenderer
      * @see Sink#link(String)
      * @see Sink#link_()
      */
-    protected void link( String href, String name )
-    {
-        sink.link( href );
+    protected void link(String href, String name) {
+        sink.link(href);
 
-        text( name );
+        text(name);
 
         sink.link_();
     }
 
     /**
      * Convenience method to wrap a text in the current sink.
-     * <p>If text is empty or has a <code>null</code> value, add the <code>"-"</code> charater</p>
+     * <p>If text is empty or has a <code>null</code> value, add the <code>"-"</code> character</p>
      *
      * @param text a text, could be null.
      * @see Sink#text(String)
      */
-    protected void text( String text )
-    {
-        if ( StringUtils.isEmpty( text ) ) // Take care of spaces
-        {
-            sink.text( "-" );
-        }
-        else
+    protected void text(String text) {
+        if (text == null || text.isEmpty()) // Take care of spaces
         {
-            sink.text( text );
+            sink.text("-");
+        } else {
+            sink.text(text);
         }
     }
 
@@ -442,14 +339,13 @@ public abstract class AbstractMavenReportRenderer
      *
      * @param text a text, could be null.
      * @see #text(String)
-     * @see Sink#verbatim(boolean)
+     * @see Sink#verbatim(org.apache.maven.doxia.sink.SinkEventAttributes)
      * @see Sink#verbatim_()
      */
-    protected void verbatimText( String text )
-    {
-        sink.verbatim( SinkEventAttributeSet.BOXED );
+    protected void verbatimText(String text) {
+        sink.verbatim();
 
-        text( text );
+        text(text);
 
         sink.verbatim_();
     }
@@ -461,34 +357,45 @@ public abstract class AbstractMavenReportRenderer
      * @param href an href could be null
      * @see #link(String, String)
      * @see #verbatimText(String)
-     * @see Sink#verbatim(boolean)
+     * @see Sink#verbatim(org.apache.maven.doxia.sink.SinkEventAttributes)
      * @see Sink#verbatim_()
      */
-    protected void verbatimLink( String text, String href )
-    {
-        if ( StringUtils.isEmpty( href ) )
-        {
-            verbatimText( text );
-        }
-        else
-        {
-            sink.verbatim( SinkEventAttributeSet.BOXED );
+    protected void verbatimLink(String text, String href) {
+        if (href == null || href.isEmpty()) {
+            verbatimText(text);
+        } else {
+            sink.verbatim();
 
-            link( href, text );
+            link(href, text);
 
             sink.verbatim_();
         }
     }
 
+    /**
+     * Convenience method to wrap source code as verbatim style in the current sink .
+     *
+     * @param source a source code, could be null.
+     * @see #text(String)
+     * @see Sink#verbatim(org.apache.maven.doxia.sink.SinkEventAttributes)
+     * @see Sink#verbatim_()
+     */
+    protected void verbatimSource(String source) {
+        sink.verbatim(SinkEventAttributeSet.SOURCE);
+
+        text(source);
+
+        sink.verbatim_();
+    }
+
     /**
      * Convenience method to add a Javascript code in the current sink.
      *
      * @param jsCode a string of Javascript
      * @see Sink#rawText(String)
      */
-    protected void javaScript( String jsCode )
-    {
-        sink.rawText( "<script type=\"text/javascript\">\n" + jsCode + "</script>" );
+    protected void javaScript(String jsCode) {
+        sink.rawText(Markup.EOL + "<script>" + Markup.EOL + jsCode + Markup.EOL + "</script>" + Markup.EOL);
     }
 
     /**
@@ -501,34 +408,23 @@ public abstract class AbstractMavenReportRenderer
      * @see #link(String, String)
      * @see #applyPattern(String)
      */
-    public void linkPatternedText( String text )
-    {
-        if ( StringUtils.isEmpty( text ) )
-        {
-            text( text );
-        }
-        else
-        {
-            List<String> segments = applyPattern( text );
-
-            if ( segments == null )
-            {
-                text( text );
-            }
-            else
-            {
-                for ( Iterator<String> it = segments.iterator(); it.hasNext(); )
-                {
+    public void linkPatternedText(String text) {
+        if (text == null || text.isEmpty()) {
+            text(text);
+        } else {
+            List<String> segments = applyPattern(text);
+
+            if (segments == null) {
+                text(text);
+            } else {
+                for (Iterator<String> it = segments.iterator(); it.hasNext(); ) {
                     String name = it.next();
                     String href = it.next();
 
-                    if ( href == null )
-                    {
-                        text( name );
-                    }
-                    else
-                    {
-                       link( href, name );
+                    if (href == null) {
+                        text(name);
+                    } else {
+                        link(href, name);
                     }
                 }
             }
@@ -545,15 +441,12 @@ public abstract class AbstractMavenReportRenderer
      * @return a link pattern
      * @see #linkPatternedText(String)
      */
-    protected static String createLinkPatternedText( String text, String href )
-    {
-        if ( text == null )
-        {
+    protected static String createLinkPatternedText(String text, String href) {
+        if (text == null) {
             return text;
         }
 
-        if ( href == null )
-        {
+        if (href == null) {
             return text;
         }
 
@@ -566,23 +459,19 @@ public abstract class AbstractMavenReportRenderer
      * @param props the properties to display.
      * @return the properties object as comma separated String
      */
-    protected static String propertiesToString( Properties props )
-    {
-        if ( props == null || props.isEmpty() )
-        {
+    protected static String propertiesToString(Properties props) {
+        if (props == null || props.isEmpty()) {
             return "";
         }
 
         StringBuilder sb = new StringBuilder();
 
-        for ( Map.Entry<?, ?> entry : props.entrySet() )
-        {
-            if ( sb.length() > 0 )
-            {
-                sb.append( ", " );
+        for (Map.Entry<?, ?> entry : props.entrySet()) {
+            if (sb.length() > 0) {
+                sb.append(", ");
             }
 
-            sb.append( entry.getKey() ).append( "=" ).append( entry.getValue() );
+            sb.append(entry.getKey()).append("=").append(entry.getValue());
         }
 
         return sb.toString();
@@ -599,10 +488,8 @@ public abstract class AbstractMavenReportRenderer
      * @param text a text with or without the pattern <code>{text, url}</code>
      * @return a map of text/href
      */
-    private static List<String> applyPattern( String text )
-    {
-        if ( StringUtils.isEmpty( text ) )
-        {
+    private static List<String> applyPattern(String text) {
+        if (text == null || text.isEmpty()) {
             return null;
         }
 
@@ -611,19 +498,15 @@ public abstract class AbstractMavenReportRenderer
         List<String> segments = new ArrayList<>();
 
         // TODO Special case http://jira.codehaus.org/browse/MEV-40
-        if ( text.indexOf( "${" ) != -1 )
-        {
-            int lastComma = text.lastIndexOf( "," );
-            int lastSemi = text.lastIndexOf( "}" );
-            if ( lastComma != -1 && lastSemi != -1 && lastComma < lastSemi )
-            {
-                segments.add( text.substring( lastComma + 1, lastSemi ).trim() );
-                segments.add( null );
-            }
-            else
-            {
-                segments.add( text );
-                segments.add( null );
+        if (text.indexOf("${") != -1) {
+            int lastComma = text.lastIndexOf(",");
+            int lastSemi = text.lastIndexOf("}");
+            if (lastComma != -1 && lastSemi != -1 && lastComma < lastSemi) {
+                segments.add(text.substring(lastComma + 1, lastSemi).trim());
+                segments.add(null);
+            } else {
+                segments.add(text);
+                segments.add(null);
             }
 
             return segments;
@@ -633,38 +516,28 @@ public abstract class AbstractMavenReportRenderer
         int braceStack = 0;
         int lastOffset = 0;
 
-        for ( int i = 0; i < text.length(); i++ )
-        {
-            char ch = text.charAt( i );
+        for (int i = 0; i < text.length(); i++) {
+            char ch = text.charAt(i);
 
-            if ( ch == '\'' && !inQuote && braceStack == 0 )
-            {
+            if (ch == '\'' && !inQuote && braceStack == 0) {
                 // handle: ''
-                if ( i + 1 < text.length() && text.charAt( i + 1 ) == '\'' )
-                {
+                if (i + 1 < text.length() && text.charAt(i + 1) == '\'') {
                     i++;
-                    segments.add( text.substring( lastOffset, i ) );
-                    segments.add( null );
+                    segments.add(text.substring(lastOffset, i));
+                    segments.add(null);
                     lastOffset = i + 1;
-                }
-                else
-                {
+                } else {
                     inQuote = true;
                 }
-            }
-            else
-            {
-                switch ( ch )
-                {
+            } else {
+                switch (ch) {
                     case '{':
-                        if ( !inQuote )
-                        {
-                            if ( braceStack == 0 )
-                            {
-                                if ( i != lastOffset ) // handle { at first character
+                        if (!inQuote) {
+                            if (braceStack == 0) {
+                                if (i != lastOffset) // handle { at first character
                                 {
-                                    segments.add( text.substring( lastOffset, i ) );
-                                    segments.add( null );
+                                    segments.add(text.substring(lastOffset, i));
+                                    segments.add(null);
                                 }
                                 lastOffset = i + 1;
                             }
@@ -672,24 +545,21 @@ public abstract class AbstractMavenReportRenderer
                         }
                         break;
                     case '}':
-                        if ( !inQuote )
-                        {
+                        if (!inQuote) {
                             braceStack--;
-                            if ( braceStack == 0 )
-                            {
-                                String subString = text.substring( lastOffset, i );
+                            if (braceStack == 0) {
+                                String subString = text.substring(lastOffset, i);
                                 lastOffset = i + 1;
 
-                                int lastComma = subString.lastIndexOf( "," );
-                                if ( lastComma != -1 )
-                                {
-                                    segments.add( subString.substring( 0, lastComma ).trim() );
-                                    segments.add( subString.substring( lastComma + 1 ).trim() );
-                                }
-                                else
-                                {
-                                    segments.add( subString );
-                                    segments.add( null );
+                                int lastComma = subString.lastIndexOf(",");
+                                if (lastComma != -1) {
+                                    segments.add(
+                                            subString.substring(0, lastComma).trim());
+                                    segments.add(
+                                            subString.substring(lastComma + 1).trim());
+                                } else {
+                                    segments.add(subString);
+                                    segments.add(null);
                                 }
                             }
                         }
@@ -703,24 +573,21 @@ public abstract class AbstractMavenReportRenderer
             }
         }
 
-        if ( !StringUtils.isEmpty( text.substring( lastOffset ) ) )
-        {
-            segments.add( text.substring( lastOffset ) );
-            segments.add( null );
+        if (!StringUtils.isEmpty(text.substring(lastOffset))) {
+            segments.add(text.substring(lastOffset));
+            segments.add(null);
         }
 
-        if ( braceStack != 0 )
-        {
-            throw new IllegalArgumentException( "Unmatched braces in the pattern." );
+        if (braceStack != 0) {
+            throw new IllegalArgumentException("Unmatched braces in the pattern.");
         }
 
-        if ( inQuote )
-        {
-            //throw new IllegalArgumentException( "Unmatched quote in the pattern." );
-            //TODO: warning...
+        if (inQuote) {
+            // throw new IllegalArgumentException( "Unmatched quote in the pattern." );
+            // TODO: warning...
         }
 
-        return Collections.unmodifiableList( segments );
+        return Collections.unmodifiableList(segments);
     }
 
     // ----------------------------------------------------------------------


=====================================
src/site/apt/index.apt.vm
=====================================
@@ -38,10 +38,13 @@ ${project.name}
 
   []
 
+  The two APIs implementations are provided by <<<{{{./apidocs/org/apache/maven/reporting/AbstractMavenReport.html}AbstractMavenReport}},
+  that delegates to extender's <<<executeReport( Locale )>>> reporting method implementation.
+
 * Usage
 
   A full working sample is included in <<<maven-reporting-impl>>> ITs, which are part of 
-  {{{../source-repository.html}the component source tree}}: see <<<src/it/setup-reporting-plugin>>>.
+  {{{../scm.html}the component source tree}}: see {{{https://github.com/apache/maven-reporting-impl/tree/${project.scm.tag}/src/it/setup-reporting-plugin}<<<src/it/setup-reporting-plugin>>>}}.
 
 * History
 


=====================================
src/test/java/org/apache/maven/reporting/AbstractMavenReportRendererTest.java
=====================================
@@ -1,5 +1,3 @@
-package org.apache.maven.reporting;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@ package org.apache.maven.reporting;
  * "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
+ *   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
@@ -18,51 +16,50 @@ package org.apache.maven.reporting;
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.reporting;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Iterator;
 import java.util.List;
 
-import junit.framework.Assert;
-import junit.framework.TestCase;
-import junitx.util.PrivateAccessor;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
 
 /**
  * Test case for some public method in AbstractMavenReportRenderer.
  */
-public class AbstractMavenReportRendererTest
-    extends TestCase
-{
-    private static List<String> applyPattern( String pattern )
-        throws Throwable
-    {
-        return (List<String>) PrivateAccessor.invoke( AbstractMavenReportRenderer.class, "applyPattern",
-                                              new Class[] { String.class }, new Object[] { pattern } );
+public class AbstractMavenReportRendererTest {
+    private static List<String> applyPattern(String pattern) throws Throwable {
+        try {
+            Method method = AbstractMavenReportRenderer.class.getDeclaredMethod("applyPattern", String.class);
+            method.setAccessible(true);
+            return (List<String>) method.invoke(null, pattern);
+        } catch (InvocationTargetException ite) {
+            throw ite.getTargetException();
+        }
     }
 
-    private static void checkPattern( String pattern, String[] expectedResult ) throws Throwable
-    {
-        List<String> result = applyPattern( pattern );
-        Assert.assertEquals( "result size", expectedResult.length, result.size() );
+    private static void checkPattern(String pattern, String[] expectedResult) throws Throwable {
+        List<String> result = applyPattern(pattern);
+        assertEquals(expectedResult.length, result.size(), "result size");
         int i = 0;
-        for ( Iterator<String> it = result.iterator(); it.hasNext(); )
-        {
+        for (Iterator<String> it = result.iterator(); it.hasNext(); ) {
             String name = it.next();
             String href = it.next();
-            Assert.assertEquals( expectedResult[i], name );
-            Assert.assertEquals( expectedResult[i + 1], href );
+            assertEquals(expectedResult[i], name);
+            assertEquals(expectedResult[i + 1], href);
             i += 2;
         }
     }
 
-    private static void checkPatternIllegalArgument( String cause, String pattern ) throws Throwable
-    {
-        try
-        {
-            applyPattern( pattern );
-            Assert.fail( cause + " should throw an IllegalArgumentException" );
-        }
-        catch ( IllegalArgumentException iae )
-        {
+    private static void checkPatternIllegalArgument(String cause, String pattern) throws Throwable {
+        try {
+            applyPattern(pattern);
+            fail(cause + " should throw an IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
             // ok
         }
     }
@@ -70,60 +67,62 @@ public class AbstractMavenReportRendererTest
     /**
      * @throws Throwable if any
      */
-    public void testApplyPattern() throws Throwable
-    {
+    @Test
+    public void testApplyPattern() throws Throwable {
         // the most simple test
-        checkPattern( "test {text,url}", new String[] { "test ", null, "text", "url" } );
+        checkPattern("test {text,url}", new String[] {"test ", null, "text", "url"});
 
         // check that link content is trimmed, and no problem if 2 text values are the same
-        checkPattern( "test{ text , url }test", new String[] { "test", null, "text", "url", "test", null } );
+        checkPattern("test{ text , url }test", new String[] {"test", null, "text", "url", "test", null});
 
         // check brace stacking
-        checkPattern( "test{ {text} , url }", new String[] { "test", null, "{text}", "url" } );
+        checkPattern("test{ {text} , url }", new String[] {"test", null, "{text}", "url"});
 
         // check quoting
-        checkPatternIllegalArgument( "unmatched brace", "{" );
-        checkPattern( "'{'", new String[] { "'{'", null } );
-        checkPattern( " ' { '.", new String[] { " ' { '.", null } );
+        checkPatternIllegalArgument("unmatched brace", "{");
+        checkPattern("'{'", new String[] {"'{'", null});
+        checkPattern(" ' { '.", new String[] {" ' { '.", null});
 
         // unmatched quote: the actual behavior is to ignore that they are unmatched
-        checkPattern( " '", new String[] { " '", null } );
+        checkPattern(" '", new String[] {" '", null});
         // but shouldn't it be different and throw an IllegalArgumentException?
         //    checkPatternIllegalArgument( "unmatched quote", " ' " );
         //    checkPatternIllegalArgument( "unmatched quote", " '" );
         // impact is too important to make the change for the moment
 
         // check double quoting
-        checkPattern( " ''", new String[] { " '", null } );
-        checkPattern( " '' ", new String[] { " '", null } );
-        checkPattern( " ''   ", new String[] { " '", null } );
+        checkPattern(" ''", new String[] {" '", null});
+        checkPattern(" '' ", new String[] {" '", null});
+        checkPattern(" ''   ", new String[] {" '", null});
 
         // real world cases with quote
-        checkPattern( "project''s info", new String[] { "project'", null, "s info", null } );
-        checkPattern( "it''s a question of {chance, http://en.wikipedia.org/wiki/Chance}",
-                      new String[] { "it'", null, "s a question of ", null,
-                                     "chance", "http://en.wikipedia.org/wiki/Chance" } );
-        checkPattern( "{s'inscrire,mail at mail.com}", new String[] { "s'inscrire", "mail at mail.com" } );
+        checkPattern("project''s info", new String[] {"project'", null, "s info", null});
+        checkPattern(
+                "it''s a question of {chance, http://en.wikipedia.org/wiki/Chance}",
+                new String[] {"it'", null, "s a question of ", null, "chance", "http://en.wikipedia.org/wiki/Chance"});
+        checkPattern("{s'inscrire,mail at mail.com}", new String[] {"s'inscrire", "mail at mail.com"});
 
         // throwing an IllegalArgumentException in case of unmatched quote would avoid the following:
-        checkPattern( "it's a question of {chance, http://en.wikipedia.org/wiki/Chance}",
-                      new String[] { "it's a question of {chance, http://en.wikipedia.org/wiki/Chance}", null } );
+        checkPattern(
+                "it's a question of {chance, http://en.wikipedia.org/wiki/Chance}",
+                new String[] {"it's a question of {chance, http://en.wikipedia.org/wiki/Chance}", null});
 
-        checkPattern( "{}test,", new String[] { "", null, "test,", null } );
-        checkPattern( "Hi ${name}. How is it going, sir?", new String[] { "Hi ${name}. How is it going, sir?", null } );
+        checkPattern("{}test,", new String[] {"", null, "test,", null});
+        checkPattern("Hi ${name}. How is it going, sir?", new String[] {"Hi ${name}. How is it going, sir?", null});
 
         // MSHARED-392 multiple links
-        checkPattern( "{Indiana University Extreme! Lab Software License, vesion 1.1.1,"
+        checkPattern(
+                "{Indiana University Extreme! Lab Software License, vesion 1.1.1,"
                         + "http://www.extreme.indiana.edu/viewcvs/~checkout~/XPP3/java/LICENSE.txt}"
                         + "{Public Domain,http://creativecommons.org/licenses/publicdomain}"
                         + "{Apache Software License, version 1.1,http://www.apache.org/licenses/LICENSE-1.1}",
-                                  new String[]{"Indiana University Extreme! Lab Software License, vesion 1.1.1", 
-                                      "http://www.extreme.indiana.edu/viewcvs/~checkout~/XPP3/java/LICENSE.txt",
-                                      "Public Domain",
-                                      "http://creativecommons.org/licenses/publicdomain",
-                                      "Apache Software License, version 1.1",
-                                      "http://www.apache.org/licenses/LICENSE-1.1"});
-
-        
+                new String[] {
+                    "Indiana University Extreme! Lab Software License, vesion 1.1.1",
+                    "http://www.extreme.indiana.edu/viewcvs/~checkout~/XPP3/java/LICENSE.txt",
+                    "Public Domain",
+                    "http://creativecommons.org/licenses/publicdomain",
+                    "Apache Software License, version 1.1",
+                    "http://www.apache.org/licenses/LICENSE-1.1"
+                });
     }
 }



View it on GitLab: https://salsa.debian.org/java-team/maven-reporting-impl/-/commit/ab2d2d7b3ac5f294f43086c24987001a5cc6aa0d

-- 
View it on GitLab: https://salsa.debian.org/java-team/maven-reporting-impl/-/commit/ab2d2d7b3ac5f294f43086c24987001a5cc6aa0d
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20241024/5627ca7b/attachment.htm>


More information about the pkg-java-commits mailing list