Skip to content

Commit 9ab1206

Browse files
committed
finally!!!
1 parent 9dcd462 commit 9ab1206

File tree

7 files changed

+742
-3597
lines changed

7 files changed

+742
-3597
lines changed

.puppeteerrc.cjs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
15
const {join} = require('path');
26

3-
const isCI = process.env.TEAMCITY_VERSION || process.env.GITHUB_ACTIONS;
7+
const isTC = process.env.TEAMCITY_VERSION;
8+
const isGA = process.env.GITHUB_ACTIONS;
49

5-
if (isCI) {
10+
if (isTC !== undefined || isGA !== undefined) {
611
/**
712
* @type {import("puppeteer").Configuration}
813
*/

docs/environment.md

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,24 +366,71 @@ Here is a 'simple' guide for solving problems:
366366
- Kotlin/Js or Kotlin/Wasm
367367
- `kotlinUpgradePackageLock` or `kotlinWasmUpgradePackageLock` (and also `kotlinNpmInstall` or `kotlinWasmNpmInstall`)
368368
have a funny tendency to fail sometimes, and you don't know why.
369+
<br/>
369370
I'll tell you!
371+
<br/>
370372
We use proxy repos, and sometimes dependencies get downloaded from the wrong source.
371373
Make sure ALL urls in `package-lock.json` files start with `https://packages.jetbrains.team/npm/p/krpc/build-deps/`.
374+
<br/>
372375
If something doesn't work, your steps are:
373376
- Delete `package-lock.json` file
374377
- Delete `<REPO_ROOT>/build/js` / `<REPO_ROOT>/build/wasm`
375378
- Run `kotlinUpgradePackageLock` / `kotlinWasmUpgradePackageLock`
376-
- If the problem persists:
377-
- Check that `<REPO_ROOT>/build/<target>/.npmrc` AND `<REPO_ROOT>/build/<target>/.yarnrc` are present
378-
- Check that `.yarnrc` contains one line: `registry: "https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
379-
- Check that `.npmrc` contains the following lines:
380-
- `registry="https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
381-
- `always-auth=true`
382-
- `save-exact=true`
383-
- `//packages.jetbrains.team/npm/p/krpc/build-deps/:_authToken=<your_auth_token>`,
379+
- If the problem persists:
380+
- Check that `<REPO_ROOT>/build/<target>/.npmrc` AND `<REPO_ROOT>/build/<target>/.yarnrc` are present
381+
- Check that `.yarnrc` contains one line: `registry: "https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
382+
- Check that `.npmrc` contains the following lines:
383+
- `registry="https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
384+
- `always-auth=true`
385+
- `save-exact=true`
386+
- `//packages.jetbrains.team/npm/p/krpc/build-deps/:_authToken=<your_auth_token>`,
384387
where `<your_auth_token>` is from the [proxy-repositories.md](proxy-repositories.md) guide.
385-
- Check that `<USER_HOME>/.npmrc` / `<USER_HOME>/.yarnrc` don't interfere
388+
- Check that `<USER_HOME>/.npmrc` / `<USER_HOME>/.yarnrc` don't interfere
386389
command to debug. Replace versions of tools if needed.
390+
- When you get the following error — `puppeteer` failed to run the installation script.
391+
Reasons vary, try updating the version to a newer one,
392+
check the [.puppeteerrc.cjs](../.puppeteerrc.cjs) and [chrome_bin.js](../karma/chrome_bin.js) files if they are valid js.
393+
394+
For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
395+
at ChromeLauncher.resolveExecutablePath (/rpc/build/js/packages/kotlinx-rpc-utils-test/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:295:27)
396+
397+
- When the previous error is gone, you may get the next one.
398+
399+
Errors occurred during launch of browser for testing.
400+
- ChromeHeadless
401+
Please make sure that you have installed browsers.
402+
Or change it via
403+
browser {
404+
testTask {
405+
useKarma {
406+
useFirefox()
407+
useChrome()
408+
useSafari()
409+
}
410+
}
411+
}
412+
This means the `puppeteer` failed to locate Chrome.
413+
Either the cache dir is wrong (check [.puppeteerrc.cjs](../.puppeteerrc.cjs) file) or it really isn't there.
414+
<br/>
415+
Reasons again vary.
416+
When `npm` installs `puppeteer`, it should execute script to install the browser too
417+
(On CI to the `<ROOT_DIR>/.puppeteer/browsers` directory).
418+
This absence may be caused by the `--ignore-scripts` flag.
419+
Check the clean installation (`rm -rf build && ./gradlew clean cleanJsBrowserTest`) with `--debug` flag.
420+
(Something like `./gradlew jsBrowserTest --debug`).
421+
**IMPORTANT: run in docker with `TEAMCITY_VERSION` env var set, if you are chasing a CI fail**.
422+
<br/>
423+
The property is set in [npm.kt](../gradle-conventions/src/main/kotlin/util/tasks/npm.kt), see `ignoreScripts`,
424+
it should be `false`.
425+
<br/>
426+
If this is not the case, check the debug log for other `node`-related issues.
427+
Try installing browsers manually: `~/.gradle/nodejs/node-v22.0.0-linux-x64/bin/node build/js/node_modules/puppeteer/install.mjs`
428+
If this works — problem is somewhere in KGP and probably your configs.
429+
Check that your config (like ones with `ignoreScript`) are actually applied,
430+
as they use on demand execution and may target wrong plugin or extension and never be executed.
431+
<br/>
432+
**Bonus**: it may not be installed, because npm install doesn't do this.
433+
See the long comment in [npm.kt](../gradle-conventions/src/main/kotlin/util/tasks/npm.kt).
387434

388435
Something doesn't work, and you are sure it's not your fault? Report it appropriately! Don't be lazy.
389436

gradle-conventions/src/main/kotlin/util/tasks/npm.kt

Lines changed: 99 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,41 @@ package util.tasks
66

77
import org.gradle.api.GradleException
88
import org.gradle.api.Project
9+
import org.gradle.api.Task
10+
import org.gradle.api.tasks.Delete
11+
import org.gradle.api.tasks.Exec
12+
import org.gradle.api.tasks.TaskProvider
913
import org.gradle.kotlin.dsl.*
1014
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnvSpec
15+
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
1116
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
1217
import org.jetbrains.kotlin.gradle.targets.js.npm.BaseNpmExtension
1318
import org.jetbrains.kotlin.gradle.targets.js.npm.LockFileMismatchReport
19+
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmExtension
1420
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsEnvSpec
21+
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsRootExtension
1522
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsRootPlugin
23+
import org.jetbrains.kotlin.gradle.targets.wasm.npm.WasmNpmExtension
1624
import org.jetbrains.kotlin.gradle.targets.web.nodejs.BaseNodeJsEnvSpec
25+
import org.jetbrains.kotlin.gradle.targets.web.nodejs.BaseNodeJsRootExtension
1726
import org.jetbrains.kotlin.gradle.targets.web.nodejs.CommonNodeJsRootPlugin
18-
import org.jetbrains.kotlin.gradle.targets.web.npm.CommonNpmResolverPlugin
1927
import util.other.optionalProperty
2028
import util.other.spacePassword
2129
import util.other.useProxyRepositories
2230
import java.io.File
2331

32+
const val PUPPETEER_BROWSERS_DIR = ".puppeteer"
33+
2434
private inline fun <
2535
reified Plugin : CommonNodeJsRootPlugin,
26-
reified Spec : BaseNodeJsEnvSpec
27-
> Project.registerExecuteNpmLoginTask(
36+
reified Spec : BaseNodeJsEnvSpec,
37+
reified RootExtension : BaseNodeJsRootExtension,
38+
> Project.registerCustomNpmTasks(
2839
target: String,
29-
npmInstallTaskName: String,
3040
useProxy: Boolean,
3141
) {
3242
val capitalizedTarget = target.replaceFirstChar { it.titlecase() }
33-
val task = tasks.register("execute${capitalizedTarget}NpmLogin") {
43+
val login = tasks.register("execute${capitalizedTarget}NpmLogin") {
3444
if (!useProxyRepositories) {
3545
return@register
3646
}
@@ -75,46 +85,106 @@ private inline fun <
7585
}
7686

7787
plugins.withType<Plugin>().configureEach {
78-
rootProject.extensions.configure<Spec> {
88+
extensions.configure<Spec> {
7989
download = true
8090

8191
if (useProxy) {
8292
downloadBaseUrl = "https://packages.jetbrains.team/files/p/krpc/build-deps/"
8393
}
84-
}
8594

86-
tasks.named(npmInstallTaskName).configure {
87-
dependsOn(task)
95+
val nodeExecutable = executable
96+
97+
extensions.configure<RootExtension> {
98+
/**
99+
* Long story short:
100+
* We can use Yarn because of this: https://youtrack.jetbrains.com/issue/KT-78504
101+
* So: `kotlin.js.yarn=false`
102+
*
103+
* When we use `npm` instead, it runs `npm install` task.
104+
* That should install `puppeteer` package, which should run its script `install.mjs`.
105+
* That script installs browsers for tests.
106+
*
107+
* If we pass `--ignore-scripts` to npm, the script won't be executed.
108+
* KGP does it by default.
109+
* So we set `ignoreScripts = false`.
110+
* We set it for `NpmExtension` and `WasmNpmExtension` in `NodeJsRootPlugin` and `WasmNodeJsRootPlugin`
111+
* respectively (and not their common supertype because it will not work)
112+
*
113+
* And this approach worked for Yarn.
114+
* Script was executed, browsers were installed.
115+
*
116+
* For some reason, for `npm` it didn't work.
117+
* Even with a proper flag (which I checked with a --debug flag).
118+
*
119+
* So we need to run the script manually AFTER `kotlinNpmInstall` (or `kotlinWasmNpmInstall`).
120+
* But also, BEFORE every other action that comes after `kotlinNpmInstall` (or `kotlinWasmNpmInstall`),
121+
* as otherwise there will be race in parallel tasks execution.
122+
*
123+
* Hence, all shenanigans.
124+
*/
125+
val puppeteerInstall = tasks.register<Exec>("puppeteerInstall$capitalizedTarget") {
126+
commandLine(nodeExecutable.get(), "build/$target/node_modules/puppeteer/install.mjs")
127+
workingDir = rootProject.projectDir
128+
129+
// keep in sync with <ROOT>/.puppeteer.cjs
130+
outputs.dir(rootProject.projectDir.resolve(PUPPETEER_BROWSERS_DIR).resolve("browsers"))
131+
}
132+
133+
npmInstallTaskProvider.configure {
134+
dependsOn(login)
135+
finalizedBy(puppeteerInstall)
136+
}
137+
138+
tasks.matching { task ->
139+
task.dependsOn.any { dependency ->
140+
when (dependency) {
141+
is Task -> dependency == npmInstallTaskProvider.get()
142+
is TaskProvider<*> -> dependency == npmInstallTaskProvider
143+
is String -> dependency == npmInstallTaskProvider.name
144+
else -> false
145+
}
146+
}
147+
}.configureEach {
148+
dependsOn(puppeteerInstall)
149+
}
150+
}
88151
}
89152
}
90153
}
91154

155+
@Suppress("UnusedReceiverParameter")
156+
fun BaseNpmExtension.configureNpmExtension(useProxy: Boolean, kotlinMasterBuild: Boolean) {
157+
// todo it still doesn't work for an unknown reason, see 'puppeteerInstall*' tasks above
158+
ignoreScripts = false // if true - puppeteer won't install browsers
159+
160+
packageLockMismatchReport = if (useProxy && !kotlinMasterBuild) {
161+
LockFileMismatchReport.FAIL
162+
} else {
163+
LockFileMismatchReport.WARNING
164+
}
165+
}
166+
92167
fun Project.configureNpm() {
93168
val kotlinMasterBuild by optionalProperty()
94169
val useProxy = useProxyRepositories
95170

96-
registerExecuteNpmLoginTask<NodeJsRootPlugin, NodeJsEnvSpec>(
97-
target = "js",
98-
npmInstallTaskName = "kotlinNpmInstall",
99-
useProxy = useProxy,
100-
)
101-
102-
registerExecuteNpmLoginTask<WasmNodeJsRootPlugin, WasmNodeJsEnvSpec>(
103-
target = "wasm",
104-
npmInstallTaskName = "kotlinWasmNpmInstall",
105-
useProxy = useProxy,
106-
)
171+
registerCustomNpmTasks<NodeJsRootPlugin, NodeJsEnvSpec, NodeJsRootExtension>("js", useProxy)
172+
registerCustomNpmTasks<WasmNodeJsRootPlugin, WasmNodeJsEnvSpec, WasmNodeJsRootExtension>("wasm", useProxy)
107173

108174
// necessary for CI js tests
109-
rootProject.plugins.withType<CommonNpmResolverPlugin> {
110-
rootProject.extensions.configure<BaseNpmExtension> {
111-
ignoreScripts = false
112-
113-
packageLockMismatchReport = if (useProxy && !kotlinMasterBuild) {
114-
LockFileMismatchReport.FAIL
115-
} else {
116-
LockFileMismatchReport.WARNING
117-
}
175+
rootProject.plugins.withType<NodeJsRootPlugin> {
176+
rootProject.extensions.configure<NpmExtension> {
177+
configureNpmExtension(useProxy, kotlinMasterBuild)
118178
}
119179
}
180+
181+
rootProject.plugins.withType<WasmNodeJsRootPlugin> {
182+
rootProject.extensions.configure<WasmNpmExtension> {
183+
configureNpmExtension(useProxy, kotlinMasterBuild)
184+
}
185+
}
186+
187+
tasks.named<Delete>("clean") {
188+
delete(project.layout.projectDirectory.dir(PUPPETEER_BROWSERS_DIR))
189+
}
120190
}

karma/chrome_bin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
config.set({

0 commit comments

Comments
 (0)