diff --git a/plugins/reporters/static-html/src/funTest/assets/static-html-reporter-test-expected-output.html b/plugins/reporters/static-html/src/funTest/assets/static-html-reporter-test-expected-output.html
index 8de1dad1f4c4c..c294869c8a9bb 100644
--- a/plugins/reporters/static-html/src/funTest/assets/static-html-reporter-test-expected-output.html
+++ b/plugins/reporters/static-html/src/funTest/assets/static-html-reporter-test-expected-output.html
@@ -152,57 +152,70 @@
border-right: 1px solid rgba(34, 36, 38, .15);
}
-.report-table li.resolved {
- color: #2c662d;
-}
-
.report-table details {
overflow: scroll;
}
-.report-table tr.error {
+.report-table tr.error td {
background: #fff6f6;
color: #9f3a38;
}
-.report-table tr.warning {
+.report-table tr.warning td {
background: #fffaf3;
color: #573a08;
}
-.report-table tr.hint {
+.report-table tr.hint td {
background: #f7f5ff;
color: #1c0859;
}
/**
- * Rule violation table, which specializes .report-table.
+ * Project section.
*/
-.report-rule-violation-table tr.resolved {
- background: #fcfff5;
- color: #2c662d;
+.project.excluded {
+ h3, .report-key-value-table, .report-project-table > thead th {
+ filter: opacity(50%);
+ }
}
-/**
- * Project table, which specializes .report-table.
- */
+.report-project-table .pkg.excluded {
+ > td:nth-child(1), td:nth-child(2), td:nth-child(3), td:nth-child(4) {
+ filter: opacity(50%);
+ }
+}
-.report-project-table tr.error {
- color: black;
+.report-project-table .pkg:not(.excluded) {
+ .scope.excluded, .detected-license.excluded {
+ filter: opacity(50%);
+ }
}
-.report-project-table tr.error td:nth-child(5),
-.report-project-table tr.error td:nth-child(6) {
- color: #9f3a38;
+.report-project-table td:has(.package-issue-table) {
+ padding: 0px;
}
-/*
- * Excluded state.
- */
+.package-issue-table {
+ border-spacing: 10px;
+ padding: 0px;
+ margin: 0px;
+}
-.excluded {
- filter: opacity(50%);
+.package-issue-table td {
+ border-radius: .60rem !important;
+ border-bottom: 1px solid rgba(34, 36, 38, .15);
+}
+
+.package-issue-table tr.resolved td {
+ background: #fcfff5;
+ color: #2c662d;
+}
+
+.package-issue-table tr.excluded td {
+ background: #f9fafb;
+ color: rgba(34, 36, 38, .7);
}
.reason {
@@ -213,18 +226,6 @@
display: inline;
}
-table.excluded tr.excluded {
- filter: opacity(100%);
-}
-
-table tr.excluded td li.excluded {
- filter: opacity(100%);
-}
-
-table.excluded tr.excluded td li.excluded {
- filter: opacity(100%);
-}
-
/**
* Report table media specific styling.
*/
@@ -832,398 +833,410 @@
Advisor Issue Summary (1 errors, 1 warnings, 1 hi
-
- Project is Excluded
-
The project is excluded for the following reason(s):
-
-
EXAMPLE_OF - The project is an example.
-
- VCS Information
-
-
-
- Type |
- Git |
-
-
- URL |
- https://example.com/git |
-
-
- Path |
- project |
-
-
- Revision |
- master |
-
-
-
- Packages
-
-
-
- # |
- Package |
- Scopes |
- Licenses |
- Analyzer Issues |
- Scanner Issues |
-
-
-
-
- 1 |
- Gradle:org.ossreviewtoolkit:nested-fake-project:1.0.0 |
- |
- Declared Licenses:
- -
-
-
-
- Detected Licenses (from VCS):
- -
-
-
MIT (Excluded: EXAMPLE_OF - These are example files.)
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- -
-
2024-04-22T10:36:10.661544294Z [ERROR]: FakeScanner - ERROR: Timeout after 300 seconds
- while scanning file 'project/file-within-excluded-project.dat'.
-
- -
-
2024-04-25T07:44:20.725613974Z [HINT]: FakeScanner - Example hint.
-
- -
-
2024-04-25T07:44:20.725613974Z [WARNING]: FakeScanner - Example warning.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: FakeScanner - Example error.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: FakeScanner - Example error, resolved.
-
- Resolved by: CANT_FIX_ISSUE - Resolved for illustration.
-
-
- |
-
-
-
-
- VCS Information
-
-
-
- Type |
- Git |
-
-
- URL |
- https://github.com/oss-review-toolkit/ort.git |
-
-
- Path |
- analyzer/src/funTest/assets/projects/synthetic/gradle/lib |
-
-
- Revision |
- master |
-
-
-
- Packages
-
-
-
- # |
- Package |
- Scopes |
- Licenses |
- Analyzer Issues |
- Scanner Issues |
-
-
-
-
- 1 |
- Gradle:org.ossreviewtoolkit.gradle.example:lib:1.0.0 |
- |
- Detected Licenses (from VCS):
- -
-
-
-
LicenseRef-test-Apache-2.0-multi-line ( link to the location)
- LicenseRef-test-Apache-2.0-single-line (exemplary link to the first of 2 locations)
-
-
- Effective License:
- -
-
-
-
- |
-
-
- -
-
2024-04-25T07:44:20.725613974Z [HINT]: Gradle - Example hint.
-
- -
-
2024-04-25T07:44:20.725613974Z [WARNING]: Gradle - Example warning.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: Gradle - Example error.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: Gradle - Example error, resolved.
-
- Resolved by: CANT_FIX_ISSUE - Resolved for illustration.
-
-
- |
-
-
- -
-
Unknown time [ERROR]: Dummy - DownloadException: No source artifact URL provided for
- 'Gradle:org.ossreviewtoolkit.gradle.example:lib:1.0.0'. Caused by: DownloadException: No VCS URL provided for 'Gradle:org.ossreviewtoolkit.gradle.example:lib:1.0.0'.
- Please make sure the published POM file includes the SCM connection, see: https://docs.gradle.org/current/userguide/publishing_maven.html#sec:modifying_the_generated_pom
-
- -
-
2024-04-22T10:36:10.661544294Z [ERROR]: FakeScanner - ERROR: Timeout after 300 seconds
- while scanning file 'analyzer/src/funTest/assets/projects/synthetic/gradle/lib/included-file.dat'.
-
- -
-
2024-04-25T07:44:20.725613974Z [HINT]: FakeScanner - Example hint.
-
- -
-
2024-04-25T07:44:20.725613974Z [WARNING]: FakeScanner - Example warning.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: FakeScanner - Example error.
-
- -
-
2024-04-25T07:44:20.725613974Z [ERROR]: FakeScanner - Example error, resolved.
-
- Resolved by: CANT_FIX_ISSUE - Resolved for illustration.
-
-
- |
-
-
- 2 |
- Ant:junit:junit:4.12 |
-
-
- |
- Declared Licenses:
- -
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
- 3 |
- Maven:com.foobar:foobar:1.0 |
-
-
- |
- Concluded License:
- -
-
-
- Declared Licenses:
- -
-
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
- 4 |
- Maven:com.h2database:h2:1.4.200 |
-
-
- |
- Concluded License:
- -
-
-
- Declared Licenses:
- -
-
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
- 5 |
- Maven:org.apache.commons:commons-lang3:3.5 |
-
-
- |
- Declared Licenses:
- -
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
- 6 |
- Maven:org.apache.commons:commons-text:1.1 |
-
-
- |
- Declared Licenses:
- -
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
- 7 |
- Maven:org.example.test:component:1.11 |
-
-
- |
- |
-
-
- |
-
-
- |
-
-
- 8 |
- Maven:org.hamcrest:hamcrest-core:1.3 |
-
-
- |
- Declared Licenses:
- -
-
-
- Effective License:
- -
-
-
-
- |
-
-
- |
-
-
- |
-
-
-
+
+
Repository Configuration
---
diff --git a/plugins/reporters/static-html/src/main/kotlin/StaticHtmlReporter.kt b/plugins/reporters/static-html/src/main/kotlin/StaticHtmlReporter.kt
index 53351541dee16..5cc112b45a88d 100644
--- a/plugins/reporters/static-html/src/main/kotlin/StaticHtmlReporter.kt
+++ b/plugins/reporters/static-html/src/main/kotlin/StaticHtmlReporter.kt
@@ -389,83 +389,79 @@ class StaticHtmlReporter : Reporter {
private fun DIV.projectTable(table: ProjectTable) {
val excludedClass = "excluded".takeIf { table.isExcluded() }.orEmpty()
- h2 {
+ div("project $excludedClass") {
id = table.id.toCoordinates()
- +"${table.id.toCoordinates()} (${table.fullDefinitionFilePath})"
- }
- if (table.isExcluded()) {
- h3 { +"Project is Excluded" }
- p { +"The project is excluded for the following reason(s):" }
- }
+ h2 {
+ +"${table.id.toCoordinates()} (${table.fullDefinitionFilePath})"
+ }
- table.pathExcludes.forEach { exclude ->
- p {
- div("reason") { +exclude.description }
+ if (table.isExcluded()) {
+ h3 { +"Project is Excluded" }
+ p { +"The project is excluded for the following reason(s):" }
}
- }
- table.vcs.let { vcsInfo ->
- h3(excludedClass) { +"VCS Information" }
+ table.pathExcludes.forEach { exclude ->
+ p {
+ div("reason") { +exclude.description }
+ }
+ }
- table("report-key-value-table $excludedClass") {
- tbody {
- tr {
- td { +"Type" }
- td { +vcsInfo.type.toString() }
- }
- tr {
- td { +"URL" }
- td { +vcsInfo.url }
- }
- tr {
- td { +"Path" }
- td { +vcsInfo.path }
- }
- tr {
- td { +"Revision" }
- td { +vcsInfo.revision }
+ table.vcs.let { vcsInfo ->
+ h3 { +"VCS Information" }
+
+ table("report-key-value-table $excludedClass") {
+ tbody {
+ tr {
+ td { +"Type" }
+ td { +vcsInfo.type.toString() }
+ }
+ tr {
+ td { +"URL" }
+ td { +vcsInfo.url }
+ }
+ tr {
+ td { +"Path" }
+ td { +vcsInfo.path }
+ }
+ tr {
+ td { +"Revision" }
+ td { +vcsInfo.revision }
+ }
}
}
}
- }
- h3(excludedClass) { +"Packages" }
+ h3 { +"Packages" }
- table("report-table report-project-table $excludedClass") {
- thead {
- tr {
- th { +"#" }
- th { +"Package" }
- th { +"Scopes" }
- th { +"Licenses" }
- th { +"Analyzer Issues" }
- th { +"Scanner Issues" }
+ table("report-table report-project-table $excludedClass") {
+ thead {
+ tr(excludedClass) {
+ th { +"#" }
+ th { +"Package" }
+ th { +"Scopes" }
+ th { +"Licenses" }
+ th { +"Open Issues" }
+ th { +"Excluded & Resolved Issues" }
+ }
}
- }
- tbody {
- repeat(table.rows.size) { index ->
- projectRow(table, index)
+ tbody {
+ repeat(table.rows.size) { index ->
+ projectRow(table, index)
+ }
}
}
}
}
private fun TBODY.projectRow(projectTable: ProjectTable, rowIndex: Int) {
- val row = projectTable.rows[rowIndex]
- val rowId = "${projectTable.id.toCoordinates()}-pkg-${rowIndex + 1}"
-
// Only mark the row as excluded if all scopes the dependency appears in are excluded.
- val rowExcludedClass = "excluded".takeIf { row.isExcluded() }.orEmpty()
-
- val cssClass = when {
- row.analyzerIssues.containsUnresolved() || row.scanIssues.containsUnresolved() -> "error"
- row.declaredLicenses.isEmpty() && row.detectedLicenses.isEmpty() -> "warning"
- else -> "success"
- }
+ val rowId = "${projectTable.id.toCoordinates()}-pkg-${rowIndex + 1}"
+ val row = projectTable.rows[rowIndex]
+ val rowExcludedClass = "excluded".takeIf { projectTable.isExcluded() || row.isExcluded() }.orEmpty()
- tr("$cssClass $rowExcludedClass") {
+ tr("pkg $rowExcludedClass") {
id = rowId
td {
a {
@@ -479,8 +475,8 @@ class StaticHtmlReporter : Reporter {
if (row.scopes.isNotEmpty()) {
ul {
row.scopes.forEach { scope ->
- val excludedClass = "excluded".takeIf { scope.isExcluded() }.orEmpty()
- li(excludedClass) {
+ val scopeExcludedClass = "excluded".takeIf { scope.isExcluded() }.orEmpty()
+ li("scope $scopeExcludedClass") {
+scope.name
if (scope.excludes.isNotEmpty()) {
+" "
@@ -528,7 +524,7 @@ class StaticHtmlReporter : Reporter {
}
if (!license.isDetectedExcluded) {
- div {
+ div("detected-license") {
licensesLink(license.license)
if (permalink != null) {
val count = license.locations.count { it.matchingPathExcludes.isEmpty() }
@@ -536,7 +532,7 @@ class StaticHtmlReporter : Reporter {
}
}
} else {
- div("excluded") {
+ div("detected-license excluded") {
+"${license.license} (Excluded: "
+pathExcludes.joinToString { it.description }
+")"
@@ -556,21 +552,39 @@ class StaticHtmlReporter : Reporter {
}
}
- td { issueList(row.analyzerIssues) }
+ td {
+ if (row.openIssues.isNotEmpty()) {
+ issueList(row.openIssues)
+ }
+ }
- td { issueList(row.scanIssues) }
+ td {
+ if (row.excludedOrResolvedIssues.isNotEmpty()) {
+ issueList(row.excludedOrResolvedIssues)
+ }
+ }
}
}
private fun TD.issueList(issues: List) {
- ul {
+ table("report-table package-issue-table") {
issues.forEach {
- li {
- p { issueDescription(it) }
+ val cssClass = when {
+ it.isResolved -> "resolved"
+ it.isExcluded -> "excluded"
+ it.severity == Severity.ERROR -> "error"
+ it.severity == Severity.WARNING -> "warning"
+ it.severity == Severity.HINT -> "hint"
+ else -> null
+ }
- if (it.isResolved) {
- classes = setOf("resolved")
- p { +it.resolutionDescription }
+ tr(cssClass) {
+ td {
+ p { issueDescription(it) }
+
+ if (it.isResolved) {
+ p { +it.resolutionDescription }
+ }
}
}
}
@@ -716,5 +730,3 @@ private fun IssueTable.title(): String =
private fun IssueTable.id(): String = "${type.name.lowercase()}-issue-summary"
private fun IssueTable.rowId(index: Int): String = "${id()}-$index"
-
-private fun Collection.containsUnresolved() = any { !it.isResolved }
diff --git a/plugins/reporters/static-html/src/main/kotlin/TablesReport.kt b/plugins/reporters/static-html/src/main/kotlin/TablesReport.kt
index 731aa6cfe1ba3..7724bbdca1645 100644
--- a/plugins/reporters/static-html/src/main/kotlin/TablesReport.kt
+++ b/plugins/reporters/static-html/src/main/kotlin/TablesReport.kt
@@ -176,12 +176,12 @@ internal data class ProjectTable(
/**
* All analyzer issues related to this package.
*/
- val analyzerIssues: List,
+ val openIssues: List,
/**
- * All scan issues related to this package.
+ * All issues which are either resolved or excluded or both.
*/
- val scanIssues: List
+ val excludedOrResolvedIssues: List
) {
/**
* Return true if and only if this [Row] is excluded by any [ScopeExclude]s
@@ -211,6 +211,7 @@ internal data class TablesReportIssue(
val source: String,
val description: String,
val resolutionDescription: String,
+ val isExcluded: Boolean,
val isResolved: Boolean,
val severity: Severity,
val howToFix: String
diff --git a/plugins/reporters/static-html/src/main/kotlin/TablesReportModelMapper.kt b/plugins/reporters/static-html/src/main/kotlin/TablesReportModelMapper.kt
index 5400498a7635e..24580e36dee1d 100644
--- a/plugins/reporters/static-html/src/main/kotlin/TablesReportModelMapper.kt
+++ b/plugins/reporters/static-html/src/main/kotlin/TablesReportModelMapper.kt
@@ -84,7 +84,8 @@ private fun OrtResult.getScopesForDependencies(project: Project): Map
+ val isRowExcluded = input.ortResult.isExcluded(id) ||
+ (id != project.id && scopesForId[id].orEmpty().all { it.value.isNotEmpty() })
+
+ issue.toTableReportIssue(
+ input.ortResult,
+ input.howToFixTextProvider,
+ isRowExcluded || input.ortResult.isExcluded(issue, id)
+ )
+ }
+
+ val (openIssues, excludedOrResolvedIssue) = issues.partition {
+ !(it.isResolved || it.isExcluded)
+ }
val scopes = scopesForId[id].orEmpty().map { (name, excludes) ->
ProjectTable.Scope(name, excludes)
@@ -161,12 +179,8 @@ private fun getProjectTable(input: ReporterInput, project: Project): ProjectTabl
declaredLicenses = declaredLicenses,
detectedLicenses = detectedLicenses,
effectiveLicense = effectiveLicense,
- analyzerIssues = analyzerIssues.map {
- it.toTableReportIssue(input.ortResult, input.howToFixTextProvider)
- },
- scanIssues = scannerIssuesForId[id].orEmpty().map {
- it.toTableReportIssue(input.ortResult, input.howToFixTextProvider)
- }
+ openIssues.sortedByDescending { it.severity },
+ excludedOrResolvedIssue.sortedByDescending { it.isResolved }
)
}
@@ -194,7 +208,7 @@ private fun getAdvisorIssueSummaryTable(input: ReporterInput): IssueTable =
private fun Map>.toIssueSummaryTable(type: IssueTable.Type, input: ReporterInput): IssueTable {
val rows = flatMap { (id, issues) ->
issues.map { issue ->
- val resolvableIssue = issue.toTableReportIssue(input.ortResult, input.howToFixTextProvider)
+ val resolvableIssue = issue.toTableReportIssue(input.ortResult, input.howToFixTextProvider, false)
IssueTable.Row(resolvableIssue, id)
}
}.sortedWith(compareByDescending { it.issue.severity }.thenBy { it.id })
diff --git a/plugins/reporters/static-html/src/main/resources/static-html-reporter.css b/plugins/reporters/static-html/src/main/resources/static-html-reporter.css
index dbb70cb699b63..a2f40c84d17ad 100644
--- a/plugins/reporters/static-html/src/main/resources/static-html-reporter.css
+++ b/plugins/reporters/static-html/src/main/resources/static-html-reporter.css
@@ -144,57 +144,70 @@ ul {
border-right: 1px solid rgba(34, 36, 38, .15);
}
-.report-table li.resolved {
- color: #2c662d;
-}
-
.report-table details {
overflow: scroll;
}
-.report-table tr.error {
+.report-table tr.error td {
background: #fff6f6;
color: #9f3a38;
}
-.report-table tr.warning {
+.report-table tr.warning td {
background: #fffaf3;
color: #573a08;
}
-.report-table tr.hint {
+.report-table tr.hint td {
background: #f7f5ff;
color: #1c0859;
}
/**
- * Rule violation table, which specializes .report-table.
+ * Project section.
*/
-.report-rule-violation-table tr.resolved {
- background: #fcfff5;
- color: #2c662d;
+.project.excluded {
+ h3, .report-key-value-table, .report-project-table > thead th {
+ filter: opacity(50%);
+ }
}
-/**
- * Project table, which specializes .report-table.
- */
+.report-project-table .pkg.excluded {
+ > td:nth-child(1), td:nth-child(2), td:nth-child(3), td:nth-child(4) {
+ filter: opacity(50%);
+ }
+}
-.report-project-table tr.error {
- color: black;
+.report-project-table .pkg:not(.excluded) {
+ .scope.excluded, .detected-license.excluded {
+ filter: opacity(50%);
+ }
}
-.report-project-table tr.error td:nth-child(5),
-.report-project-table tr.error td:nth-child(6) {
- color: #9f3a38;
+.report-project-table td:has(.package-issue-table) {
+ padding: 0px;
}
-/*
- * Excluded state.
- */
+.package-issue-table {
+ border-spacing: 10px;
+ padding: 0px;
+ margin: 0px;
+}
-.excluded {
- filter: opacity(50%);
+.package-issue-table td {
+ border-radius: .60rem !important;
+ border-bottom: 1px solid rgba(34, 36, 38, .15);
+}
+
+.package-issue-table tr.resolved td {
+ background: #fcfff5;
+ color: #2c662d;
+}
+
+.package-issue-table tr.excluded td {
+ background: #f9fafb;
+ color: rgba(34, 36, 38, .7);
}
.reason {
@@ -205,18 +218,6 @@ ul {
display: inline;
}
-table.excluded tr.excluded {
- filter: opacity(100%);
-}
-
-table tr.excluded td li.excluded {
- filter: opacity(100%);
-}
-
-table.excluded tr.excluded td li.excluded {
- filter: opacity(100%);
-}
-
/**
* Report table media specific styling.
*/