Add FUS statistics for dokka usage

#KT-57330 Fixed
This commit is contained in:
Nataliya.Valtman
2023-04-24 16:07:59 +02:00
committed by Space Team
parent 180fc84eb7
commit 1591869991
4 changed files with 192 additions and 2 deletions
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.GradleTest
import org.junit.jupiter.api.DisplayName
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.replaceText
import org.jetbrains.kotlin.test.KtAssert.fail
import java.nio.file.Files
import java.nio.file.Path
import kotlin.streams.asSequence
@DisplayName("FUS statistic")
class FusStatisticsIT : KGPBaseTest() {
@DisplayName("for dokka")
@GradleTest
fun testDokka(gradleVersion: GradleVersion) {
project(
"simpleProject",
gradleVersion,
) {
applyDokka()
build("compileKotlin", "dokkaHtml", "-Pkotlin.session.logger.root.path=$projectPath") {
assertFileContains(
fusStatisticsPath,
"ENABLED_DOKKA",
"ENABLED_DOKKA_HTML"
)
}
}
}
private fun TestProject.applyDokka() {
buildGradle.replaceText(
"plugins {",
"""
plugins {
id("org.jetbrains.dokka") version "1.7.10"
""".trimIndent()
)
buildGradle.modify {
"""
import org.jetbrains.dokka.DokkaConfiguration.Visibility
import org.jetbrains.dokka.gradle.DokkaTask
$it
tasks.withType(DokkaTask.class) {
dokkaSourceSets.configureEach {
documentedVisibilities.set([
Visibility.PUBLIC,
Visibility.PROTECTED
])
}
}
""".trimIndent()
}
}
private val GradleProject.fusStatisticsPath: Path
get() {
val statisticsDir = projectPath.resolve("kotlin-profile")
return Files.list(statisticsDir).use {
val files = it.asSequence().toList()
files.singleOrNull() ?: fail("The directory must contain a single statistics file, but got: $files")
}
}
@DisplayName("general fields")
@GradleTest
fun testFusStatistics(gradleVersion: GradleVersion) {
project(
"simpleProject",
gradleVersion,
) {
build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") {
val fusStatisticsPath = fusStatisticsPath
assertFileContains(
fusStatisticsPath,
"OS_TYPE",
"BUILD_FAILED=false",
"EXECUTED_FROM_IDEA=false",
"BUILD_FINISH_TIME",
"GRADLE_VERSION",
"KOTLIN_STDLIB_VERSION",
"KOTLIN_COMPILER_VERSION",
)
assertFileDoesNotContain(
fusStatisticsPath,
"ENABLED_DOKKA",
"ENABLED_DOKKA_HTML",
) // asserts that we do not put DOKKA metrics everywhere just in case
}
}
}
@DisplayName("for failed build")
@GradleTest
fun testFusStatisticsForFailedBuild(gradleVersion: GradleVersion) {
project(
"simpleProject",
gradleVersion,
) {
projectPath.resolve("src/main/kotlin/helloWorld.kt").modify {
it.replace("java.util.ArrayList", "")
}
buildAndFail("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") {
assertFileContains(
fusStatisticsPath,
"BUILD_FAILED=true",
"OS_TYPE",
"EXECUTED_FROM_IDEA=false",
"BUILD_FINISH_TIME",
"GRADLE_VERSION",
"KOTLIN_STDLIB_VERSION",
"KOTLIN_COMPILER_VERSION",
)
}
}
}
}
@@ -26,6 +26,8 @@ import kotlin.system.measureTimeMillis
class KotlinBuildStatHandler {
companion object {
const val DOKKA_PLUGIN = "org.jetbrains.dokka"
@JvmStatic
internal fun getLogger() = Logging.getLogger(KotlinBuildStatHandler::class.java)
@@ -101,6 +103,9 @@ class KotlinBuildStatHandler {
val statisticOverhead = measureTimeMillis {
gradle.allprojects { project ->
project.plugins.findPlugin(DOKKA_PLUGIN)?.also {
sessionLogger.report(BooleanMetrics.ENABLED_DOKKA, true)
}
for (configuration in project.configurations) {
val configurationName = configuration.name
val dependencies = configuration.dependencies
@@ -13,6 +13,9 @@ import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.initialization.BuildRequestMetaData
import org.gradle.invocation.DefaultGradle
import org.gradle.tooling.events.OperationCompletionListener
import org.gradle.tooling.events.task.TaskFinishEvent
import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler.Companion.runSafe
import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsMXBean
import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsService
@@ -131,6 +134,14 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
if (!isConfigurationCacheAvailable(gradle)) {
gradle.addBuildListener(instance!!)
}
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider {
OperationCompletionListener { event ->
if (event is TaskFinishEvent) {
reportTaskIfNeed(event.descriptor.name)
}
}
})
}
instance
}
@@ -147,6 +158,24 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
}
}
protected fun reportTaskIfNeed(task: String) {
val metric = when (task.substringAfterLast(":")) {
"dokkaHtml" -> BooleanMetrics.ENABLED_DOKKA_HTML
"dokkaGfm" -> BooleanMetrics.ENABLED_DOKKA_GFM
"dokkaJavadoc" -> BooleanMetrics.ENABLED_DOKKA_JAVADOC
"dokkaJekyll" -> BooleanMetrics.ENABLED_DOKKA_JEKYLL
"dokkaHtmlMultiModule" -> BooleanMetrics.ENABLED_DOKKA_HTML_MULTI_MODULE
"dokkaGfmMultiModule" -> BooleanMetrics.ENABLED_DOKKA_GFM_MULTI_MODULE
"dokkaJekyllMultiModule" -> BooleanMetrics.ENABLED_DOKKA_JEKYLL_MULTI_MODULE
"dokkaHtmlCollector" -> BooleanMetrics.ENABLED_DOKKA_HTML_COLLECTOR
"dokkaGfmCollector" -> BooleanMetrics.ENABLED_DOKKA_GFM_COLLECTOR
"dokkaJavadocCollector" -> BooleanMetrics.ENABLED_DOKKA_JAVADOC_COLLECTOR
"dokkaJekyllCollector" -> BooleanMetrics.ENABLED_DOKKA_JEKYLL_COLLECTOR
else -> null
}
metric?.also { getInstance()?.report(it, true) }
}
/**
* Invokes provided collector if the reporting service is initialised.
@@ -220,14 +249,31 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private
internal abstract class AbstractKotlinBuildStatsService(
gradle: Gradle,
protected val beanName: ObjectName
protected val beanName: ObjectName,
) : KotlinBuildStatsService() {
companion object {
//test only
const val CUSTOM_LOGGER_ROOT_PATH = "kotlin.session.logger.root.path"
private val logger = Logging.getLogger(AbstractKotlinBuildStatsService::class.java)
}
private val forcePropertiesValidation = if (gradle.rootProject.hasProperty(FORCE_VALUES_VALIDATION)) {
gradle.rootProject.property(FORCE_VALUES_VALIDATION).toString().toBoolean()
} else {
false
}
protected val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir, forceValuesValidation = forcePropertiesValidation)
private val customSessionLoggerRootPath =
gradle.rootProject.properties[CUSTOM_LOGGER_ROOT_PATH]?.also {
logger.warn("$CUSTOM_LOGGER_ROOT_PATH property for test purpose only")
} as String?
private val sessionLoggerRootPath =
customSessionLoggerRootPath?.let { File(it) } ?: gradle.gradleUserHomeDir
protected val sessionLogger = BuildSessionLogger(sessionLoggerRootPath, forceValuesValidation = forcePropertiesValidation)
private fun gradleBuildStartTime(gradle: Gradle): Long? {
return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime
@@ -49,6 +49,20 @@ enum class BooleanMetrics(val type: BooleanOverridePolicy, val anonymization: Bo
JS_KLIB_INCREMENTAL(OR, SAFE),
JS_IR_INCREMENTAL(OR, SAFE),
//Dokka features
ENABLED_DOKKA(OR, SAFE),
ENABLED_DOKKA_HTML(OR, SAFE),
ENABLED_DOKKA_JAVADOC(OR, SAFE),
ENABLED_DOKKA_GFM(OR, SAFE),
ENABLED_DOKKA_JEKYLL(OR, SAFE),
ENABLED_DOKKA_HTML_MULTI_MODULE(OR, SAFE),
ENABLED_DOKKA_GFM_MULTI_MODULE(OR, SAFE),
ENABLED_DOKKA_JEKYLL_MULTI_MODULE(OR, SAFE),
ENABLED_DOKKA_HTML_COLLECTOR(OR, SAFE),
ENABLED_DOKKA_JAVADOC_COLLECTOR(OR, SAFE),
ENABLED_DOKKA_GFM_COLLECTOR(OR, SAFE),
ENABLED_DOKKA_JEKYLL_COLLECTOR(OR, SAFE),
// User scenarios
DEBUGGER_ENABLED(OVERRIDE, SAFE),
COMPILATION_STARTED(OVERRIDE, SAFE),