[Gradle, JS] Add npm support but default Yarn package manager left

Co-authored-by: Alexander Likhachev <Alexander.Likhachev@jetbrains.com>


^KT-64119 fixed
This commit is contained in:
Ilya Goncharov
2024-01-26 13:38:23 +00:00
committed by Space Team
parent f9348c69ba
commit d18660c8f1
57 changed files with 1609 additions and 717 deletions
@@ -112,10 +112,30 @@ class JsIrConfigurationCacheIT : KGPBaseTest() {
@DisplayName("KT-48241: configuration cache works with test dependencies")
@GradleTest
fun testTestDependencies(gradleVersion: GradleVersion) {
project("kotlin-js-project-with-test-dependencies", gradleVersion) {
assertSimpleConfigurationCacheScenarioWorks(
"assemble", "kotlinStorePackageLock",
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = false
)
),
executedTaskNames = listOf(":rootPackageJson")
)
}
}
@DisplayName("KT-48241: configuration cache works with test dependencies for yarn.lock")
@GradleTest
fun testTestDependenciesYarnLock(gradleVersion: GradleVersion) {
project("kotlin-js-project-with-test-dependencies", gradleVersion) {
assertSimpleConfigurationCacheScenarioWorks(
"assemble", "kotlinStoreYarnLock",
buildOptions = defaultBuildOptions,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = true
)
),
executedTaskNames = listOf(":rootPackageJson")
)
}
@@ -28,16 +28,47 @@ class JsSetupConfigurationCacheIT : KGPBaseTest() {
@DisplayName("Check Node.JS setup on different platforms")
@GradleTest
fun checkNodeJsSetup(gradleVersion: GradleVersion) {
project("kotlin-js-browser-project", gradleVersion) {
build("kotlinUpgradeYarnLock") {
assertTasksExecuted(":kotlinUpgradeYarnLock")
assertConfigurationCacheStored()
}
project(
"kotlin-js-browser-project",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = false
)
)
) {
checkNodeJsSetup("kotlinUpgradePackageLock")
}
}
build("kotlinUpgradeYarnLock") {
assertTasksUpToDate(":kotlinUpgradeYarnLock")
assertConfigurationCacheReused()
}
// hack to be run on Mac m*
@DisplayName("Check Node.JS setup on different platforms with Yarn")
@GradleTest
fun checkNodeJsSetupYarn(gradleVersion: GradleVersion) {
project(
"kotlin-js-browser-project",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = true
)
)
) {
checkNodeJsSetup("kotlinUpgradeYarnLock")
}
}
private fun TestProject.checkNodeJsSetup(
upgradeTask: String
) {
build(upgradeTask) {
assertTasksExecuted(":$upgradeTask")
assertConfigurationCacheStored()
}
build(upgradeTask) {
assertTasksUpToDate(":$upgradeTask")
assertConfigurationCacheReused()
}
}
}
@@ -12,12 +12,15 @@ import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.targets.js.dsl.Distribution
import org.jetbrains.kotlin.gradle.targets.js.ir.KLIB_TYPE
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.PACKAGE_LOCK_MISMATCH_MESSAGE
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.RESTORE_PACKAGE_LOCK_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.STORE_PACKAGE_LOCK_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.UPGRADE_PACKAGE_LOCK
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import org.jetbrains.kotlin.gradle.targets.js.npm.fromSrcPackageJson
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.STORE_YARN_LOCK_NAME
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.UPGRADE_YARN_LOCK
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.YARN_LOCK_MISMATCH_MESSAGE
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.testbase.TestVersions.Gradle.G_7_6
import org.jetbrains.kotlin.gradle.util.replaceText
@@ -34,6 +37,7 @@ import kotlin.test.assertTrue
@JsGradlePluginTests
class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
@DisplayName("TS type declarations are generated")
@GradleTest
fun generateDts(gradleVersion: GradleVersion) {
@@ -171,37 +175,6 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("js composite build works with yarn.lock persistence")
@GradleTest
@GradleTestVersions(minVersion = G_7_6)
fun testJsCompositeBuildWithUpgradeYarnLock(gradleVersion: GradleVersion) {
project("js-composite-build", gradleVersion) {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
subProject("lib").apply {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
}
subProject("base").apply {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
}
build("kotlinUpgradeYarnLock") {
assertTasksExecuted(":base:publicPackageJson")
assertTasksExecuted(":lib:lib-2:publicPackageJson")
assertTasksExecuted(":kotlinNpmInstall")
assertTasksExecuted(":kotlinUpgradeYarnLock")
}
build(":nodeTest") {
assertTasksUpToDate(":base:publicPackageJson")
assertTasksUpToDate(":lib:lib-2:publicPackageJson")
assertTasksUpToDate(":kotlinNpmInstall")
assertTasksExecuted(":kotlinStoreYarnLock")
}
}
}
@GradleTest
fun testJsIrIncrementalInParallel(gradleVersion: GradleVersion) {
project("kotlin-js-browser-project", gradleVersion) {
@@ -1029,7 +1002,15 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
@DisplayName("public NPM dependencies are included into package.json")
@GradleTest
fun testPackageJsonWithPublicNpmDependencies(gradleVersion: GradleVersion) {
project("npm-dependencies", gradleVersion) {
project(
"npm-dependencies",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = false
)
)
) {
build("jsJar") {
val archive = projectPath
.resolve("build/libs")
@@ -1097,8 +1078,8 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
build(UPGRADE_YARN_LOCK) {
assertTasksExecuted(":$UPGRADE_YARN_LOCK")
build(UPGRADE_PACKAGE_LOCK) {
assertTasksExecuted(":$UPGRADE_PACKAGE_LOCK")
}
build("jsJar") {
@@ -1216,10 +1197,18 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("yarn resolutions works")
@DisplayName("npm overrides works")
@GradleTest
fun testYarnResolution(gradleVersion: GradleVersion) {
project("kotlin-js-yarn-resolutions", gradleVersion) {
fun testNpmOverrides(gradleVersion: GradleVersion) {
project(
"kotlin-js-npm-overrides",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = false
)
)
) {
build("packageJson", "rootPackageJson", "kotlinNpmInstall") {
fun getPackageJson() =
projectPath.resolve("build/js")
@@ -1229,16 +1218,16 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
val name = "lodash"
val version = getPackageJson().resolutions?.get(name)
val version = getPackageJson().overrides?.get(name)
val requiredVersion = ">=1.0.0 <1.2.1 || >1.4.0 <2.0.0"
assertTrue("Root package.json must have resolution $name with version $requiredVersion, but $version found") {
assertTrue("Root package.json must override $name with version $requiredVersion, but $version found") {
version == requiredVersion
}
val react = "react"
val reactVersion = getPackageJson().resolutions?.get(react)
val reactVersion = getPackageJson().overrides?.get(react)
val requiredReactVersion = "16.0.0"
assertTrue("Root package.json must have resolution $react with version $requiredReactVersion, but $reactVersion found") {
assertTrue("Root package.json must override $react with version $requiredReactVersion, but $reactVersion found") {
reactVersion == requiredReactVersion
}
}
@@ -1374,176 +1363,6 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("Failing with yarn.lock update")
@GradleTest
fun testFailingWithYarnLockUpdate(gradleVersion: GradleVersion) {
project("kotlin-js-yarn-lock-project", gradleVersion) {
build(STORE_YARN_LOCK_NAME) {
assertTasksExecuted(":$STORE_YARN_LOCK_NAME")
}
projectPath.resolve("kotlin-js-store").deleteRecursively()
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().reportNewYarnLock = true
}
""".trimIndent()
}
buildAndFail(STORE_YARN_LOCK_NAME) {
assertTasksFailed(":$STORE_YARN_LOCK_NAME")
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockMismatchReport =
org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport.FAIL
}
""".trimIndent()
}
buildAndFail(STORE_YARN_LOCK_NAME) {
assertTasksFailed(":$STORE_YARN_LOCK_NAME")
}
// yarn.lock was not updated
buildAndFail(STORE_YARN_LOCK_NAME) {
assertTasksFailed(":$STORE_YARN_LOCK_NAME")
}
build(UPGRADE_YARN_LOCK) {
assertTasksExecuted(":$UPGRADE_YARN_LOCK")
}
buildGradleKts.modify {
val replaced = it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
replaced + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockMismatchReport =
org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport.WARNING
}
""".trimIndent()
}
build(STORE_YARN_LOCK_NAME) {
assertTasksExecuted(":$STORE_YARN_LOCK_NAME")
assertOutputContains(YARN_LOCK_MISMATCH_MESSAGE)
}
build(UPGRADE_YARN_LOCK) {
assertTasksExecuted(":$UPGRADE_YARN_LOCK")
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockMismatchReport =
org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport.NONE
}
""".trimIndent()
}
build(STORE_YARN_LOCK_NAME) {
assertTasksExecuted(":$STORE_YARN_LOCK_NAME")
assertOutputDoesNotContain(YARN_LOCK_MISMATCH_MESSAGE)
}
build(UPGRADE_YARN_LOCK) {
assertTasksExecuted(":$UPGRADE_YARN_LOCK")
}
buildGradleKts.modify {
it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
}
projectPath.resolve("kotlin-js-store").deleteRecursively()
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockMismatchReport =
org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport.NONE
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().reportNewYarnLock =
true
}
""".trimIndent()
}
build(STORE_YARN_LOCK_NAME) {
assertTasksExecuted(":$STORE_YARN_LOCK_NAME")
assertOutputDoesNotContain(YARN_LOCK_MISMATCH_MESSAGE)
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockMismatchReport =
org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport.FAIL
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().yarnLockAutoReplace =
true
}
""".trimIndent()
}
buildAndFail(STORE_YARN_LOCK_NAME) {
assertTasksFailed(":$STORE_YARN_LOCK_NAME")
}
//yarn.lock was updated
build(STORE_YARN_LOCK_NAME) {
assertTasksExecuted(":$STORE_YARN_LOCK_NAME")
}
buildGradleKts.modify {
it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
}
// check if everything ok without build/js/yarn.lock
build("clean") {
assertTasksExecuted(":clean")
}
build("clean") {
assertTasksUpToDate(":clean")
}
buildAndFail(STORE_YARN_LOCK_NAME) {
assertTasksFailed(":$STORE_YARN_LOCK_NAME")
}
projectPath.resolve("kotlin-js-store").deleteRecursively()
//check if independent tasks can be executed
build("help") {
assertTasksExecuted(":help")
}
}
}
@DisplayName("webpack configuration is valid")
@GradleTest
fun testWebpackConfig(gradleVersion: GradleVersion) {
@@ -1622,7 +1441,15 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
@DisplayName("Disable download should not download Node.JS and Yarn")
@GradleTest
fun testNodeJsAndYarnNotDownloaded(gradleVersion: GradleVersion) {
project("nodeJsDownload", gradleVersion) {
project(
"nodeJsDownload",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
jsOptions = defaultBuildOptions.jsOptions?.copy(
yarn = true
)
)
) {
buildGradleKts.modify {
it + "\n" +
"""
@@ -1640,71 +1467,6 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("Yarn.lock persistence")
@GradleTest
fun testYarnLockStore(gradleVersion: GradleVersion) {
project("nodeJsDownload", gradleVersion) {
build("assemble", "kotlinStoreYarnLock") {
assertFileExists(projectPath.resolve("kotlin-js-store").resolve("yarn.lock"))
assert(
projectPath
.resolve("kotlin-js-store")
.resolve("yarn.lock")
.readText() == projectPath.resolve("build/js/yarn.lock").readText()
)
}
}
}
@DisplayName("Yarn ignore scripts")
@GradleTest
fun testYarnIgnoreScripts(gradleVersion: GradleVersion) {
project("nodeJsDownload", gradleVersion) {
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("puppeteer", "11.0.0"))
}
""".trimIndent()
}
build("assemble", "kotlinNpmInstall") {
assert(
projectPath
.resolve("build")
.resolve("js")
.resolve("node_modules")
.resolve("puppeteer")
.resolve(".local-chromium")
.notExists()
) {
"Chromium should not be installed with --ignore-scripts"
}
}
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().ignoreScripts = false
}
""".trimIndent()
}
build("clean")
build("assemble", "kotlinNpmInstall") {
assertDirectoryExists(
projectPath
.resolve("build")
.resolve("js")
.resolve("node_modules")
.resolve("puppeteer")
.resolve(".local-chromium")
)
}
}
}
@DisplayName("js files from dependency are installed")
@GradleTest
fun testKotlinJsDependencyWithJsFiles(gradleVersion: GradleVersion) {
@@ -1754,7 +1516,7 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
}
}
@DisplayName("test package.jsom skipped with main package.json was up-to-date")
@DisplayName("test package.json skipped with main package.json was up-to-date")
@GradleTest
fun testPackageJsonSkippedWithUpToDatePackageJsons(gradleVersion: GradleVersion) {
project("kotlin-js-browser-library-project", gradleVersion) {
@@ -0,0 +1,464 @@
/*
* Copyright 2010-2020 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.targets.js.npm.LockCopyTask
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.PACKAGE_LOCK_MISMATCH_MESSAGE
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.RESTORE_PACKAGE_LOCK_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.STORE_PACKAGE_LOCK_NAME
import org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask.Companion.UPGRADE_PACKAGE_LOCK
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.testbase.TestVersions.Gradle.G_7_6
import org.junit.jupiter.api.DisplayName
import kotlin.io.path.deleteRecursively
import kotlin.io.path.notExists
import kotlin.io.path.readText
class NpmGradlePluginIT : PackageManagerGradlePluginIT() {
override val yarn: Boolean = false
override val plugin = "nodejs.NodeJsRootPlugin"
override val extension = "npm.NpmExtension"
override val upgradeTaskName: String = UPGRADE_PACKAGE_LOCK
override val storeTaskName = STORE_PACKAGE_LOCK_NAME
override val restoreTaskName = RESTORE_PACKAGE_LOCK_NAME
override val reportNewLockFile = "reportNewPackageLock"
override val lockMismatchReport = "packageLockMismatchReport"
override val lockFileAutoReplace = "packageLockAutoReplace"
override val mismatchReportType = "npm.LockFileMismatchReport"
override val lockFileName: String = LockCopyTask.PACKAGE_LOCK
override val setProperty: (String) -> String = { ".set($it)" }
}
class YarnGradlePluginIT : PackageManagerGradlePluginIT() {
override val yarn: Boolean = true
override val plugin: String = "yarn.YarnPlugin"
override val extension: String = "yarn.YarnRootExtension"
override val upgradeTaskName: String = YarnPlugin.UPGRADE_YARN_LOCK
override val storeTaskName = YarnPlugin.STORE_YARN_LOCK_NAME
override val restoreTaskName: String = YarnPlugin.RESTORE_YARN_LOCK_NAME
override val reportNewLockFile: String = "reportNewYarnLock"
override val lockMismatchReport: String = "yarnLockMismatchReport"
override val lockFileAutoReplace: String = "yarnLockAutoReplace"
override val mismatchReportType: String = "yarn.YarnLockMismatchReport"
override val lockFileName: String = LockCopyTask.YARN_LOCK
override val setProperty: (String) -> String = { " = $it" }
}
@JsGradlePluginTests
abstract class PackageManagerGradlePluginIT : KGPBaseTest() {
abstract val yarn: Boolean
abstract val plugin: String
abstract val extension: String
abstract val upgradeTaskName: String
abstract val storeTaskName: String
abstract val restoreTaskName: String
abstract val reportNewLockFile: String
abstract val lockMismatchReport: String
abstract val lockFileAutoReplace: String
abstract val mismatchReportType: String
abstract val lockFileName: String
abstract val setProperty: (String) -> String
override val defaultBuildOptions: BuildOptions
get() = super.defaultBuildOptions.copy(
jsOptions = super.defaultBuildOptions.jsOptions?.copy(
yarn = yarn
)
)
@DisplayName("js composite build works with lock file persistence")
@GradleTest
@GradleTestVersions(minVersion = G_7_6)
fun testJsCompositeBuildWithUpgradeLockFile(gradleVersion: GradleVersion) {
project("js-composite-build", gradleVersion) {
testJsCompositeBuildWithUpgradeLockFile(
upgradeTaskName,
storeTaskName
)
}
}
private fun TestProject.testJsCompositeBuildWithUpgradeLockFile(
upgradeTask: String,
storeTask: String,
) {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
subProject("lib").apply {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
}
subProject("base").apply {
buildGradleKts.modify(::transformBuildScriptWithPluginsDsl)
}
build(upgradeTask) {
assertTasksExecuted(":base:publicPackageJson")
assertTasksExecuted(":lib:lib-2:publicPackageJson")
assertTasksExecuted(":kotlinNpmInstall")
assertTasksExecuted(":$upgradeTask")
}
build(":nodeTest") {
assertTasksUpToDate(":base:publicPackageJson")
assertTasksUpToDate(":lib:lib-2:publicPackageJson")
assertTasksUpToDate(":kotlinNpmInstall")
assertTasksExecuted(":$storeTask")
}
}
@DisplayName("Failing with lock file update")
@GradleTest
fun testFailingWithLockFileUpdate(gradleVersion: GradleVersion) {
project("kotlin-js-package-lock-project", gradleVersion) {
testFailingWithLockFileUpdate(
storeTaskName = storeTaskName,
restoreTaskName = restoreTaskName,
upgradeTaskName = upgradeTaskName,
extension = extension,
reportNewLockFile = reportNewLockFile,
lockMismatchReport = lockMismatchReport,
lockFileAutoReplace = lockFileAutoReplace,
mismatchReport = mismatchReportType,
set = setProperty
)
}
}
private fun TestProject.testFailingWithLockFileUpdate(
storeTaskName: String,
restoreTaskName: String,
upgradeTaskName: String,
extension: String,
reportNewLockFile: String,
lockMismatchReport: String,
lockFileAutoReplace: String,
mismatchReport: String,
set: (String) -> String,
) {
build(storeTaskName) {
assertTasksSkipped(":$restoreTaskName")
assertTasksExecuted(":$storeTaskName")
}
projectPath.resolve(LockCopyTask.KOTLIN_JS_STORE).deleteRecursively()
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$reportNewLockFile${set("true")}
}
""".trimIndent()
}
buildAndFail(storeTaskName) {
assertTasksSkipped(":$restoreTaskName")
assertTasksFailed(":$storeTaskName")
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockMismatchReport${
set(
"org.jetbrains.kotlin.gradle.targets.js.$mismatchReport.FAIL"
)
}
}
""".trimIndent()
}
buildAndFail(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksFailed(":$storeTaskName")
}
// yarn.lock was not updated
buildAndFail(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksFailed(":$storeTaskName")
}
build(upgradeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$upgradeTaskName")
}
buildGradleKts.modify {
val replaced = it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
replaced + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockMismatchReport${
set(
"org.jetbrains.kotlin.gradle.targets.js.$mismatchReport.WARNING"
)
}
}
""".trimIndent()
}
build(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$storeTaskName")
assertOutputContains(PACKAGE_LOCK_MISMATCH_MESSAGE)
}
build(upgradeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$upgradeTaskName")
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockMismatchReport${
set(
"org.jetbrains.kotlin.gradle.targets.js.$mismatchReport.NONE"
)
}
}
""".trimIndent()
}
build(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$storeTaskName")
assertOutputDoesNotContain(PACKAGE_LOCK_MISMATCH_MESSAGE)
}
build(upgradeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$upgradeTaskName")
}
buildGradleKts.modify {
it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
}
projectPath.resolve(LockCopyTask.KOTLIN_JS_STORE).deleteRecursively()
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockMismatchReport${
set(
"org.jetbrains.kotlin.gradle.targets.js.$mismatchReport.NONE"
)
}
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$reportNewLockFile${
set(
"true"
)
}
}
""".trimIndent()
}
build(storeTaskName) {
assertTasksSkipped(":$restoreTaskName")
assertTasksExecuted(":$storeTaskName")
assertOutputDoesNotContain(PACKAGE_LOCK_MISMATCH_MESSAGE)
}
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("decamelize", "6.0.0"))
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockMismatchReport${
set(
"org.jetbrains.kotlin.gradle.targets.js.$mismatchReport.FAIL"
)
}
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().$lockFileAutoReplace${
set(
"true"
)
}
}
""".trimIndent()
}
buildAndFail(storeTaskName) {
assertTasksUpToDate(":$restoreTaskName")
assertTasksFailed(":$storeTaskName")
}
//yarn.lock was updated
build(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksExecuted(":$storeTaskName")
}
buildGradleKts.modify {
it.replace("implementation(npm(\"decamelize\", \"6.0.0\"))", "")
}
// check if everything ok without build/js/yarn.lock
build("clean") {
assertTasksExecuted(":clean")
}
build("clean") {
assertTasksUpToDate(":clean")
}
buildAndFail(storeTaskName) {
assertTasksExecuted(":$restoreTaskName")
assertTasksFailed(":$storeTaskName")
}
projectPath.resolve(LockCopyTask.KOTLIN_JS_STORE).deleteRecursively()
//check if independent tasks can be executed
build("help") {
assertTasksExecuted(":help")
}
}
@DisplayName("Lock file persistence")
@GradleTest
fun testLockStore(gradleVersion: GradleVersion) {
project("nodeJsDownload", gradleVersion) {
testLockStore(
storeTaskName,
lockFileName
)
}
}
private fun TestProject.testLockStore(
taskName: String,
lockFile: String,
) {
build("assemble", taskName) {
assertFileExists(projectPath.resolve(LockCopyTask.KOTLIN_JS_STORE).resolve(lockFile))
assert(
projectPath
.resolve(LockCopyTask.KOTLIN_JS_STORE)
.resolve(lockFile)
.readText() == projectPath.resolve("build/js/${lockFile}").readText()
)
}
}
@DisplayName("Package manager ignore scripts")
@GradleTest
fun testIgnoreScripts(gradleVersion: GradleVersion) {
project("nodeJsDownload", gradleVersion) {
testIgnoreScripts(
plugin,
extension,
setProperty
)
}
}
private fun TestProject.testIgnoreScripts(
plugin: String,
extension: String,
set: (String) -> String,
) {
buildGradleKts.modify {
it + "\n" +
"""
dependencies {
implementation(npm("puppeteer", "11.0.0"))
}
""".trimIndent()
}
build("assemble", "kotlinNpmInstall") {
assert(
projectPath
.resolve("build")
.resolve("js")
.resolve("node_modules")
.resolve("puppeteer")
.resolve(".local-chromium")
.notExists()
) {
"Chromium should not be installed with --ignore-scripts"
}
}
buildGradleKts.modify {
it + "\n" +
"""
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.$plugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.$extension>().ignoreScripts${set("false")}
}
""".trimIndent()
}
build("clean")
build("assemble", "kotlinNpmInstall") {
assertDirectoryExists(
projectPath
.resolve("build")
.resolve("js")
.resolve("node_modules")
.resolve("puppeteer")
.resolve(".local-chromium")
)
}
}
}
@@ -37,7 +37,7 @@ data class BuildOptions(
val buildCacheEnabled: Boolean = false,
val kaptOptions: KaptOptions? = null,
val androidVersion: String? = null,
val jsOptions: JsOptions? = null,
val jsOptions: JsOptions? = JsOptions(),
val buildReport: List<BuildReportType> = emptyList(),
val usePreciseJavaTracking: Boolean? = null,
val languageVersion: String? = null,
@@ -79,7 +79,8 @@ data class BuildOptions(
data class JsOptions(
val incrementalJs: Boolean? = null,
val incrementalJsKlib: Boolean? = null,
val incrementalJsIr: Boolean? = null
val incrementalJsIr: Boolean? = null,
val yarn: Boolean? = null,
)
data class NativeOptions(
@@ -163,6 +164,7 @@ data class BuildOptions(
jsOptions.incrementalJs?.let { arguments.add("-Pkotlin.incremental.js=$it") }
jsOptions.incrementalJsKlib?.let { arguments.add("-Pkotlin.incremental.js.klib=$it") }
jsOptions.incrementalJsIr?.let { arguments.add("-Pkotlin.incremental.js.ir=$it") }
jsOptions.yarn?.let { arguments.add("-Pkotlin.js.yarn=$it") }
}
if (androidVersion != null) {
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.targets.js.yarn.yarn
plugins {
kotlin("js")
}
@@ -10,6 +12,8 @@ kotlin {
}
}
yarn
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().downloadBaseUrl = null
}
@@ -10,13 +10,13 @@ repositories {
mavenCentral()
}
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().apply {
resolution("lodash") {
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.npm.NpmExtension>().apply {
override("lodash") {
include("^1.0.0")
exclude("~1.2.1", "1.3.0 - 1.4.0")
}
resolution("react", "16.0.0")
override("react", "16.0.0")
}
}
@@ -0,0 +1,4 @@
rootProject.name = "kotlin-js-npm-overrides"
include("base")
include("lib")
@@ -1,4 +0,0 @@
rootProject.name = "kotlin-js-yarn-resolutions"
include("base")
include("lib")
@@ -25,9 +25,9 @@ allprojects.forEach {
}
}
tasks.named<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask>("kotlinStoreYarnLock") {
tasks.named<org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask>("kotlinStorePackageLock") {
//A little hacky way to make yarn results
inputFile.fileValue(projectDir.resolve("yarnLockStub"))
inputFile.fileValue(projectDir.resolve("packageLockStub"))
}
kotlin {
@@ -5,9 +5,9 @@ plugins {
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().nodeVersion = "20.2.0"
tasks.named<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask>("kotlinStoreYarnLock") {
tasks.named<org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask>("kotlinStorePackageLock") {
//A little hacky way to make yarn results
inputFile.fileValue(projectDir.resolve("yarnLockStub"))
inputFile.fileValue(projectDir.resolve("packageLockStub"))
}
}
@@ -20,9 +20,9 @@ allprojects.forEach {
}
}
tasks.named<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask>("kotlinStoreYarnLock") {
tasks.named<org.jetbrains.kotlin.gradle.targets.js.npm.LockCopyTask>("kotlinStorePackageLock") {
//A little hacky way to make yarn results
inputFile.fileValue(projectDir.resolve("yarnLockStub"))
inputFile.fileValue(projectDir.resolve("packageLockStub"))
}
repositories {