You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by fg...@apache.org on 2005/12/28 18:14:45 UTC

svn commit: r359564 - in /maven/plugins/trunk/maven-project-info-reports-plugin: ./ src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java src/main/resources/project-info-report.properties

Author: fgiust
Date: Wed Dec 28 09:14:38 2005
New Revision: 359564

URL: http://svn.apache.org/viewcvs?rev=359564&view=rev
Log:
PR: MPIR-10 Add Dependency Convergence (w/Ready for Release indicator) report.
Submitted by: Joakim Erdfelt
Reviewed by: Fabrizio Giustina

Added:
    maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java   (with props)
Modified:
    maven/plugins/trunk/maven-project-info-reports-plugin/   (props changed)
    maven/plugins/trunk/maven-project-info-reports-plugin/src/main/resources/project-info-report.properties

Propchange: maven/plugins/trunk/maven-project-info-reports-plugin/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Dec 28 09:14:38 2005
@@ -1,3 +1,4 @@
+
 release.properties
 target
 *.iml
@@ -6,3 +7,4 @@
 .wtpmodules
 .classpath
 .project
+.settings

Added: maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java?rev=359564&view=auto
==============================================================================
--- maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java (added)
+++ maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java Wed Dec 28 09:14:38 2005
@@ -0,0 +1,552 @@
+package org.apache.maven.report.projectinfo;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.reporting.AbstractMavenReport;
+import org.apache.maven.reporting.MavenReportException;
+import org.codehaus.doxia.sink.Sink;
+import org.codehaus.doxia.site.renderer.SiteRenderer;
+import org.codehaus.plexus.i18n.I18N;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * 
+ * Generates the Dependency Convergence report for reactor builds.
+ *
+ * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
+ * @goal dependency-convergence
+ * @aggregator
+ */
+public class DependencyConvergenceReport
+    extends AbstractMavenReport
+{
+
+    /**
+     * Report output directory.
+     *
+     * @parameter expression="${project.reporting.outputDirectory}"
+     * @required
+     */
+    private String outputDirectory;
+
+    /**
+     * Doxia Site Renderer.
+     *
+     * @parameter expression="${component.org.codehaus.doxia.site.renderer.SiteRenderer}"
+     * @required
+     * @readonly
+     */
+    private SiteRenderer siteRenderer;
+
+    /**
+     * The Maven Project.
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Internationalization.
+     *
+     * @component
+     */
+    private I18N i18n;
+
+    /**
+     * The projects in the current build. The effective-POM for
+     * each of these projects will written.
+     * 
+     * @parameter expression="${reactorProjects}"
+     * @required
+     * @readonly
+     */
+    private List reactorProjects;
+
+    protected SiteRenderer getSiteRenderer()
+    {
+        return siteRenderer;
+    }
+
+    protected String getOutputDirectory()
+    {
+        return outputDirectory;
+    }
+
+    protected MavenProject getProject()
+    {
+        return project;
+    }
+
+    public String getOutputName()
+    {
+        return "dependency-convergence";
+    }
+
+    public String getName( Locale locale )
+    {
+        return getI18nString( locale, "name" );
+    }
+
+    public String getDescription( Locale locale )
+    {
+        return getI18nString( locale, "description" );
+    }
+
+    /**
+     * @see org.apache.maven.reporting.MavenReport#getCategoryName()
+     */
+    public String getCategoryName()
+    {
+        return CATEGORY_PROJECT_INFORMATION;
+    }
+
+    protected void executeReport( Locale locale )
+        throws MavenReportException
+    {
+        Sink sink = getSink();
+
+        sink.head();
+        sink.title();
+        sink.text( getI18nString( locale, "title" ) );
+        sink.title_();
+        sink.head_();
+
+        sink.body();
+
+        sink.section1();
+
+        sink.sectionTitle1();
+        sink.text( getI18nString( locale, "title" ) );
+        sink.sectionTitle1_();
+
+        Map dependencyMap = getDependencyMap();
+
+        // legend
+        generateLegend( locale, sink );
+
+        // stats
+        generateStats( locale, sink, dependencyMap );
+
+        // convergence
+        generateConvergence( locale, sink, dependencyMap );
+
+        sink.section1_();
+
+        sink.body_();
+        sink.flush();
+    }
+
+    private void generateConvergence( Locale locale, Sink sink, Map dependencyMap )
+    {
+        sink.text( getI18nString( locale, "convergence.caption" ) );
+
+        Iterator it = dependencyMap.keySet().iterator();
+        while ( it.hasNext() )
+        {
+            String key = (String) it.next();
+            List depList = (List) dependencyMap.get( key );
+
+            sink.section2();
+            sink.sectionTitle2();
+            sink.text( key );
+            sink.sectionTitle2_();
+
+            generateDependencyDetails( sink, depList );
+
+            sink.section2_();
+        }
+    }
+
+    private void generateDependencyDetails( Sink sink, List depList )
+    {
+        sink.table();
+
+        Map artifactMap = getSortedUniqueArtifactMap( depList );
+
+        sink.tableRow();
+
+        sink.tableCell();
+        if ( artifactMap.size() > 1 )
+        {
+            iconError( sink );
+        }
+        else
+        {
+            iconSuccess( sink );
+        }
+        sink.tableCell_();
+
+        sink.tableCell();
+
+        sink.table();
+        Iterator it = artifactMap.keySet().iterator();
+        while ( it.hasNext() )
+        {
+            String version = (String) it.next();
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( version );
+            sink.tableCell_();
+
+            sink.tableCell();
+            generateVersionDetails( sink, artifactMap, version );
+            sink.tableCell_();
+
+            sink.tableRow_();
+        }
+        sink.table_();
+        sink.tableCell_();
+
+        sink.tableRow_();
+
+        sink.table_();
+    }
+
+    private void generateVersionDetails( Sink sink, Map artifactMap, String version )
+    {
+        sink.numberedList( 1 ); // parameter value is apparently irrelevant here.
+        List depList = (List) artifactMap.get( version );
+        Collections.sort( depList, new ProjectComparator() );
+        Iterator it = depList.iterator();
+        while ( it.hasNext() )
+        {
+            ReverseDependencyLink rdl = (ReverseDependencyLink) it.next();
+            sink.numberedListItem();
+            if ( StringUtils.isNotEmpty( rdl.project.getUrl() ) )
+            {
+                sink.link( rdl.project.getUrl() );
+            }
+            sink.text( rdl.project.getGroupId() + ":" + rdl.project.getArtifactId() );
+            if ( StringUtils.isNotEmpty( rdl.project.getUrl() ) )
+            {
+                sink.link_();
+            }
+            sink.numberedListItem_();
+        }
+        sink.numberedList_();
+    }
+
+    private Map getSortedUniqueArtifactMap( List depList )
+    {
+        Map uniqueArtifactMap = new TreeMap();
+
+        Iterator it = depList.iterator();
+        while ( it.hasNext() )
+        {
+            ReverseDependencyLink rdl = (ReverseDependencyLink) it.next();
+            String key = rdl.getDependency().getVersion();
+            List projectList = (List) uniqueArtifactMap.get( key );
+            if ( projectList == null )
+            {
+                projectList = new ArrayList();
+            }
+            projectList.add( rdl );
+            uniqueArtifactMap.put( key, projectList );
+        }
+
+        return uniqueArtifactMap;
+    }
+
+    private void generateLegend( Locale locale, Sink sink )
+    {
+        sink.table();
+        sink.tableCaption();
+        sink.text( getI18nString( locale, "legend" ) + ":" );
+        sink.tableCaption_();
+
+        sink.tableRow();
+
+        sink.tableCell();
+        iconSuccess( sink );
+        sink.tableCell_();
+        sink.tableCell();
+        sink.text( getI18nString( locale, "legend.shared" ) );
+        sink.tableCell_();
+
+        sink.tableRow_();
+
+        sink.tableRow();
+
+        sink.tableCell();
+        iconError( sink );
+        sink.tableCell_();
+        sink.tableCell();
+        sink.text( getI18nString( locale, "legend.different" ) );
+        sink.tableCell_();
+
+        sink.tableRow_();
+
+        sink.table_();
+    }
+
+    private void generateStats( Locale locale, Sink sink, Map dependencyMap )
+    {
+        int depCount = dependencyMap.size();
+        int artifactCount = 0;
+        int convergence = 0;
+        int snapshotCount = 0;
+
+        Iterator it = dependencyMap.values().iterator();
+        while ( it.hasNext() )
+        {
+            List depList = (List) it.next();
+            Map artifactMap = getSortedUniqueArtifactMap( depList );
+            snapshotCount += countSnapshots( artifactMap );
+            artifactCount += artifactMap.size();
+        }
+
+        convergence = (int) ( ( (double) depCount / (double) artifactCount ) * 100 );
+
+        sink.table();
+        sink.tableCaption();
+        sink.text( getI18nString( locale, "stats.caption" ) );
+        sink.tableCaption_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.subprojects" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+        sink.text( String.valueOf( reactorProjects.size() ) );
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.dependencies" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+        sink.text( String.valueOf( depCount ) );
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.artifacts" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+        sink.text( String.valueOf( artifactCount ) );
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.snapshots" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+        sink.text( String.valueOf( snapshotCount ) );
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.convergence" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+
+        if ( convergence < 100 )
+        {
+            iconError( sink );
+        }
+        else
+        {
+            iconSuccess( sink );
+        }
+        sink.nonBreakingSpace();
+
+        sink.bold();
+        sink.text( String.valueOf( convergence ) + "%" );
+        sink.bold_();
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.tableRow();
+        sink.tableHeaderCell();
+        sink.text( getI18nString( locale, "stats.readyrelease" ) + ":" );
+        sink.tableHeaderCell_();
+        sink.tableCell();
+        boolean readyForRelease = ( ( convergence >= 100 ) && ( snapshotCount <= 0 ) );
+        if ( readyForRelease )
+        {
+            iconSuccess( sink );
+            sink.nonBreakingSpace();
+            sink.bold();
+            sink.text( getI18nString( locale, "stats.readyrelease.success" ) );
+            sink.bold_();
+        }
+        else
+        {
+            iconError( sink );
+            sink.nonBreakingSpace();
+            sink.bold();
+            sink.text( getI18nString( locale, "stats.readyrelease.error" ) );
+            sink.bold_();
+            if ( convergence < 100 )
+            {
+                sink.lineBreak();
+                sink.text( getI18nString( locale, "stats.readyrelease.error.convergence" ) );
+            }
+            if ( snapshotCount > 0 )
+            {
+                sink.lineBreak();
+                sink.text( getI18nString( locale, "stats.readyrelease.error.snapshots" ) );
+            }
+        }
+        sink.tableCell_();
+        sink.tableRow_();
+
+        sink.table_();
+    }
+
+    private int countSnapshots( Map artifactMap )
+    {
+        int count = 0;
+        Iterator it = artifactMap.keySet().iterator();
+        while ( it.hasNext() )
+        {
+            String version = (String) it.next();
+            if ( version.endsWith( "-SNAPSHOT" ) )
+            {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private void iconSuccess( Sink sink )
+    {
+        sink.figure();
+        sink.figureCaption();
+        sink.text( "success" );
+        sink.figureCaption_();
+        sink.figureGraphics( "images/icon_success_sml.gif" );
+        sink.figure_();
+    }
+
+    private void iconError( Sink sink )
+    {
+        sink.figure();
+        sink.figureCaption();
+        sink.text( "error" );
+        sink.figureCaption_();
+        sink.figureGraphics( "images/icon_error_sml.gif" );
+        sink.figure_();
+    }
+
+    public Map getDependencyMap()
+    {
+        Iterator it = reactorProjects.iterator();
+
+        Map dependencyMap = new TreeMap();
+
+        while ( it.hasNext() )
+        {
+            MavenProject reactorProject = (MavenProject) it.next();
+
+            Iterator itdep = reactorProject.getDependencies().iterator();
+            while ( itdep.hasNext() )
+            {
+                Dependency dep = (Dependency) itdep.next();
+                String key = dep.getGroupId() + ":" + dep.getArtifactId();
+                List depList = (List) dependencyMap.get( key );
+                if ( depList == null )
+                {
+                    depList = new ArrayList();
+                }
+                depList.add( new ReverseDependencyLink( dep, reactorProject ) );
+                dependencyMap.put( key, depList );
+            }
+        }
+
+        return dependencyMap;
+    }
+
+    private String getI18nString( Locale locale, String key )
+    {
+        return i18n.getString( "project-info-report", locale, "report.dependency-convergence." + key );
+    }
+
+    class ReverseDependencyLink
+    {
+        private Dependency dependency;
+
+        protected MavenProject project;
+
+        public ReverseDependencyLink( Dependency dependency, MavenProject project )
+        {
+            this.dependency = dependency;
+            this.project = project;
+        }
+
+        public Dependency getDependency()
+        {
+            return dependency;
+        }
+
+        public MavenProject getProject()
+        {
+            return project;
+        }
+
+        public String toString()
+        {
+            return project.getId();
+        }
+    }
+
+    class ProjectComparator
+        implements Comparator
+    {
+
+        public int compare( Object o1, Object o2 )
+        {
+            if ( ( o1 instanceof ReverseDependencyLink ) && ( o2 instanceof ReverseDependencyLink ) )
+            {
+                ReverseDependencyLink p1 = (ReverseDependencyLink) o1;
+                ReverseDependencyLink p2 = (ReverseDependencyLink) o2;
+                return p1.getProject().getId().compareTo( p2.getProject().getId() );
+            }
+            else
+            {
+                return 0;
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.maven.reporting.AbstractMavenReport#canGenerateReport()
+     */
+    public boolean canGenerateReport()
+    {
+        // only generate the convergency report if we are running a reactor build
+        return reactorProjects.size() > 1;
+    }
+
+}

Propchange: maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/plugins/trunk/maven-project-info-reports-plugin/src/main/java/org/apache/maven/report/projectinfo/DependencyConvergenceReport.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: maven/plugins/trunk/maven-project-info-reports-plugin/src/main/resources/project-info-report.properties
URL: http://svn.apache.org/viewcvs/maven/plugins/trunk/maven-project-info-reports-plugin/src/main/resources/project-info-report.properties?rev=359564&r1=359563&r2=359564&view=diff
==============================================================================
--- maven/plugins/trunk/maven-project-info-reports-plugin/src/main/resources/project-info-report.properties (original)
+++ maven/plugins/trunk/maven-project-info-reports-plugin/src/main/resources/project-info-report.properties Wed Dec 28 09:14:38 2005
@@ -155,3 +155,22 @@
 report.license.title=Project License
 report.license.overview.title=Overview
 report.license.overview.intro=Typically the licenses listed for the project are that of the project itself, and not of dependencies.
+
+report.dependency-convergence.name=Dependency Convergence
+report.dependency-convergence.description=This document presents the convergence of dependency versions across the entire project, and its sub modules.
+report.dependency-convergence.title=Reactor Dependency Convergence
+report.dependency-convergence.legend=Legend
+report.dependency-convergence.legend.shared=All projects share one version of the dependency.
+report.dependency-convergence.legend.different=At least one project has a differing version of the dependency.
+report.dependency-convergence.stats.caption=Statistics
+report.dependency-convergence.stats.subprojects=Number of sub-projects
+report.dependency-convergence.stats.dependencies=Number of dependencies (NOD)
+report.dependency-convergence.stats.artifacts=Number of unique artifacts (NOA)
+report.dependency-convergence.stats.snapshots=Number of SNAPSHOT artifacts (NOS)
+report.dependency-convergence.stats.convergence=Convergence (NOD/NOA)
+report.dependency-convergence.stats.readyrelease=Ready for Release (100% Convergence and no SNAPSHOTS)
+report.dependency-convergence.stats.readyrelease.success=Success
+report.dependency-convergence.stats.readyrelease.error=Error
+report.dependency-convergence.stats.readyrelease.error.convergence=You do not have 100% convergence.
+report.dependency-convergence.stats.readyrelease.error.snapshots=You have SNAPSHOT dependencies.
+report.dependency-convergence.convergence.caption=Dependencies used in sub-projects