All Downloads are FREE. Search and download functionalities are using the official Maven repository.

utils.SeverityStatsPrinter.kt Maven / Gradle / Ivy

/*
 * Copyright (C) 2021 The ORT Project Authors (see )
 *
 * 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
 *
 *     https://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.
 *
 * SPDX-License-Identifier: Apache-2.0
 * License-Filename: LICENSE
 */

package org.ossreviewtoolkit.plugins.commands.api.utils

import com.github.ajalt.clikt.core.ProgramResult
import com.github.ajalt.mordant.rendering.Theme
import com.github.ajalt.mordant.terminal.Terminal

import org.ossreviewtoolkit.model.Issue
import org.ossreviewtoolkit.model.RuleViolation
import org.ossreviewtoolkit.model.Severity
import org.ossreviewtoolkit.model.utils.ResolutionProvider

/**
 * A helper class to print severity statistics.
 */
class SeverityStatsPrinter(private val terminal: Terminal, private val resolutionProvider: ResolutionProvider) {
    inner class Entry(
        val name: String,
        val resolvedCounts: Map,
        val unresolvedCounts: Map
    ) {
        /**
         * Print the stats to the [terminal].
         */
        fun print() =
            apply {
                fun p(count: Int, thing: String) = if (count == 1) "$count $thing" else "$count ${thing}s"

                val resolved = Severity.entries.toTypedArray().sortedArrayDescending().map {
                    val count = resolvedCounts.getOrDefault(it, 0)
                    val text = p(count, it.name.lowercase())
                    Theme.Default.success(text)
                }

                terminal.println("${Theme.Default.info("Resolved ${name}s:")} ${resolved.joinToString()}.")

                val unresolved = Severity.entries.toTypedArray().sortedArrayDescending().map {
                    val count = unresolvedCounts.getOrDefault(it, 0)
                    val text = p(count, it.name.lowercase())
                    if (count == 0) Theme.Default.success(text) else Theme.Default.danger(text)
                }

                terminal.println("${Theme.Default.warning("Unresolved ${name}s:")} ${unresolved.joinToString()}.")
            }

        /**
         * Conclude severity statistics by printing an according note and throw a [ProgramResult] exception with
         * [severeStatusCode] if there are severities equal to or greater than [threshold].
         */
        fun conclude(threshold: Severity, severeStatusCode: Int) =
            apply {
                val severeCount = unresolvedCounts.entries.sumOf { (severity, count) ->
                    if (severity >= threshold) count else 0
                }

                if (severeCount > 0) {
                    val (be, s) = if (severeCount == 1) "is" to "" else "are" to "s"

                    terminal.println(
                        "There $be $severeCount unresolved $name$s with a severity equal to or greater than the " +
                            "$threshold threshold."
                    )

                    throw ProgramResult(severeStatusCode)
                }
            }
    }

    @JvmName("statsForIssues")
    fun stats(issues: Collection) =
        stats("issue", issues.partition { resolutionProvider.isResolved(it) }) { severity }

    @JvmName("statsForRuleViolations")
    fun stats(ruleViolations: Collection) =
        stats("rule violation", ruleViolations.partition { resolutionProvider.isResolved(it) }) { severity }

    private fun  stats(name: String, thingsWithSeverities: Pair, List>, selector: T.() -> Severity) =
        Entry(
            name = name,
            resolvedCounts = thingsWithSeverities.first.groupingBy(selector).eachCount(),
            unresolvedCounts = thingsWithSeverities.second.groupingBy(selector).eachCount()
        )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy