diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/diagnosticsAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/diagnosticsAssertions.kt index a19bdd82d4d..17e41df458f 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/diagnosticsAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/diagnosticsAssertions.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.testbase import org.gradle.testkit.runner.BuildResult import org.jetbrains.kotlin.gradle.BaseGradleIT import org.jetbrains.kotlin.gradle.internals.VERBOSE_DIAGNOSTIC_SEPARATOR +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory import kotlin.test.assertNull import kotlin.test.assertTrue @@ -68,10 +69,13 @@ fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withS /** * NB: Needs verbose mode of diagnostics, see [org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.internalVerboseDiagnostics] + * Because this mode is enabled by the 'kotlin.internal'-property, actual output will always contain + * [org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed]. + * For the sake of clarity, this diagnostic is filtered by default. */ fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildString { var diagnosticStarted = false - val currentDiagnostic = StringBuilder() + val currentDiagnostic = mutableListOf() fun startDiagnostic(line: String, lineIndex: Int) { require(!diagnosticStarted) { @@ -79,12 +83,12 @@ fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildStrin "Unexpected start of diagnostic $line on line ${lineIndex + 1}. The end of the previous diagnostic wasn't found yet" } - currentDiagnostic.appendLine(line) + currentDiagnostic += line diagnosticStarted = true } fun continueDiagnostic(line: String) { - currentDiagnostic.appendLine(line) + currentDiagnostic += line } fun endDiagnostic(line: String, lineIndex: Int) { @@ -93,9 +97,16 @@ fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildStrin "Unexpected end of diagnostic $line on line ${lineIndex + 1}" } - currentDiagnostic.appendLine(line) - currentDiagnostic.appendLine() - append(currentDiagnostic.toString()) + currentDiagnostic += line + + // Suppress InternalKotlinGradlePluginProperties, but only if the single property it complains about is + // 'kotlin.internal.verboseDiagnostics' + val offendingProperties = currentDiagnostic.asSequence().filter { it.startsWith("kotlin.internal.") } + if (KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed.id !in currentDiagnostic.first() || + offendingProperties.singleOrNull() != "kotlin.internal.verboseDiagnostics" + ) { + appendLine(currentDiagnostic.joinToString(separator = "\n", postfix = "\n")) + } currentDiagnostic.clear() diagnosticStarted = false diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt index dec9909dbc5..e4f9cbf3b3d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt @@ -48,6 +48,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_VERSION_ALIGNMENT import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnosticOncePerBuild import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService @@ -213,9 +214,9 @@ internal class PropertiesProvider private constructor(private val project: Proje get() = booleanProperty(KOTLIN_NATIVE_DEPENDENCY_PROPAGATION) var mpp13XFlagsSetByPlugin: Boolean - get() = booleanProperty("kotlin.internal.mpp.13X.flags.setByPlugin") ?: false + get() = booleanProperty(MPP_13X_FLAGS_SET_BY_PLUGIN) ?: false set(value) { - project.extensions.extraProperties.set("kotlin.internal.mpp.13X.flags.setByPlugin", "$value") + project.extensions.extraProperties.set(MPP_13X_FLAGS_SET_BY_PLUGIN, "$value") } val mppHierarchicalStructureByDefault: Boolean @@ -581,7 +582,8 @@ internal class PropertiesProvider private constructor(private val project: Proje localProperties.getProperty(propName) } - private fun propertiesWithPrefix(prefix: String): Map { + @UnsafeApi + internal fun propertiesWithPrefix(prefix: String): Map { val result: MutableMap = mutableMapOf() project.properties.forEach { (name, value) -> if (name.startsWith(prefix) && value is String) { @@ -604,7 +606,6 @@ internal class PropertiesProvider private constructor(private val project: Proje const val KOTLIN_MPP_ENABLE_GRANULAR_SOURCE_SETS_METADATA = "kotlin.mpp.enableGranularSourceSetsMetadata" const val KOTLIN_MPP_ENABLE_COMPATIBILITY_METADATA_VARIANT = "kotlin.mpp.enableCompatibilityMetadataVariant" const val KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION = "kotlin.mpp.enableCInteropCommonization" - const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "kotlin.internal.mpp.hierarchicalStructureByDefault" const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT = "kotlin.mpp.hierarchicalStructureSupport" const val KOTLIN_MPP_DEPRECATED_PROPERTIES_NO_WARN = "kotlin.mpp.deprecatedProperties.nowarn" const val KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN = "kotlin.mpp.androidGradlePluginCompatibility.nowarn" @@ -629,17 +630,24 @@ internal class PropertiesProvider private constructor(private val project: Proje const val KOTLIN_COMPILER_USE_PRECISE_COMPILATION_RESULTS_BACKUP = "kotlin.compiler.preciseCompilationResultsBackup" const val KOTLIN_COMPILER_KEEP_INCREMENTAL_COMPILATION_CACHES_IN_MEMORY = "kotlin.compiler.keepIncrementalCompilationCachesInMemory" const val KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING = "kotlin.compiler.suppressExperimentalICOptimizationsWarning" - const val KOTLIN_CREATE_DEFAULT_MULTIPLATFORM_PUBLICATIONS = "kotlin.internal.mpp.createDefaultMultiplatformPublications" const val KOTLIN_RUN_COMPILER_VIA_BUILD_TOOLS_API = "kotlin.compiler.runViaBuildToolsApi" const val KOTLIN_MPP_ALLOW_LEGACY_DEPENDENCIES = "kotlin.mpp.allow.legacy.dependencies" const val KOTLIN_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE = "kotlin.publishJvmEnvironmentAttribute" const val KOTLIN_EXPERIMENTAL_TRY_K2 = "kotlin.experimental.tryK2" - const val KOTLIN_INTERNAL_VERBOSE_DIAGNOSTICS = "kotlin.internal.verboseDiagnostics" const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_WARNINGS = "kotlin.suppressGradlePluginWarnings" - const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS = "kotlin.internal.suppressGradlePluginErrors" const val KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS = "kotlin.native.ignoreDisabledTargets" const val KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING = "kotlin.native.suppressExperimentalArtifactsDslWarning" const val KONAN_DATA_DIR = "konan.data.dir" + + /** + * Internal properties: builds get big non-suppressible warning when such properties are used + * See [org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.InternalGradlePropertiesUsageChecker] + **/ + const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "$KOTLIN_INTERNAL_NAMESPACE.mpp.hierarchicalStructureByDefault" + const val KOTLIN_CREATE_DEFAULT_MULTIPLATFORM_PUBLICATIONS = "$KOTLIN_INTERNAL_NAMESPACE.mpp.createDefaultMultiplatformPublications" + const val KOTLIN_INTERNAL_VERBOSE_DIAGNOSTICS = "$KOTLIN_INTERNAL_NAMESPACE.verboseDiagnostics" + const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS = "$KOTLIN_INTERNAL_NAMESPACE.suppressGradlePluginErrors" + const val MPP_13X_FLAGS_SET_BY_PLUGIN = "$KOTLIN_INTERNAL_NAMESPACE.mpp.13X.flags.setByPlugin" } companion object { @@ -651,6 +659,8 @@ internal class PropertiesProvider private constructor(private val project: Proje private const val KOTLIN_NATIVE_BINARY_OPTION_PREFIX = "kotlin.native.binary." + internal const val KOTLIN_INTERNAL_NAMESPACE = "kotlin.internal" + operator fun invoke(project: Project): PropertiesProvider = with(project.extensions.extraProperties) { if (!has(CACHED_PROVIDER_EXT_NAME)) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt index f87113736d2..013551e69ca 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt @@ -114,6 +114,7 @@ internal interface KotlinGradleProjectChecker { AndroidMainSourceSetConventionsChecker, IosSourceSetConventionChecker, KotlinTargetAlreadyDeclaredChecker, + InternalGradlePropertiesUsageChecker, ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt index 0e4c7bda5e9..4a16103f638 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt @@ -602,6 +602,19 @@ object KotlinToolingDiagnostics { """.trimIndent() ) } + + object InternalKotlinGradlePluginPropertiesUsed : ToolingDiagnosticFactory(WARNING) { + operator fun invoke(propertiesUsed: Collection) = build( + """ + |ATTENTION! This build uses the following Kotlin Gradle Plugin properties: + | + |${propertiesUsed.joinToString(separator = "\n")} + | + |kotlin.internal-properties are not recommended for production use. + |Stability and future compatibility of the build is not guaranteed. + """.trimMargin() + ) + } } private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/ToolingDiagnosticRenderingOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/ToolingDiagnosticRenderingOptions.kt index 3c2e882f935..5a3e9a40f71 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/ToolingDiagnosticRenderingOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/ToolingDiagnosticRenderingOptions.kt @@ -26,6 +26,9 @@ internal class ToolingDiagnosticRenderingOptions( internal fun ToolingDiagnostic.isSuppressed(options: ToolingDiagnosticRenderingOptions): Boolean { return when { + // Non-suppressible + id == KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed.id -> false + severity == ToolingDiagnostic.Severity.WARNING -> id in options.suppressedWarningIds severity == ToolingDiagnostic.Severity.ERROR -> id in options.suppressedErrorIds diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt new file mode 100644 index 00000000000..72fe9bb3008 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt @@ -0,0 +1,33 @@ +/* + * 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.plugin.diagnostics.checkers + +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider +import org.jetbrains.kotlin.gradle.plugin.await +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector +import org.jetbrains.kotlin.tooling.core.UnsafeApi + +internal object InternalGradlePropertiesUsageChecker : KotlinGradleProjectChecker { + override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) { + KotlinPluginLifecycle.Stage.ReadyForExecution.await() + + @OptIn(UnsafeApi::class) + val internalPropertiesUsed = kotlinPropertiesProvider.propertiesWithPrefix(PropertiesProvider.KOTLIN_INTERNAL_NAMESPACE).keys + val internalPropertiesFiltered = internalPropertiesUsed.minus(PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN) + if (internalPropertiesFiltered.isEmpty()) return + + collector.reportOncePerGradleBuild( + project, + KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed(internalPropertiesFiltered.sorted()), + // Known issue in edge case: if several Gradle subprojects declare internal properties, only one will be reported + key = InternalGradlePropertiesUsageChecker::class.qualifiedName!! + ) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/suppressedErrors.txt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/suppressedErrors.txt new file mode 100644 index 00000000000..4fbc7bd6b79 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/suppressedErrors.txt @@ -0,0 +1,6 @@ +[InternalKotlinGradlePluginPropertiesUsed | WARNING] ATTENTION! This build uses the following Kotlin Gradle Plugin properties: + +kotlin.internal.suppressGradlePluginErrors + +kotlin.internal-properties are not recommended for production use. +Stability and future compatibility of the build is not guaranteed.