diff --git a/src/it/it-parent-updates-report-001/invoker.properties b/src/it/it-parent-updates-report-001/invoker.properties
new file mode 100644
index 0000000000..c01f7db0e4
--- /dev/null
+++ b/src/it/it-parent-updates-report-001/invoker.properties
@@ -0,0 +1 @@
+invoker.goals=site
diff --git a/src/it/it-parent-updates-report-001/module/pom.xml b/src/it/it-parent-updates-report-001/module/pom.xml
new file mode 100644
index 0000000000..80c8c58638
--- /dev/null
+++ b/src/it/it-parent-updates-report-001/module/pom.xml
@@ -0,0 +1,64 @@
+
+ 4.0.0
+
+
+ localhost
+ dummy-parent3
+ 1.0.0
+
+
+ module
+ 1.0.0
+
+
+
+
+
+ maven-clean-plugin
+ 2.2
+
+
+ maven-deploy-plugin
+ 2.3
+
+
+ maven-install-plugin
+ 2.2
+
+
+ maven-site-plugin
+ @sitePluginVersion@
+
+
+ maven-project-info-reports-plugin
+ 2.1
+
+
+
+
+
+
+
+
+ maven-project-info-reports-plugin
+ 2.1
+
+
+
+
+
+ @project.groupId@
+ @project.artifactId@
+ @project.version@
+
+
+
+ parent-updates-report
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/it/it-parent-updates-report-001/pom.xml b/src/it/it-parent-updates-report-001/pom.xml
new file mode 100644
index 0000000000..ef9bad54d2
--- /dev/null
+++ b/src/it/it-parent-updates-report-001/pom.xml
@@ -0,0 +1,70 @@
+
+ 4.0.0
+
+
+ localhost
+ dummy-parent2
+ 1.0
+
+
+ it-parent-updates-report-001
+ 1.0.0
+ pom
+
+
+ module
+
+
+
+
+
+
+ maven-clean-plugin
+ 2.2
+
+
+ maven-deploy-plugin
+ 2.3
+
+
+ maven-install-plugin
+ 2.2
+
+
+ maven-site-plugin
+ @sitePluginVersion@
+
+
+ maven-project-info-reports-plugin
+ 2.1
+
+
+
+
+
+
+
+
+ maven-project-info-reports-plugin
+ 2.1
+
+
+
+
+
+ @project.groupId@
+ @project.artifactId@
+ @project.version@
+
+
+
+ parent-updates-report
+
+
+
+
+
+
+
+
diff --git a/src/it/it-parent-updates-report-001/src/site/site.xml b/src/it/it-parent-updates-report-001/src/site/site.xml
new file mode 100644
index 0000000000..e955148484
--- /dev/null
+++ b/src/it/it-parent-updates-report-001/src/site/site.xml
@@ -0,0 +1,7 @@
+
+
+ org.apache.maven.skins
+ maven-default-skin
+ 1.0
+
+
diff --git a/src/it/it-parent-updates-report-001/verify.groovy b/src/it/it-parent-updates-report-001/verify.groovy
new file mode 100644
index 0000000000..130ccd01f0
--- /dev/null
+++ b/src/it/it-parent-updates-report-001/verify.groovy
@@ -0,0 +1,13 @@
+report = new File( basedir, "target/site/parent-updates-report.html" ).text
+ .replaceAll( "<[^>]+>", " " )
+ .replaceAll( "&[^;]+;", " " )
+ .replaceAll( "\\s+", " " )
+
+assert report =~ /dummy-parent2 +1.0 +pom +3.1/
+
+report = new File( basedir, "module/target/site/parent-updates-report.html" ).text
+ .replaceAll( "<[^>]+>", " " )
+ .replaceAll( "&[^;]+;", " " )
+ .replaceAll( "\\s+", " " )
+
+assert report =~ /dummy-parent3 +1.0.0 +pom/
\ No newline at end of file
diff --git a/src/main/java/org/codehaus/mojo/versions/DependencyUpdatesRenderer.java b/src/main/java/org/codehaus/mojo/versions/DependencyUpdatesRenderer.java
index 647b865873..d1d6b807af 100644
--- a/src/main/java/org/codehaus/mojo/versions/DependencyUpdatesRenderer.java
+++ b/src/main/java/org/codehaus/mojo/versions/DependencyUpdatesRenderer.java
@@ -72,10 +72,9 @@ protected void renderBody()
renderSummaryTotalsTable( allUpdates );
- renderSummaryTable( "report.overview.dependencyManagement", dependencyManagementUpdates,
- "report.overview.noDependencyManagement" );
+ renderDependencyManagementSummary();
- renderSummaryTable( "report.overview.dependency", dependencyUpdates, "report.overview.noDependency" );
+ renderDependencySummary();
sink.section1_();
@@ -94,7 +93,18 @@ protected void renderBody()
sink.section1_();
}
- private void renderSummaryTable( String titleKey, Map contents, String emptyKey )
+ protected void renderDependencySummary()
+ {
+ renderSummaryTable( "report.overview.dependency", dependencyUpdates, "report.overview.noDependency" );
+ }
+
+ protected void renderDependencyManagementSummary()
+ {
+ renderSummaryTable( "report.overview.dependencyManagement", dependencyManagementUpdates,
+ "report.overview.noDependencyManagement" );
+ }
+
+ protected void renderSummaryTable( String titleKey, Map contents, String emptyKey )
{
sink.section2();
sink.sectionTitle2();
@@ -114,7 +124,7 @@ private void renderSummaryTable( String titleKey, Map allUpdates )
+ protected void renderSummaryTotalsTable( Map allUpdates )
{
int numInc = 0;
int numMin = 0;
@@ -203,7 +213,7 @@ else if ( details.getOldestUpdate( of( MAJOR ) ) != null )
sink.table_();
}
- private void renderDependencyDetail( Dependency dependency, ArtifactVersions details )
+ protected void renderDependencyDetail( Dependency dependency, ArtifactVersions details )
{
sink.section2();
sink.sectionTitle2();
diff --git a/src/main/java/org/codehaus/mojo/versions/ParentUpdatesReport.java b/src/main/java/org/codehaus/mojo/versions/ParentUpdatesReport.java
new file mode 100644
index 0000000000..cbc99740f3
--- /dev/null
+++ b/src/main/java/org/codehaus/mojo/versions/ParentUpdatesReport.java
@@ -0,0 +1,145 @@
+package org.codehaus.mojo.versions;
+
+/*
+ * 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.
+ */
+
+import javax.inject.Inject;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.MavenReportException;
+import org.apache.maven.repository.RepositorySystem;
+import org.codehaus.mojo.versions.api.ArtifactVersions;
+import org.codehaus.mojo.versions.utils.DependencyBuilder;
+import org.codehaus.plexus.i18n.I18N;
+
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+
+/**
+ * Generates a report on available updates for parent artifacts
+ *
+ * @author Andrzej Jarmoniuk
+ * @since 2.13.0
+ */
+@Mojo( name = "parent-updates-report",
+ requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = false )
+public class ParentUpdatesReport extends AbstractVersionsReport
+{
+ @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
+ protected List reactorProjects;
+
+ @Inject
+ protected ParentUpdatesReport( I18N i18n, RepositorySystem repositorySystem, ArtifactResolver artifactResolver,
+ ArtifactMetadataSource artifactMetadataSource, WagonManager wagonManager )
+ {
+ super( i18n, repositorySystem, artifactResolver, artifactMetadataSource, wagonManager );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isExternalReport()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canGenerateReport()
+ {
+ if ( getProject().getParent() == null )
+ {
+ getLog().warn( "Project does not have a parent." );
+ return false;
+ }
+
+ if ( reactorProjects.contains( getProject().getParent() ) )
+ {
+ getLog().warn( "Parent project is part of the reactor." );
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * generates an empty report in case there are no sources to generate a report with
+ *
+ * @param locale the locale to generate the report for.
+ * @param sink the report formatting tool
+ */
+ @SuppressWarnings( "deprecation" )
+ protected void doGenerateReport( Locale locale, Sink sink ) throws MavenReportException
+ {
+ try
+ {
+ ArtifactVersions artifactVersions = getHelper().lookupArtifactVersions( project.getParentArtifact(),
+ false );
+ artifactVersions.setIncludeSnapshots( allowSnapshots );
+ Dependency parent = DependencyBuilder.newBuilder()
+ .withGroupId( artifactVersions.getGroupId() )
+ .withArtifactId( artifactVersions.getArtifactId() )
+ .withVersion( artifactVersions.getArtifact().getVersion() )
+ .withScope( artifactVersions.getArtifact().getScope() )
+ .withType( artifactVersions.getArtifact().getType() )
+ .withClassifier( artifactVersions.getArtifact().getClassifier() )
+ .build();
+ new DependencyUpdatesRenderer( sink, getI18n(), getOutputName(), locale,
+ singletonMap( parent, artifactVersions ), emptyMap() )
+ {
+ @Override
+ protected void renderSummaryTotalsTable( Map allUpdates )
+ {
+ }
+
+ @Override
+ protected void renderDependencyManagementSummary()
+ {
+ }
+ }
+ .renderBody();
+ }
+ catch ( ArtifactMetadataRetrievalException e )
+ {
+ throw new MavenReportException( e.getMessage(), e );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getOutputName()
+ {
+ return "parent-updates-report";
+ }
+}
diff --git a/src/main/resources/parent-updates-report.properties b/src/main/resources/parent-updates-report.properties
new file mode 100644
index 0000000000..632d111778
--- /dev/null
+++ b/src/main/resources/parent-updates-report.properties
@@ -0,0 +1,58 @@
+# 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.
+
+report.title=Parent Updates Report
+report.description=Provides information on parent artifact updates
+report.overview.title=Overview
+report.overview.text=This report summarizes newer versions that may be available for your project's parent artifacts
+report.overview.dependency=Parent artifact
+report.overview.noDependency=This project does not declare a parent artifact
+report.overview.numUpToDate=# of parent artifacts using the latest version available
+report.overview.numNewerMajorAvailable=# of parent artifacts where the next version available is a major version update
+report.overview.numNewerMinorAvailable=# of parent artifacts where the next version available is a minor version update
+report.overview.numNewerIncrementalAvailable=# of parent artifacts where the next version available is an incremental \
+ version update
+report.overview.numNewerVersionAvailable=# of parent artifacts where the next version available is smaller than an \
+ incremental version update
+report.overview.property=Summary of parent artifacts associated with artifact versions
+report.overview.noProperty=No properties associated with artifacts have been defined.
+report.detail.title=Parent Update
+report.detail.text=
+report.status=Status
+report.groupId=Group Id
+report.artifactId=Artifact Id
+report.currentVersion=Current Version
+report.scope=Scope
+report.classifier=Classifier
+report.type=Type
+report.nextVersion=Next Version
+report.latestSubIncremental=Latest Subincremental
+report.nextIncremental=Next Incremental
+report.latestIncremental=Latest Incremental
+report.nextMinor=Next Minor
+report.latestMinor=Latest Minor
+report.nextMajor=Next Major
+report.latestMajor=Latest Major
+report.updateVersions=Newer versions
+report.noUpdatesAvailable=No newer versions available.
+report.otherUpdatesAvailable=There is at least one newer version available.
+report.incrementalUpdatesAvailable=There is at least one newer incremental version available. \
+ Incremental updates are typically passive.
+report.minorUpdatesAvailable=There is at least one newer minor version available. \
+ Minor updates are sometimes passive.
+report.majorUpdatesAvailable=There is at least one newer major version available. \
+ Major updates are rarely passive.
diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt
index 66d643fe39..e95618a672 100644
--- a/src/site/apt/index.apt
+++ b/src/site/apt/index.apt
@@ -116,6 +116,9 @@ Versions Maven Plugin
* {{{./property-updates-report-mojo.html}versions:property-updates-report}} produces a report of
those properties which are used to control artifact versions and which properties have newer versions available.
+ * {{{./parent-updates-report-mojo.html}versions:parent-updates-report}} produces a report on possible parent artifact
+ upgrades.
+
* Usage
General instructions on how to use the Versions Plugin can be found on the {{{./usage.html}usage page}}. Some more
diff --git a/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportTest.java b/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportTest.java
index ed0b789267..12c149f223 100644
--- a/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportTest.java
+++ b/src/test/java/org/codehaus/mojo/versions/DependencyUpdatesReportTest.java
@@ -27,7 +27,6 @@
import java.util.Locale;
import java.util.Set;
-import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.doxia.module.xhtml5.Xhtml5SinkFactory;
import org.apache.maven.doxia.sink.SinkFactory;
import org.apache.maven.model.Dependency;
@@ -35,9 +34,8 @@
import org.apache.maven.model.Model;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReportException;
-import org.apache.maven.repository.RepositorySystem;
-import org.codehaus.mojo.versions.utils.DependencyBuilder;
import org.codehaus.mojo.versions.model.RuleSet;
+import org.codehaus.mojo.versions.utils.DependencyBuilder;
import org.codehaus.mojo.versions.utils.MockUtils;
import org.junit.Test;
@@ -49,9 +47,6 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
/**
* Basic tests for {@linkplain DependencyUpdatesReport}.
@@ -65,7 +60,7 @@ private static class TestDependencyUpdatesReport extends DependencyUpdatesReport
@SuppressWarnings( "deprecation" )
TestDependencyUpdatesReport()
{
- super( mockI18N(), mockRepositorySystem(), null, mockArtifactMetadataSource(), null );
+ super( mockI18N(), MockUtils.mockRepositorySystem(), null, mockArtifactMetadataSource(), null );
siteTool = MockUtils.mockSiteTool();
project = new MavenProject();
@@ -133,20 +128,6 @@ public TestDependencyUpdatesReport withIgnoredVersions(
this.ignoredVersions = ignoredVersions;
return this;
}
-
- private static RepositorySystem mockRepositorySystem()
- {
- RepositorySystem repositorySystem = mock( RepositorySystem.class );
- when( repositorySystem.createDependencyArtifact( any( Dependency.class ) ) ).thenAnswer(
- invocation ->
- {
- Dependency dependency = invocation.getArgument( 0 );
- return new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(),
- dependency.getVersion(), dependency.getScope(), dependency.getType(),
- dependency.getClassifier(), null );
- } );
- return repositorySystem;
- }
}
private static Dependency dependencyOf( String artifactId )
diff --git a/src/test/java/org/codehaus/mojo/versions/ParentUpdatesReportTest.java b/src/test/java/org/codehaus/mojo/versions/ParentUpdatesReportTest.java
new file mode 100644
index 0000000000..95c81c19be
--- /dev/null
+++ b/src/test/java/org/codehaus/mojo/versions/ParentUpdatesReportTest.java
@@ -0,0 +1,87 @@
+package org.codehaus.mojo.versions;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.doxia.module.xhtml5.Xhtml5SinkFactory;
+import org.apache.maven.doxia.sink.SinkFactory;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.MavenReportException;
+import org.junit.Test;
+
+import static org.codehaus.mojo.versions.utils.MockUtils.mockArtifactMetadataSource;
+import static org.codehaus.mojo.versions.utils.MockUtils.mockI18N;
+import static org.codehaus.mojo.versions.utils.MockUtils.mockRepositorySystem;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
+
+/**
+ * Basic tests for {@linkplain ParentUpdatesReport}.
+ *
+ * @author Andrzej Jarmoniuk
+ */
+public class ParentUpdatesReportTest
+{
+ @Test
+ public void testAllowSnapshots() throws IOException, MavenReportException
+ {
+ OutputStream os = new ByteArrayOutputStream();
+ SinkFactory sinkFactory = new Xhtml5SinkFactory();
+ new ParentUpdatesReport( mockI18N(), mockRepositorySystem(), null,
+ mockArtifactMetadataSource( new HashMap()
+ {{
+ put( "default-artifact", new String[] {"1.0.0", "1.0.1", "1.1.0", "2.0.0", "2.0.1-SNAPSHOT"} );
+ }} ), null )
+ {{
+ allowSnapshots = true;
+ project = new MavenProject( new Model()
+ {{
+ setGroupId( "default-group" );
+ setArtifactId( "child-artifact" );
+ setVersion( "1.0.0" );
+ }} );
+ project.setParent( new MavenProject( new Model()
+ {{
+ setGroupId( "default-group" );
+ setArtifactId( "default-artifact" );
+ setVersion( "1.0.0" );
+ }} ) );
+ reactorProjects = new ArrayList<>();
+ project.setParentArtifact( new DefaultArtifact( project.getParent().getGroupId(),
+ project.getParent().getArtifactId(), project.getParent().getVersion(),
+ Artifact.SCOPE_COMPILE, "pom", "default", null ) );
+ }}.generate( sinkFactory.createSink( os ), sinkFactory, Locale.getDefault() );
+
+ String output = os.toString();
+ assertThat( output, allOf( containsString( "1.0.0" ),
+ containsString( "1.0.1" ), containsString( "1.1.0" ),
+ containsString( "2.0.0" ), containsString( "2.0.1-SNAPSHOT" ) ) );
+ }
+}
diff --git a/src/test/java/org/codehaus/mojo/versions/utils/MockUtils.java b/src/test/java/org/codehaus/mojo/versions/utils/MockUtils.java
index 71e885f889..efc108dd25 100644
--- a/src/test/java/org/codehaus/mojo/versions/utils/MockUtils.java
+++ b/src/test/java/org/codehaus/mojo/versions/utils/MockUtils.java
@@ -25,11 +25,14 @@
import java.util.Map;
import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.doxia.tools.SiteTool;
import org.apache.maven.doxia.tools.SiteToolException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.i18n.I18N;
import static org.mockito.ArgumentMatchers.any;
@@ -111,4 +114,18 @@ public static SiteTool mockSiteTool()
}
return siteTool;
}
+
+ public static RepositorySystem mockRepositorySystem()
+ {
+ RepositorySystem repositorySystem = mock( RepositorySystem.class );
+ when( repositorySystem.createDependencyArtifact( any( Dependency.class ) ) ).thenAnswer(
+ invocation ->
+ {
+ Dependency dependency = invocation.getArgument( 0 );
+ return new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(),
+ dependency.getVersion(), dependency.getScope(), dependency.getType(),
+ dependency.getClassifier(), null );
+ } );
+ return repositorySystem;
+ }
}