Skip to content

Commit

Permalink
Disabled writing of FreeMarker logs to stdout when generating an HTML…
Browse files Browse the repository at this point in the history
… report

Due to an untraceable error of FreeMarker templates, repeated attempts to generate a report are triggered in some cases. In case of unsuccessful attempts, FreeMarker writes to its logger, which is sent to stdout by default.
If the error repeats frequently, an exception will be thrown with an error message - so we can ignore FreeMarker's own logging when generating an HTML report.

- upgraded IntelliJ Coverage Library to version `1.0.738`
- changed IntelliJ stdout logging level to error
- refactored code that works with Gradle Worker API
- small refactoring IntelliJ integration

Fixes #446
PR #469
  • Loading branch information
shanshin authored Oct 10, 2023
1 parent ac35dc2 commit 84f1b12
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 177 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]

intellij-coverage = "1.0.729"
intellij-coverage = "1.0.738"
junit = "5.9.0"
kotlinx-bcv = "0.13.2"
kotlinx-dokka = "1.8.10"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public object KoverVersions {
/**
* Kover coverage tool version.
*/
public const val KOVER_TOOL_VERSION = "1.0.724"
public const val KOVER_TOOL_VERSION = "1.0.738"

/**
* JaCoCo coverage tool version used by default.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.kover.gradle.plugin.tools.kover

import com.intellij.rt.coverage.util.ErrorReporter
import kotlinx.kover.gradle.plugin.commons.ArtifactContent
import kotlinx.kover.gradle.plugin.commons.ReportContext
import kotlinx.kover.gradle.plugin.commons.ReportFilters
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkQueue

private const val FREE_MARKER_LOGGER_PROPERTY_NAME = "org.freemarker.loggerLibrary"

internal interface ReportParameters: WorkParameters {
val filters: Property<ReportFilters>

val files: Property<ArtifactContent>
val tempDir: DirectoryProperty
val projectPath: Property<String>
val charset: Property<String>
}

internal abstract class AbstractReportAction<T : ReportParameters> : WorkAction<T> {
protected abstract fun generate()

final override fun execute() {
// print to stdout only critical errors
ErrorReporter.setLogLevel(ErrorReporter.ERROR)

// disable freemarker logging to stdout for the time of report generation
val oldFreemarkerLogger = System.setProperty(FREE_MARKER_LOGGER_PROPERTY_NAME, "none")
try {
generate()
} finally {
if (oldFreemarkerLogger == null) {
System.clearProperty(FREE_MARKER_LOGGER_PROPERTY_NAME)
} else {
System.setProperty(FREE_MARKER_LOGGER_PROPERTY_NAME, oldFreemarkerLogger)
}
}
}
}

internal inline fun <reified A : AbstractReportAction<P>, P : ReportParameters> ReportContext.submitAction(noinline parametersConfig: P.() -> Unit) {
val workQueue: WorkQueue = services.workerExecutor.classLoaderIsolation {
classpath.from(this@submitAction.classpath)
}
workQueue.submit(A::class.java) { parametersConfig(this) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,12 @@ import kotlinx.kover.gradle.plugin.tools.writeToFile
import kotlinx.kover.gradle.plugin.util.ONE_HUNDRED
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkQueue
import org.jetbrains.kotlin.gradle.utils.`is`
import java.io.File
import java.math.BigDecimal


internal fun ReportContext.printCoverage(request: CoverageRequest, outputFile: File) {
val workQueue: WorkQueue = services.workerExecutor.classLoaderIsolation {
this.classpath.from(this@printCoverage.classpath)
}

workQueue.submit(CollectCoverageAction::class.java) {
submitAction<CollectCoverageAction, CollectCoverageParameters> {
this.outputFile.set(outputFile)
this.request.convention(request)

Expand All @@ -40,8 +33,8 @@ internal fun ReportContext.printCoverage(request: CoverageRequest, outputFile: F
}


internal abstract class CollectCoverageAction : WorkAction<CollectCoverageParameters> {
override fun execute() {
internal abstract class CollectCoverageAction : AbstractReportAction<CollectCoverageParameters>() {
override fun generate() {
val request = parameters.request.get()
val bound = VerificationBound(ONE_HUNDRED, BigDecimal.ZERO, request.metric, request.aggregation)
val failRule = VerificationRule(true, null, null, request.entity, listOf(bound))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,13 @@ package kotlinx.kover.gradle.plugin.tools.kover

import com.intellij.rt.coverage.aggregate.api.AggregatorApi
import com.intellij.rt.coverage.aggregate.api.Request
import com.intellij.rt.coverage.report.api.Filters
import kotlinx.kover.gradle.plugin.commons.ReportContext
import kotlinx.kover.gradle.plugin.util.asPatterns
import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkQueue
import java.io.File


internal fun ReportContext.koverBinaryReport(binary: File) {
val workQueue: WorkQueue = services.workerExecutor.classLoaderIsolation {
this.classpath.from(this@koverBinaryReport.classpath)
}

workQueue.submit(BinaryReportAction::class.java) {
submitAction<BinaryReportAction, BinaryReportParameters> {
binaryFile.set(binary)
filters.convention(this@koverBinaryReport.filters)

Expand All @@ -30,19 +22,14 @@ internal interface BinaryReportParameters : ReportParameters {
val binaryFile: Property<File>
}

internal abstract class BinaryReportAction : WorkAction<BinaryReportParameters> {
override fun execute() {
internal abstract class BinaryReportAction : AbstractReportAction<BinaryReportParameters>() {
override fun generate() {
val binary = parameters.binaryFile.get()
val smapFile = parameters.tempDir.file("report.smap").get().asFile

val files = parameters.files.get()
val filtersIntern = parameters.filters.get()
val filters = Filters(
filtersIntern.includesClasses.toList().asPatterns(),
filtersIntern.excludesClasses.toList().asPatterns(),
filtersIntern.excludesAnnotations.toList().asPatterns()
)
val request = Request(filters, binary, smapFile)
val filters = parameters.filters.get()
val request = Request(filters.toIntellij(), binary, smapFile)

AggregatorApi.aggregate(listOf(request), files.reports.toList(), files.outputs.toList())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package kotlinx.kover.gradle.plugin.tools.kover

import com.intellij.rt.coverage.report.api.Filters
import com.intellij.rt.coverage.verify.api.Counter
import com.intellij.rt.coverage.verify.api.Target
import com.intellij.rt.coverage.verify.api.ValueType
import kotlinx.kover.gradle.plugin.commons.ReportFilters
import kotlinx.kover.gradle.plugin.commons.VerificationBound
import kotlinx.kover.gradle.plugin.commons.VerificationRule
import kotlinx.kover.gradle.plugin.dsl.AggregationType
import kotlinx.kover.gradle.plugin.dsl.GroupingEntityType
import kotlinx.kover.gradle.plugin.dsl.MetricType
import kotlinx.kover.gradle.plugin.util.ONE_HUNDRED
import kotlinx.kover.gradle.plugin.util.asPatterns
import java.math.BigDecimal
import java.math.RoundingMode

internal fun ReportFilters.toIntellij() = Filters(
includesClasses.asPatterns(),
excludesClasses.asPatterns(),
excludesAnnotations.asPatterns()
)

internal fun VerificationRule.targetToIntellij(): Target {
return when (entityType) {
GroupingEntityType.APPLICATION -> Target.ALL
GroupingEntityType.CLASS -> Target.CLASS
GroupingEntityType.PACKAGE -> Target.PACKAGE
}
}

internal fun VerificationBound.counterToIntellij(): Counter {
return when (metric) {
MetricType.LINE -> Counter.LINE
MetricType.INSTRUCTION -> Counter.INSTRUCTION
MetricType.BRANCH -> Counter.BRANCH
}
}

internal fun VerificationBound.valueTypeToIntellij(): ValueType {
return when (aggregation) {
AggregationType.COVERED_COUNT -> ValueType.COVERED
AggregationType.MISSED_COUNT -> ValueType.MISSED
AggregationType.COVERED_PERCENTAGE -> ValueType.COVERED_RATE
AggregationType.MISSED_PERCENTAGE -> ValueType.MISSED_RATE
}
}

internal fun VerificationBound.valueToIntellij(value: BigDecimal?): BigDecimal? {
value ?: return null
return if (aggregation.isPercentage) {
value.divide(ONE_HUNDRED, 6, RoundingMode.HALF_UP)
} else {
value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,16 @@

package kotlinx.kover.gradle.plugin.tools.kover

import com.intellij.rt.coverage.report.api.Filters
import com.intellij.rt.coverage.report.api.ReportApi
import kotlinx.kover.gradle.plugin.commons.ReportContext
import kotlinx.kover.gradle.plugin.util.asPatterns
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkQueue
import java.io.File


internal fun ReportContext.koverHtmlReport(htmlReportDir: File, htmlTitle: String, charsetName: String?) {
val workQueue: WorkQueue = services.workerExecutor.classLoaderIsolation {
this.classpath.from(this@koverHtmlReport.classpath)
}

workQueue.submit(HtmlReportAction::class.java) {
submitAction<HtmlReportAction, HtmlReportParameters> {
htmlDir.set(htmlReportDir)
title.convention(htmlTitle)
charset.convention(charsetName)
Expand All @@ -34,11 +26,7 @@ internal fun ReportContext.koverHtmlReport(htmlReportDir: File, htmlTitle: Strin
}

internal fun ReportContext.koverXmlReport(xmlReportFile: File) {
val workQueue: WorkQueue = services.workerExecutor.classLoaderIsolation {
classpath.from(this@koverXmlReport.classpath)
}

workQueue.submit(XmlReportAction::class.java) {
submitAction<XmlReportAction, XmlReportParameters> {
xmlFile.set(xmlReportFile)
filters.convention(this@koverXmlReport.filters)

Expand All @@ -58,38 +46,28 @@ internal interface HtmlReportParameters : ReportParameters {
val title: Property<String>
}

internal abstract class XmlReportAction : WorkAction<XmlReportParameters> {
override fun execute() {
internal abstract class XmlReportAction : AbstractReportAction<XmlReportParameters>() {
override fun generate() {
val files = parameters.files.get()
val filtersIntern = parameters.filters.get()
val filters = Filters(
filtersIntern.includesClasses.toList().asPatterns(),
filtersIntern.excludesClasses.toList().asPatterns(),
filtersIntern.excludesAnnotations.toList().asPatterns()
)
val filters = parameters.filters.get()

ReportApi.xmlReport(
parameters.xmlFile.get().asFile,
files.reports.toList(),
files.outputs.toList(),
files.sources.toList(),
filters
filters.toIntellij()
)
}
}

internal abstract class HtmlReportAction : WorkAction<HtmlReportParameters> {
override fun execute() {
internal abstract class HtmlReportAction : AbstractReportAction<HtmlReportParameters>() {
override fun generate() {
val htmlDir = parameters.htmlDir.get().asFile
htmlDir.mkdirs()

val files = parameters.files.get()
val filtersIntern = parameters.filters.get()
val filters = Filters(
filtersIntern.includesClasses.toList().asPatterns(),
filtersIntern.excludesClasses.toList().asPatterns(),
filtersIntern.excludesAnnotations.toList().asPatterns()
)
val filters = parameters.filters.get()

ReportApi.htmlReport(
parameters.htmlDir.get().asFile,
Expand All @@ -98,7 +76,7 @@ internal abstract class HtmlReportAction : WorkAction<HtmlReportParameters> {
files.reports.toList(),
files.outputs.toList(),
files.sources.toList(),
filters
filters.toIntellij()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ private const val APPEND_TO_DATA_FILE = true
private const val LINING_ONLY_MODE = false

/**
* Enables saving the array in the /candy field,
* Enables saving the array in the candy field,
* without it there will be an appeal to the hash table foreach method, which very slow.
*/
private const val ENABLE_TRACING = "idea.new.tracing.coverage=true"

/**
* Print errors to the Gradle stdout
* Disable agent logging to stdout for messages of levels `debug`, `info`, `warn`.
*/
private const val PRINT_ONLY_ERRORS = "idea.coverage.log.level=error"

Expand All @@ -62,13 +62,14 @@ internal fun buildJvmAgentArgs(

return mutableListOf(
"-javaagent:${jarFile.canonicalPath}=${argsFile.canonicalPath}",
"-D$ENABLE_TRACING",
"-D$PRINT_ONLY_ERRORS",
"-D$IGNORE_STATIC_CONSTRUCTORS",
"-D$DO_NOT_COUNT_HIT_AMOUNT"
property(ENABLE_TRACING),
property(PRINT_ONLY_ERRORS),
property(IGNORE_STATIC_CONSTRUCTORS),
property(DO_NOT_COUNT_HIT_AMOUNT)
)
}

private fun property(propertyDef: String) = "-D$propertyDef"

private fun File.writeAgentArgs(binReportFile: File, excludedClasses: Set<String>) {
binReportFile.parentFile.mkdirs()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,3 @@ internal class KoverTool(override val variant: CoverageToolVariant) : CoverageTo
context.printCoverage(request, outputFile)
}
}


internal interface ReportParameters: WorkParameters {
val filters: Property<ReportFilters>

val files: Property<ArtifactContent>
val tempDir: DirectoryProperty
val projectPath: Property<String>
val charset: Property<String>
}


internal interface VerifyReportParameters: ReportParameters {
val outputFile: RegularFileProperty
val rules: ListProperty<VerificationRule>
}
Loading

0 comments on commit 84f1b12

Please sign in to comment.