From 01f567a16df4b07566d636e5344c9b10321b6b45 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 5 Aug 2022 12:30:14 +0200 Subject: [PATCH] Disable yarn and npm tasks from the build when tests are not active Kotlin build shouldn't depend on npm during while deploy artefacts tasks ^KTI-887 Fixed ^KT-53687 Related --- build.gradle.kts | 2 + .../src/main/kotlin/YarnAndNpmSupressor.kt | 121 ++++++++++++++++++ libraries/kotlin.test/js-ir/build.gradle.kts | 2 + libraries/kotlin.test/wasm/build.gradle.kts | 2 + .../js-ir-minimal-for-test/build.gradle.kts | 2 + libraries/stdlib/js-ir/build.gradle.kts | 4 +- libraries/stdlib/wasm/build.gradle.kts | 2 + .../atomicfu-runtime/build.gradle.kts | 2 + 8 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 buildSrc/src/main/kotlin/YarnAndNpmSupressor.kt diff --git a/build.gradle.kts b/build.gradle.kts index 2277f9b3973..2ea6b0fd0aa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -895,6 +895,8 @@ if (disableVerificationTasks) { } } +gradle.taskGraph.whenReady(checkYarnAndNPMSuppressed) + plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class) { extensions.configure(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension::class.java) { npmInstallTaskProvider?.configure { diff --git a/buildSrc/src/main/kotlin/YarnAndNpmSupressor.kt b/buildSrc/src/main/kotlin/YarnAndNpmSupressor.kt new file mode 100644 index 00000000000..f79906fd62e --- /dev/null +++ b/buildSrc/src/main/kotlin/YarnAndNpmSupressor.kt @@ -0,0 +1,121 @@ +/* + * Copyright 2010-2022 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. + */ +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.execution.TaskExecutionGraph +import org.gradle.api.tasks.TaskProvider + +/* This file is solely needed to suppress implicit dependencies on npm and yarn tasks registered by Kotlin Gradle Plugin */ + +private val rootNpmRelatedTasks = setOf("kotlinNpmInstall", "kotlinStoreYarnLock") +private val ownNpmRelatedTasks = setOf("jsGenerateExternalsIntegrated", "irGenerateExternalsIntegrated", "wasmGenerateExternalsIntegrated") + +private val forbidImplicitDependOnNpmRelatedTasks = setOf( + "jsPackageJson", + "jsPublicPackageJson", + "irPublicPackageJson", + "legacyPublicPackageJson", + "wasmPackageJson", + "wasmPublicPackageJson", + "compileKotlinJs", + "compileKotlinJsIr", + "compileKotlinWasm", + "compileKotlinJsLegacy" +) +private val allowImplicitDependOnNpmForTasks = setOf("compileTestKotlinJs", "compileTestKotlinWasm") + +/** + * Kotlin JS gradle plugin implicitly define dependency to installing NPM and Yarn + * https://youtrack.jetbrains.com/issue/KT-53687/Dont-trigger-npm-and-yarn-related-tasks-if-it-not-relevant-for-assemble + * We would like to explicitly disable this behaviour for kotlin standard library publication as it's shouldn't be needed but make the + * build slower, make it less stable, generated additional traiffic, make the build less secure and so on. + * + * Implemented by manually removing dependencies set by Kotlin Gradle Plugin. + */ +fun Project.suppressYarnAndNpmForAssemble() { + afterEvaluate { + for (npmYarnTaskName in rootNpmRelatedTasks) { + tasks.findByPath(":$npmYarnTaskName") ?: error("Can't find root task $npmYarnTaskName") + } + + val npmRelatedTasksNames = rootNpmRelatedTasks + ownNpmRelatedTasks + + for (taskName in forbidImplicitDependOnNpmRelatedTasks) { + val task = project.tasks.findByName(taskName) ?: continue + if (!task.enabled) continue + + val removeDependencies = task.dependsOn + .filterIsInstance(TaskProvider::class.java) + .filter { it.name in npmRelatedTasksNames } + .toSet() + + if (removeDependencies.isNotEmpty()) { + task.setDependsOn(task.dependsOn - removeDependencies) + logger.quiet("Disable NPM/Yarn dependency tasks in $project - " + + "remove ${removeDependencies.joinToString(", ") { "'${it.name}'" }} dependencies from $task") + } + } + } +} + +private fun findRootTasks(taskGraph: TaskExecutionGraph): List { + val allDependentTasksPaths = mutableSetOf() + val allTasksPaths = mutableSetOf() + taskGraph.allTasks.forEach { task -> + allTasksPaths.add(task.path) + for (dependency in task.taskDependencies.getDependencies(task)) { + allDependentTasksPaths.add(dependency.path) + } + } + val rootTasksPaths = allTasksPaths - allDependentTasksPaths + + return taskGraph.allTasks.filter { task -> task.path in rootTasksPaths } +} + +private fun tasksGraphString(taskGraph: TaskExecutionGraph, ident: String = "", nextIdent: (String) -> String = { "$it|-"}): String { + return buildString { + val alreadyPrintedTasks = mutableSetOf() + fun Task.printTree(indent: String) { + append(indent) + if (path in alreadyPrintedTasks) { + appendLine("$path *") + } else { + alreadyPrintedTasks.add(path) + appendLine(path) + val nextIndent = nextIdent(indent) + for (dependency in taskDependencies.getDependencies(this)) { + dependency.printTree(nextIndent) + } + } + } + + for (rootTask in findRootTasks(taskGraph)) { + rootTask.printTree(ident) + } + } +} + +val Project.checkYarnAndNPMSuppressed: Action get() { + return Action { + val disableNpmYarnCheck = providers.gradleProperty("kotlin.build.disable.npmyarn.suppress.check") + .forUseAtConfigurationTime().orNull?.toBoolean() ?: false + + if (disableNpmYarnCheck) return@Action + + val executeTaskNames = allTasks.filter { it.enabled }.map { it.name }.toSet() + + val npmYarnTasks = rootNpmRelatedTasks.filter { it in executeTaskNames } + val allowedTask = allowImplicitDependOnNpmForTasks.filter { it in executeTaskNames } + + if (npmYarnTasks.isNotEmpty()) { + if (allowedTask.isEmpty()) { + error("$npmYarnTasks tasks shouldn't be present in the task graph: $npmYarnTasks " + + "as $allowImplicitDependOnNpmForTasks tasks were not activated\n" + + "Graph:\n${tasksGraphString(this)}") + } + } + } +} diff --git a/libraries/kotlin.test/js-ir/build.gradle.kts b/libraries/kotlin.test/js-ir/build.gradle.kts index f583b1baa92..60fcb0c73d9 100644 --- a/libraries/kotlin.test/js-ir/build.gradle.kts +++ b/libraries/kotlin.test/js-ir/build.gradle.kts @@ -4,6 +4,8 @@ plugins { kotlin("multiplatform") } +suppressYarnAndNpmForAssemble() + val commonMainSources by task { from( "$rootDir/libraries/kotlin.test/common/src/main", diff --git a/libraries/kotlin.test/wasm/build.gradle.kts b/libraries/kotlin.test/wasm/build.gradle.kts index fa42886cd12..623218bba3a 100644 --- a/libraries/kotlin.test/wasm/build.gradle.kts +++ b/libraries/kotlin.test/wasm/build.gradle.kts @@ -35,6 +35,8 @@ kotlin { } } +suppressYarnAndNpmForAssemble() + tasks.withType>().configureEach { kotlinOptions.freeCompilerArgs += listOf( "-Xallow-kotlin-package", diff --git a/libraries/stdlib/js-ir-minimal-for-test/build.gradle.kts b/libraries/stdlib/js-ir-minimal-for-test/build.gradle.kts index de75e93f9eb..9dd7229e25f 100644 --- a/libraries/stdlib/js-ir-minimal-for-test/build.gradle.kts +++ b/libraries/stdlib/js-ir-minimal-for-test/build.gradle.kts @@ -10,6 +10,8 @@ kotlin { } } +suppressYarnAndNpmForAssemble() + val commonMainSources by task { dependsOn(":kotlin-stdlib-js-ir:commonMainSources") from { diff --git a/libraries/stdlib/js-ir/build.gradle.kts b/libraries/stdlib/js-ir/build.gradle.kts index 87cf8995d69..5747a2023c2 100644 --- a/libraries/stdlib/js-ir/build.gradle.kts +++ b/libraries/stdlib/js-ir/build.gradle.kts @@ -1,5 +1,4 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCompile -import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.IR plugins { kotlin("multiplatform") @@ -17,6 +16,8 @@ kotlin { } } +suppressYarnAndNpmForAssemble() + val unimplementedNativeBuiltIns = (file("$rootDir/core/builtins/native/kotlin/").list().toSortedSet() - file("$rootDir/libraries/stdlib/js-ir/builtins/").list()) .map { "core/builtins/native/kotlin/$it" } @@ -169,3 +170,4 @@ val packFullRuntimeKLib by tasks.registering(Jar::class) { destinationDirectory.set(rootProject.buildDir.resolve("js-ir-runtime")) archiveFileName.set("full-runtime.klib") } + diff --git a/libraries/stdlib/wasm/build.gradle.kts b/libraries/stdlib/wasm/build.gradle.kts index faca759eef0..4138cd1b8f7 100644 --- a/libraries/stdlib/wasm/build.gradle.kts +++ b/libraries/stdlib/wasm/build.gradle.kts @@ -7,6 +7,8 @@ plugins { kotlin("multiplatform") } +suppressYarnAndNpmForAssemble() + description = "Kotlin Standard Library for experimental WebAssembly platform" val unimplementedNativeBuiltIns = diff --git a/plugins/atomicfu/atomicfu-runtime/build.gradle.kts b/plugins/atomicfu/atomicfu-runtime/build.gradle.kts index 58c6cf4185b..8f2f00f6576 100644 --- a/plugins/atomicfu/atomicfu-runtime/build.gradle.kts +++ b/plugins/atomicfu/atomicfu-runtime/build.gradle.kts @@ -28,6 +28,8 @@ kotlin { } } +suppressYarnAndNpmForAssemble() + configureCommonPublicationSettingsForGradle(signLibraryPublication) publishing {