Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add support for different Node versions (NVM support) #1357

Merged
merged 27 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/repotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ jobs:
repository: 'zoom/meetingsdk-vuejs-sample'
ref: 'v2.18.0'
path: 'repotests/meetingsdk-vuejs-sample'
- uses: actions/checkout@v4
with:
repository: 'kriasoft/react-app'
path: 'repotests/react-app'
- uses: actions/checkout@v4
with:
repository: 'patrickjuchli/basic-ftp'
path: 'repotests/basic-ftp'
- uses: actions/checkout@v4
with:
repository: 'Atome-FE/llama-node'
path: 'repotests/llama-node'
- uses: actions/checkout@v4
with:
repository: 'DIYgod/RSSHub'
path: 'repotests/RSSHub'
- uses: actions/checkout@v4
with:
repository: 'sveltejs/examples'
Expand Down Expand Up @@ -232,6 +248,26 @@ jobs:
run: |
curl -s "https://get.sdkman.io" | bash
if: runner.os != 'Windows'
- name: repotests react-app
run: |
FETCH_LICENSE=false bin/cdxgen.js -p -t nodejs8 repotests/react-app -o bomresults/react-app.json
node bin/evinse.js -i bomresults/react-app.json -o bomresults/react-app.evinse.json -l javascript --with-data-flow -p repotests/react-app
shell: bash
- name: repotests basic-ftp
run: |
FETCH_LICENSE=false bin/cdxgen.js -p -t nodejs10 repotests/basic-ftp -o bomresults/basic-ftp.json
node bin/evinse.js -i bomresults/basic-ftp.json -o bomresults/basic-ftp.evinse.json -l javascript --with-data-flow -p repotests/basic-ftp
shell: bash
- name: repotests llama-node
run: |
FETCH_LICENSE=false bin/cdxgen.js -p -t nodejs16 repotests/llama-node -o bomresults/llama-node.json
node bin/evinse.js -i bomresults/llama-node.json -o bomresults/llama-node.evinse.json -l javascript --with-data-flow -p repotests/llama-node
shell: bash
- name: repotests RSSHub
run: |
FETCH_LICENSE=false bin/cdxgen.js -p -t nodejs22 repotests/RSSHub -o bomresults/RSSHub.json
node bin/evinse.js -i bomresults/RSSHub.json -o bomresults/RSSHub.evinse.json -l javascript --with-data-flow -p repotests/RSSHub
shell: bash
- name: repotests java-sec-code
run: |
bin/cdxgen.js -p -t java repotests/java-sec-code -o bomresults/bom-java-sec-code-1.json --include-formulation --include-crypto
Expand Down
91 changes: 90 additions & 1 deletion envcontext.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Buffer } from "node:buffer";
import { spawnSync } from "node:child_process";
import { existsSync } from "node:fs";
import { homedir } from "node:os";
import { delimiter, join } from "node:path";
import { delimiter, dirname, join } from "node:path";
import process from "node:process";
import {
CARGO_CMD,
Expand Down Expand Up @@ -362,6 +362,21 @@ export function isSdkmanAvailable() {
return isSdkmanSetup;
}

/**
* Method to check if nvm is available.
*/
export function isNvmAvailable() {
let isNvmSetup = false;
const result = spawnSync(process.env.SHELL || "bash", ["-i", "-c", "nvm"], {
aryan-rajoria marked this conversation as resolved.
Show resolved Hide resolved
encoding: "utf-8",
shell: process.env.SHELL || true,
});
if (result.status === 0) {
aryan-rajoria marked this conversation as resolved.
Show resolved Hide resolved
isNvmSetup = true;
}
return isNvmSetup;
}

/**
* Method to check if a given sdkman tool is installed and available.
*
Expand Down Expand Up @@ -491,6 +506,80 @@ export function installSdkmanTool(toolType, toolName) {
return true;
}

/**
* Method to check if a given nvm tool is installed and available.
*
* @param {String} toolName Tool name with version. Eg: 22.0.2-tem
*
* @returns {String} path of nvm if present, otherwise false
*/
export function getNvmToolDirectory(toolName) {
const resultWhichNode = spawnSync(
process.env.SHELL || "bash",
["-i", "-c", `"nvm which ${toolName}"`],
{
encoding: "utf-8",
shell: process.env.SHELL || true,
},
);
if (DEBUG_MODE) {
if (console.stdout) {
console.log(resultWhichNode.stdout);
}
if (console.stderr) {
console.log(resultWhichNode.stderr);
}
}
if (resultWhichNode.status !== 0 || resultWhichNode.stderr) {
return;
}

return dirname(resultWhichNode.stdout.trim());
}

/**
* Method to return nvm tool path
*
* @param {String} toolVersion Tool name with version. Eg: 22.0.2-tem
aryan-rajoria marked this conversation as resolved.
Show resolved Hide resolved
*
* @returns {String} path of the tool if not found installs and then returns paths. false if encounters an error.
*/
export function getOrInstallNvmTool(toolVersion) {
const nvmNodePath = getNvmToolDirectory(toolVersion);
if (!nvmNodePath) {
// nvm couldn't directly use toolName so maybe needs to be installed
const resultInstall = spawnSync(
process.env.SHELL || "bash",
["-i", "-c", `"nvm install ${toolVersion}"`],
{
encoding: "utf-8",
shell: process.env.SHELL || true,
},
);

if (DEBUG_MODE) {
if (console.stdout) {
console.log(resultInstall.stdout);
}
if (console.stderr) {
console.log(resultInstall.stderr);
}
}

if (resultInstall.status !== 0) {
// There was some problem install the tool
// output has already been printed out
return false;
}
const nvmNodePath = getNvmToolDirectory(toolVersion);
if (nvmNodePath) {
return nvmNodePath;
}
return false;
}
return nvmNodePath;
}

/**
* Retrieve sdkman tool full name
*/
Expand Down
9 changes: 9 additions & 0 deletions envcontext.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
collectRustInfo,
getBranch,
getOriginUrl,
isNvmAvailable,
isNvmToolAvailable,
isSdkmanAvailable,
isSdkmanToolAvailable,
listFiles,
Expand Down Expand Up @@ -39,3 +41,10 @@ test("sdkman tests", () => {
expect(isSdkmanToolAvailable("java", "22.0.1-tem")).toBeTruthy();
}
});

test("nvm tests", () => {
if (process.env?.SDKMAN_VERSION) {
expect(isNvmAvailable()).toBeTruthy();
expect(isNvmToolAvailable("22")).toBeTruthy();
}
});
149 changes: 147 additions & 2 deletions pregen.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { mkdtempSync } from "node:fs";
import { spawn, spawnSync } from "node:child_process";
import { mkdtempSync, readdirSync } from "node:fs";
import { arch, platform, tmpdir } from "node:os";
import { join } from "node:path";
import { delimiter, join } from "node:path";
import {
SDKMAN_TOOL_ALIASES,
getNvmToolDirectory,
getOrInstallNvmTool,
installSdkmanTool,
isNvmAvailable,
isSdkmanAvailable,
} from "./envcontext.js";
import { DEBUG_MODE, hasAnyProjectType } from "./utils.js";
Expand All @@ -26,6 +30,7 @@ export function prepareEnv(filePath, options) {
}
// Check the pre-requisites for python
preparePythonEnv(filePath, options);
prepareNodeEnv(filePath, options);
}

/**
Expand Down Expand Up @@ -91,3 +96,143 @@ export function preparePythonEnv(filePath, options) {
}
}
}

/**
* Method to check and prepare the environment for node
*
* @param {String} filePath Path
* @param {Object} options CLI Options
*/
export function prepareNodeEnv(filePath, options) {
// check tool for windows
for (const pt of options.projectType) {
const nodeVersion = pt.replace(/\D/g, "");
if (
pt.startsWith("nodejs") &&
nodeVersion &&
!process.env.NODE_INSTALL_ARGS
) {
if (!isNvmAvailable()) {
if (process.env.NVM_DIR) {
// for scenarios where nvm is not present, but
// we have $NVM_DIR
// custom logic to find nvmNodePath
let nvmNodePath;
const possibleNodeDir = join(process.env.NVM_DIR, "versions", "node");

if (!tryLoadNvmAndInstallTool(nodeVersion)) {
console.log(
`Could not install Nodejs${nodeVersion}. There is a problem with loading nvm from ${process.env.NVM_DIR}`,
);
return;
}

const nodeVersionArray = readdirSync(possibleNodeDir, {
withFileTypes: true,
});
const nodeRe = new RegExp(`^v${nodeVersion}.`);
for (const nodeVersionsIter of nodeVersionArray) {
const fullPath = join(possibleNodeDir, nodeVersionsIter.name);
if (
nodeVersionsIter.isDirectory() &&
nodeRe.test(nodeVersionsIter.name)
) {
nvmNodePath = join(fullPath, "bin");
}
}
if (nvmNodePath) {
doNpmInstall(filePath, nvmNodePath);
} else {
console.log(
`"node version ${nodeVersion} was not found. Please install it with 'nvm install ${nodeVersion}"`,
);
return;
}
} else {
console.log(
"Install nvm by following the instructions at https://github.com/nvm-sh/nvm",
);
return;
}
}
// set path instead of nvm use
const nvmNodePath = getOrInstallNvmTool(nodeVersion);
doNpmInstall(filePath, nvmNodePath);
}
}
}

/**
* If NVM_DIR is in path, however nvm command is not loaded.
* it is possible that required nodeVersion is not installed.
* This function loads nvm and install the nodeVersion
*
* @param {String} nodeVersion required version number
*
* @returns {Boolean} true if successful, otherwise false
*/
export function tryLoadNvmAndInstallTool(nodeVersion) {
const NVM_DIR = process.env.NVM_DIR;

const command = `
if [ -f ${NVM_DIR}/nvm.sh ]; then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok for this PR, but this won't work in Windows powershell. Maybe this could be added in another PR.

. ${NVM_DIR}/nvm.sh
nvm install ${nodeVersion}
else
echo "NVM script not found at ${NVM_DIR}/nvm.sh"
exit 1
fi
`;

const spawnedShell = spawnSync(process.env.SHELL || "bash", ["-c", command], {
encoding: "utf-8",
shell: process.env.SHELL || true,
});

return result.status === 0;
}

/**
* This method installs and create package-lock.json
*
* @param {String} filePath Path
* @param {String} nvmNodePath Path to node version in nvm
*/
export function doNpmInstall(filePath, nvmNodePath) {
// we do not install if INSTALL_ARGS set false
if (process.env.NODE_INSTALL_ARGS === false) {
return;
}

const newPath = `${nvmNodePath}${delimiter}${process.env.PATH}`;

const resultNpmInstall = spawnSync(
process.env.SHELL || "bash",
[
"-i",
"-c",
`export PATH='${nvmNodePath}${delimiter}$PATH' && npm install --package-lock-only`,
],
aryan-rajoria marked this conversation as resolved.
Show resolved Hide resolved
{
encoding: "utf-8",
shell: process.env.SHELL || true,
cwd: filePath,
env: {
...process.env,
PATH: newPath,
},
},
);

Dismissed Show dismissed Hide dismissed
if (resultNpmInstall.status !== 0 || resultNpmInstall.stderr) {
// There was some problem with NpmInstall
if (DEBUG_MODE) {
if (console.stdout) {
console.log(result.stdout);
}
if (console.stderr) {
console.log(result.stderr);
}
}
}
}
20 changes: 20 additions & 0 deletions types/envcontext.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ export function collectEnvInfo(dir: any): {
* Method to check if sdkman is available.
*/
export function isSdkmanAvailable(): boolean;
/**
* Method to check if nvm is available.
*/
export function isNvmAvailable(): boolean;
/**
* Method to check if a given sdkman tool is installed and available.
*
Expand All @@ -163,6 +167,22 @@ export function isSdkmanToolAvailable(toolType: string, toolName: string): boole
* @returns {Boolean} true if the tool is available. false otherwise.
*/
export function installSdkmanTool(toolType: string, toolName: string): boolean;
/**
* Method to check if a given nvm tool is installed and available.
*
* @param {String} toolName Tool name with version. Eg: 22.0.2-tem
*
* @returns {String} path of nvm if present, otherwise false
*/
export function getNvmToolDirectory(toolName: string): string;
/**
* Method to return nvm tool path
*
* @param {String} toolVersion Tool name with version. Eg: 22.0.2-tem
*
* @returns {String} path of the tool if not found installs and then returns paths. false if encounters an error.
*/
export function getOrInstallNvmTool(toolVersion: string): string;
export const GIT_COMMAND: any;
export namespace SDKMAN_TOOL_ALIASES {
let java8: string;
Expand Down
2 changes: 1 addition & 1 deletion types/envcontext.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading