node-gradle / gradle-node-plugin

Gradle plugin for integrating NodeJS in your build. :rocket:
Apache License 2.0
616 stars 120 forks source link

yarnSetup task using node from path and not downloaded node #280

Closed ghost closed 1 year ago

ghost commented 1 year ago

I am having an issue where the yarnSetup task is using Node from the path instead of the downloaded instance of Node. While I don't think it should matter, the build environment is a container that is using an image that is based on an alpine image.

My build.gradle file contains the following configuration.

node {
    download = true
    yarnVersion = '1.7.0'
    version = '8.10.0'
}

A build results in the following error:

Task :[REDACTED]:yarnSetup FAILED npm WARN npm npm does not support Node.js v18.14.2 npm WARN npm You should probably upgrade to a newer version of node as we npm WARN npm can't make any promises that npm will work with this version. npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9. npm WARN npm You can find the latest version at https://nodejs.org/ npm ERR! cb.apply is not a function

npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2023-06-21T07_49_59_183Z-debug.log

FAILURE: Build failed with an exception.

And the aforementioned log contains:

cat /root/.npm/_logs/2023-06-21T07_49_59_183Z-debug.log 0 info it worked if it ends with ok 1 warn npm npm does not support Node.js v18.14.2 2 warn npm You should probably upgrade to a newer version of node as we 3 warn npm can't make any promises that npm will work with this version. 4 warn npm Supported releases of Node.js are the latest release of 4, 6, 7, 8, 9. 5 warn npm You can find the latest version at https://nodejs.org/ 6 verbose cli [ 6 verbose cli '/usr/bin/node', 6 verbose cli '/code/[REDACTED]/.gradle/nodejs/node-v8.10.0-linux-x64/bin/npm', 6 verbose cli 'install', 6 verbose cli '--global', 6 verbose cli '--no-save', 6 verbose cli '--prefix', 6 verbose cli '/code/[REDACTED]/.gradle/yarn/yarn-v1.7.0', 6 verbose cli 'yarn@1.7.0' 6 verbose cli ] 7 info using npm@5.6.0 8 info using node@v18.14.2 9 verbose npm-session 8d304f258da181fe 10 silly install loadCurrentTree 11 silly install readGlobalPackageData 12 http fetch GET 200 https://registry.npmjs.org/yarn 32ms (from cache) 13 silly pacote version manifest for yarn@1.7.0 fetched in 51ms 14 verbose stack TypeError: cb.apply is not a function 14 verbose stack at /code/[REDACTED]/.gradle/nodejs/node-v8.10.0-linux-x64/lib/node_modules/npm/node_modules/graceful-fs/polyfills.js:287:18 14 verbose stack at FSReqCallback.oncomplete (node:fs:208:5) 15 verbose cwd /code/[REDACTED] 16 verbose Linux 5.15.90.1-microsoft-standard-WSL2 17 verbose argv "/usr/bin/node" "/code/[REDACTED]/.gradle/nodejs/node-v8.10.0-linux-x64/bin/npm" "install" "--global" "--no-save" "--prefix" "/code/[REDACTED]/.gradle/yarn/yarn-v1.7.0" "yarn@1.7.0" 18 verbose node v18.14.2 19 verbose npm v5.6.0 20 error cb.apply is not a function 21 verbose exit [ 1, true ]

The plugin is using the Node version on the path (v18) but the NPM version from the downloaded version (v8).

deepy commented 1 year ago

There's a few things here at play, I've made doubly certain that the correct versions are being passed, and they are. yarnSetup is passed the expected .gradle\nodejs\node-v18.17.0-win-x64\npm.cmd in my tests and I can confirm it working in your output as well: .gradle/nodejs/node-v8.10.0-linux-x64/bin/npm Both npm.cmd and the shell script contain a similar setup, both will attempt to use node(with or without .exe) and fall back to system node if it fails:

#Excerpt from npm shell script, from 9 but iirc it's been like this for a long while
NODE_EXE="$basedir/node.exe"
if ! [ -x "$NODE_EXE" ]; then
  NODE_EXE="$basedir/node"
fi
if ! [ -x "$NODE_EXE" ]; then
  NODE_EXE=node
fi

If you invoke npm version it'll tell you which node version it used

I don't know why it's not working, it should be using the node next to it, can you try running ./.gradle/nodejs/node-v8.10.0-linux-x64/bin/node --version and see what that outputs? My immediate thought was that you're on a musl-based system like alpine, but afaik WSL2 is not

ghost commented 1 year ago

I had reason to revisit this scenario recently. The issue did turn out to be related to the Linux distro for the container, which was Alpine.

If the Alpine Linux instance has Node installed then the Gradle plugin ends up downloading the specified Node version but using the version installed via the package manager, apk add nodejs. This turns out to be because the Node version installed by the Gradle plugin cannot be executed but the one installed via the package manager can.

I was seeing the following when attempting to execute the version of node that added by the Gradle plugin. The /bin directly clearly did have the node executable, but infuriatingly the shell kept on saying "not found".

/myproject/.gradle/nodejs/node-v17.9.1-linux-x64/bin # ./node --version /bin/sh: ./node: not found

After determining that the downloaded instance could not be executed, I decided to add a compatibility layer for glibc programs, as suggested by the Alpine documentation. With the compatibility layer added, the Gradle plugin works as expected. What confuses me is why Node installed via the package manager did not seem to need that compatibility layer.