diff --git a/src/it/MPIR-431/pom.xml b/src/it/MPIR-431/pom.xml new file mode 100644 index 00000000..3a7b9952 --- /dev/null +++ b/src/it/MPIR-431/pom.xml @@ -0,0 +1,93 @@ + + + + + 4.0.0 + + org.apache.maven.plugins.project-info-reports.its + MPIR-431 + 1.0-SNAPSHOT + pom + http://maven.apache.org/plugins/it/${project.artifactId} + + + UTF-8 + UTF-8 + + + + + + xml-apis + xml-apis-ext + 1.3.04 + provided + + + commons-io + commons-io + 1.0 + + + commons-lang + commons-lang + 2.6 + runtime + + + org.springframework + spring-test + 5.3.0 + test + + + + + + + + org.apache.maven.plugins + maven-site-plugin + @sitePluginVersion@ + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + @project.version@ + + + + dependencies + + + + + + + + diff --git a/src/it/MPIR-431/verify.groovy b/src/it/MPIR-431/verify.groovy new file mode 100644 index 00000000..5b57a761 --- /dev/null +++ b/src/it/MPIR-431/verify.groovy @@ -0,0 +1,53 @@ +/* + * 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. + */ +String html = new File( basedir, 'target/site/dependencies.html' ).text + +def summaryLine = '''\ + +compile: 1 +compile: 45.5 kB +compile: 47 +compile: 36 +compile: 4 +1.3 +compile: 1 + +runtime: 1 +runtime: 284.2 kB +runtime: 155 +runtime: 133 +runtime: 10 +runtime: 1 + +provided: 1 +provided: 85.7 kB +provided: 209 +provided: 192 +provided: 4 +- + +test: 3 +test: 2.2 MB +test: 1619 +test: 1493 +test: 91 +1.8 +test: 3''' + +assert html.contains( summaryLine.replaceAll( "\n", System.lineSeparator() ) ) diff --git a/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java b/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java index 5da6acd8..d4c6b842 100644 --- a/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java +++ b/src/main/java/org/apache/maven/report/projectinfo/dependencies/renderer/DependenciesRenderer.java @@ -18,6 +18,8 @@ */ package org.apache.maven.report.projectinfo.dependencies.renderer; +import javax.swing.text.html.HTML.Attribute; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -56,6 +58,7 @@ import org.apache.maven.report.projectinfo.dependencies.Dependencies; import org.apache.maven.report.projectinfo.dependencies.DependenciesReportConfiguration; import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils; +import org.apache.maven.report.projectinfo.dependencies.renderer.DependenciesRenderer.TotalCell.SummaryTableRowOrder; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.shared.dependency.graph.DependencyNode; import org.apache.maven.shared.jar.JarData; @@ -70,6 +73,7 @@ * @since 2.1 */ public class DependenciesRenderer extends AbstractProjectInfoRenderer { + /** URL for the 'icon_info_sml.gif' image */ private static final String IMG_INFO_URL = "./images/icon_info_sml.gif"; @@ -93,7 +97,6 @@ public class DependenciesRenderer extends AbstractProjectInfoRenderer { private final MessageFormat javaVersionFormat = new MessageFormat("{0,choice,0#|1.1#{0,number,0.0}|9#{0,number,0}}", Locale.ROOT); - /** * @since 2.1.1 */ @@ -503,7 +506,8 @@ private void renderSectionDependencyFileDetails() { TotalCell totalentries = new TotalCell(); TotalCell totalclasses = new TotalCell(); TotalCell totalpackages = new TotalCell(); - double highestJavaVersion = 0.0; + double highestTestJavaVersion = 0.0; + double highestNonTestJavaVersion = 0.0; TotalCell totalDebugInformation = new TotalCell(); TotalCell totalsealed = new TotalCell(); @@ -551,8 +555,13 @@ private void renderSectionDependencyFileDetails() { try { if (jarDetails.getJdkRevision() != null) { - highestJavaVersion = - Math.max(highestJavaVersion, Double.parseDouble(jarDetails.getJdkRevision())); + double jdkRevision = Double.parseDouble(jarDetails.getJdkRevision()); + boolean isTestScope = Artifact.SCOPE_TEST.equalsIgnoreCase(artifact.getScope()); + if (isTestScope) { + highestTestJavaVersion = Math.max(highestTestJavaVersion, jdkRevision); + } else { + highestNonTestJavaVersion = Math.max(highestNonTestJavaVersion, jdkRevision); + } } } catch (NumberFormatException e) { // ignore @@ -607,18 +616,52 @@ private void renderSectionDependencyFileDetails() { justification[0] = Sink.JUSTIFY_RIGHT; justification[6] = Sink.JUSTIFY_RIGHT; - for (int i = -1; i < TotalCell.SCOPES_COUNT; i++) { - if (totaldeps.getTotal(i) > 0) { - tableRow(hasSealed, new String[] { - totaldeps.getTotalString(i), - totaldepsize.getTotalString(i), - totalentries.getTotalString(i), - totalclasses.getTotalString(i), - totalpackages.getTotalString(i), - (i < 0) ? javaVersionFormat.format(new Object[] {highestJavaVersion}) : "", - totalDebugInformation.getTotalString(i), - totalsealed.getTotalString(i) - }); + // calculate rowspan attr + int rowspan = computeRowspan(totaldeps); + + if (rowspan > 1) { + boolean insertRowspanAttr = false; + int column = 5; // Java Version's column + for (SummaryTableRowOrder currentRow : SummaryTableRowOrder.values()) { + if (currentRow.getTotal(totaldeps) > 0) { + int i = currentRow.ordinal(); + boolean alreadyInsertedRowspanAttr = insertRowspanAttr + && (SummaryTableRowOrder.COMPILE_SCOPE.ordinal() < i + && i <= SummaryTableRowOrder.SYSTEM_SCOPE.ordinal()); + insertRowspanAttr = (SummaryTableRowOrder.COMPILE_SCOPE.ordinal() <= i + && i <= SummaryTableRowOrder.SYSTEM_SCOPE.ordinal()); + justification[column] = (insertRowspanAttr && alreadyInsertedRowspanAttr) + ? justification[column + 1] + : Sink.JUSTIFY_CENTER; + tableRowWithRowspan( + hasSealed, insertRowspanAttr, alreadyInsertedRowspanAttr, column, rowspan, new String[] { + totaldeps.getTotalString(currentRow), + totaldepsize.getTotalString(currentRow), + totalentries.getTotalString(currentRow), + totalclasses.getTotalString(currentRow), + totalpackages.getTotalString(currentRow), + currentRow.formatMaxJavaVersionForScope( + javaVersionFormat, highestTestJavaVersion, highestNonTestJavaVersion), + totalDebugInformation.getTotalString(currentRow), + totalsealed.getTotalString(currentRow) + }); + } + } + } else { + for (SummaryTableRowOrder currentRow : SummaryTableRowOrder.values()) { + if (currentRow.getTotal(totaldeps) > 0) { + tableRow(hasSealed, new String[] { + totaldeps.getTotalString(currentRow), + totaldepsize.getTotalString(currentRow), + totalentries.getTotalString(currentRow), + totalclasses.getTotalString(currentRow), + totalpackages.getTotalString(currentRow), + currentRow.formatMaxJavaVersionForScope( + javaVersionFormat, highestTestJavaVersion, highestNonTestJavaVersion), + totalDebugInformation.getTotalString(currentRow), + totalsealed.getTotalString(currentRow) + }); + } } } @@ -626,6 +669,19 @@ private void renderSectionDependencyFileDetails() { endSection(); } + private int computeRowspan(TotalCell totaldeps) { + int rowspan = 0; + for (int i = SummaryTableRowOrder.COMPILE_SCOPE.ordinal(); + i <= SummaryTableRowOrder.SYSTEM_SCOPE.ordinal(); + i++) { + SummaryTableRowOrder currentRow = SummaryTableRowOrder.values()[i]; + if (currentRow.getTotal(totaldeps) > 0) { + rowspan++; + } + } + return rowspan; + } + // Almost as same as in the abstract class but includes the title attribute private void tableHeader(String[] content, String[] titles) { sink.tableRow(); @@ -659,6 +715,30 @@ private void tableHeaderCell(String text, String title) { sink.tableHeaderCell_(); } + private void tableRowWithRowspan( + boolean fullRow, boolean insert, boolean alreadyInserted, int contentIndex, int rowspan, String[] content) { + sink.tableRow(); + + int count = fullRow ? content.length : (content.length - 1); + + for (int i = 0; i < count; i++) { + if (i == contentIndex && insert) { + if (!alreadyInserted) { + SinkEventAttributes att = new SinkEventAttributeSet(); + att.addAttribute(Attribute.ROWSPAN, rowspan); + att.addAttribute(Attribute.STYLE, "vertical-align: middle"); + sink.tableCell(att); + text(content[i]); + sink.tableCell_(); + } + } else { + tableCell(content[i]); + } + } + + sink.tableRow_(); + } + private void tableRow(boolean fullRow, String[] content) { sink.tableRow(); @@ -1138,7 +1218,128 @@ private String getString(String key) { * Combine total and total by scope in a cell. */ static class TotalCell { - static final int SCOPES_COUNT = 5; + public enum SummaryTableRowOrder { + // Do not change the physical order of these values + TOTALS { + @Override + public void addTotal(TotalCell cell, long value) { + cell.total += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.total; + } + + @Override + protected String formatMaxJavaVersionForScope( + MessageFormat javaVersionFormat, + double highestTestJavaVersion, + double highestNonTestJavaVersion) { + double highestJavaVersion = Math.max(highestTestJavaVersion, highestNonTestJavaVersion); + return javaVersionFormat.format(new Object[] {highestJavaVersion}); + } + }, + COMPILE_SCOPE(Artifact.SCOPE_COMPILE) { + @Override + public void addTotal(TotalCell cell, long value) { + cell.totalCompileScope += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.totalCompileScope; + } + }, + RUNTIME_SCOPE(Artifact.SCOPE_RUNTIME) { + @Override + public void addTotal(TotalCell cell, long value) { + cell.totalRuntimeScope += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.totalRuntimeScope; + } + }, + PROVIDED_SCOPE(Artifact.SCOPE_PROVIDED) { + @Override + public void addTotal(TotalCell cell, long value) { + cell.totalProvidedScope += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.totalProvidedScope; + } + }, + SYSTEM_SCOPE(Artifact.SCOPE_SYSTEM) { + @Override + public void addTotal(TotalCell cell, long value) { + cell.totalSystemScope += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.totalSystemScope; + } + }, + TEST_SCOPE(Artifact.SCOPE_TEST) { + @Override + public void addTotal(TotalCell cell, long value) { + cell.totalTestScope += value; + } + + @Override + public long getTotal(TotalCell cell) { + return cell.totalTestScope; + } + + @Override + protected String formatMaxJavaVersionForScope( + MessageFormat javaVersionFormat, + double highestTestJavaVersion, + double highestNonTestJavaVersion) { + return javaVersionFormat.format(new Object[] {highestTestJavaVersion}); + } + }; + + private static final Map MAP_BY_SCOPE = new HashMap<>(); + + static { + // scope string => enum mapping + for (SummaryTableRowOrder e : SummaryTableRowOrder.values()) { + MAP_BY_SCOPE.put(e.getScope(), e); + } + } + + public static SummaryTableRowOrder fromScope(String scope) { + return MAP_BY_SCOPE.get(scope); + } + + private String scope; + + SummaryTableRowOrder() { + this(null); + } + + SummaryTableRowOrder(String scope) { + this.scope = scope; + } + + public String getScope() { + return this.scope; + } + + protected String formatMaxJavaVersionForScope( + MessageFormat javaVersionFormat, double highestTestJavaVersion, double highestNonTestJavaVersion) { + return javaVersionFormat.format(new Object[] {highestNonTestJavaVersion}); + } + + public abstract void addTotal(TotalCell cell, long value); + + public abstract long getTotal(TotalCell cell); + } DecimalFormat decimalFormat; @@ -1164,74 +1365,30 @@ void incrementTotal(String scope) { addTotal(1, scope); } - static String getScope(int index) { - switch (index) { - case 0: - return Artifact.SCOPE_COMPILE; - case 1: - return Artifact.SCOPE_TEST; - case 2: - return Artifact.SCOPE_RUNTIME; - case 3: - return Artifact.SCOPE_PROVIDED; - case 4: - return Artifact.SCOPE_SYSTEM; - default: - return null; - } - } - - long getTotal(int index) { - switch (index) { - case 0: - return totalCompileScope; - case 1: - return totalTestScope; - case 2: - return totalRuntimeScope; - case 3: - return totalProvidedScope; - case 4: - return totalSystemScope; - default: - return total; - } - } - - String getTotalString(int index) { - long totalString = getTotal(index); + String getTotalString(SummaryTableRowOrder currentRow) { + long totalString = currentRow.getTotal(this); if (totalString <= 0) { return ""; } StringBuilder sb = new StringBuilder(); - if (index >= 0) { - sb.append(getScope(index)).append(": "); + if (currentRow.compareTo(SummaryTableRowOrder.COMPILE_SCOPE) >= 0) { + sb.append(currentRow.getScope()).append(": "); } if (decimalFormat != null) { - sb.append(decimalFormat.format(getTotal(index))); + sb.append(decimalFormat.format(currentRow.getTotal(this))); } else { - sb.append(getTotal(index)); + sb.append(currentRow.getTotal(this)); } return sb.toString(); } void addTotal(long add, String scope) { - total += add; - - if (Artifact.SCOPE_COMPILE.equals(scope)) { - totalCompileScope += add; - } else if (Artifact.SCOPE_TEST.equals(scope)) { - totalTestScope += add; - } else if (Artifact.SCOPE_RUNTIME.equals(scope)) { - totalRuntimeScope += add; - } else if (Artifact.SCOPE_PROVIDED.equals(scope)) { - totalProvidedScope += add; - } else if (Artifact.SCOPE_SYSTEM.equals(scope)) { - totalSystemScope += add; - } + SummaryTableRowOrder.TOTALS.addTotal(this, add); + SummaryTableRowOrder currentRow = SummaryTableRowOrder.fromScope(scope); + currentRow.addTotal(this, add); } /** {@inheritDoc} */ @@ -1246,12 +1403,15 @@ public String toString() { sb.append(" ("); boolean needSeparator = false; - for (int i = 0; i < SCOPES_COUNT; i++) { - if (getTotal(i) > 0) { + for (int i = SummaryTableRowOrder.COMPILE_SCOPE.ordinal(); + i < SummaryTableRowOrder.TEST_SCOPE.ordinal(); + i++) { + SummaryTableRowOrder currentRow = SummaryTableRowOrder.values()[i]; + if (currentRow.getTotal(this) > 0) { if (needSeparator) { sb.append(", "); } - sb.append(getTotalString(i)); + sb.append(getTotalString(currentRow)); needSeparator = true; } }