8000 Merge pull request #3671 from dmichon-msft/install-run-lockfile · mstomar698/rushstack@2308280 · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit 2308280

Browse files
authored
Merge pull request microsoft#3671 from dmichon-msft/install-run-lockfile
[rush] Support passing a lockfile to install-run
2 parents 8263837 + 844dab4 commit 2308280

File tree

3 files changed

+67
-18
lines changed

3 files changed

+67
-18
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/rush",
5+
"comment": "Support passing a lockfile to \"install-run.js\" and \"install-run-rush.js\" to ensure stable installation on CI.",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@microsoft/rush"
10+
}

libraries/rush-lib/src/scripts/install-run-rush.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525

2626
const PACKAGE_NAME: string = '@microsoft/rush';
2727
const RUSH_PREVIEW_VERSION: string = 'RUSH_PREVIEW_VERSION';
28+
const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE: 'INSTALL_RUN_RUSH_LOCKFILE_PATH' =
29+
'INSTALL_RUN_RUSH_LOCKFILE_PATH';
2830

2931
function _getRushVersion(logger: ILogger): string {
3032
const rushPreviewVersion: string | undefined = process.env[RUSH_PREVIEW_VERSION];
@@ -103,7 +105,14 @@ function _run(): void {
103105
const version: string = _getRushVersion(logger);
104106
logger.info(`The rush.json configuration requests Rush version ${version}`);
105107

106-
return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs);
108+
const lockFilePath: string | undefined = process.env[INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE];
109+
if (lockFilePath) {
110+
logger.info(
111+
`Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.`
112+
);
113+
}
114+
115+
return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath);
107116
});
108117
}
109118

libraries/rush-lib/src/scripts/install-run.ts

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { IPackageJson } from '@rushstack/node-core-library';
2020

2121
export const RUSH_JSON_FILENAME: string = 'rush.json';
2222
const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME: string = 'RUSH_TEMP_FOLDER';
23+
const INSTALL_RUN_LOCKFILE_PATH_VARIABLE: 'INSTALL_RUN_LOCKFILE_PATH' = 'INSTALL_RUN_LOCKFILE_PATH';
2324
const INSTALLED_FLAG_FILENAME: string = 'installed.flag';
2425
const NODE_MODULES_FOLDER_NAME: string = 'node_modules';
2526
const PACKAGE_JSON_FILENAME: string = 'package.json';
@@ -334,29 +335,50 @@ function _isPackageAlreadyInstalled(packageInstallFolder: string): boolean {
334335
}
335336
}
336337

338+
/**
339+
* Delete a file. Fail silently if it does not exist.
340+
*/
341+
function _deleteFile(file: string): void {
342+
try {
343+
fs.unlinkSync(file);
344+
} catch (err) {
345+
if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
346+
throw err;
347+
}
348+
}
349+
}
350+
337351
/**
338352
* Removes the following files and directories under the specified folder path:
339353
* - installed.flag
340354
* -
341355
* - node_modules
342356
*/
343-
function _cleanInstallFolder(rushTempFolder: string, packageInstallFolder: string): void {
357+
function _cleanInstallFolder(
358+
rushTempFolder: string,
359+
packageInstallFolder: string,
360+
lockFilePath: string | undefined
361+
): void {
344362
try {
345363
const flagFile: string = path.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME);
346-
if (fs.existsSync(flagFile)) {
347-
fs.unlinkSync(flagFile);
348-
}
364+
_deleteFile(flagFile);
349365

350366
const packageLockFile: string = path.resolve(packageInstallFolder, 'package-lock.json');
351-
if (fs.existsSync(packageLockFile)) {
352-
fs.unlinkSync(packageLockFile);
353-
}
367+
if (lockFilePath) {
368+
fs.copyFileSync(lockFilePath, packageLockFile);
369+
} else {
370+
// Not running `npm ci`, so need to cleanup
371+
_deleteFile(packageLockFile);
354372

355-
const nodeModulesFolder: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME);
356-
if (fs.existsSync(nodeModulesFolder)) {
357-
const rushRecyclerFolder: string = _ensureAndJoinPath(rushTempFolder, 'rush-recycler');
373+
const nodeModulesFolder: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME);
374+
if (fs.existsSync(nodeModulesFolder)) {
375+
const rushRecyclerFolder: string = _ensureAndJoinPath(rushTempFolder, 'rush-recycler');
358376

359-
fs.renameSync(nodeModulesFolder, path.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`));
377+
fs.renameSync(
378+
nodeModulesFolder,
379+
path.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)
380+
);
381+
}
360382
}
361383
} catch (e) {
362384
throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`);
@@ -386,18 +408,24 @@ function _createPackageJson(packageInstallFolder: string, name: string, version:
386408
/**
387409
* Run "npm install" in the package install folder.
388410
*/
389-
function _installPackage(logger: ILogger, packageInstallFolder: string, name: string, version: string): void {
411+
function _installPackage(
412+
logger: ILogger,
413+
packageInstallFolder: string,
414+
name: string,
415+
version: string,
416+
command: 'install' | 'ci'
417+
): void {
390418
try {
391419
logger.info(`Installing ${name}...`);
392420
const npmPath: string = getNpmPath();
393-
const result: childProcess.SpawnSyncReturns<Buffer> = childProcess.spawnSync(npmPath, ['install'], {
421+
const result: childProcess.SpawnSyncReturns<Buffer> = childProcess.spawnSync(npmPath, [command], {
394422
stdio: 'inherit',
395423
cwd: packageInstallFolder,
396424
env: process.env
397425
});
398426

399427
if (result.status !== 0) {
400-
throw new Error('"npm install" encountered an error');
428+
throw new Error(`"npm ${command}" encountered an error`);
401429
}
402430

403431
logger.info(`Successfully installed ${name}@${version}`);
@@ -432,7 +460,8 @@ export function installAndRun(
432460
packageName: string,
433461
packageVersion: string,
434462
packageBinName: string,
435-
packageBinArgs: string[]
463+
packageBinArgs: string[],
464+
lockFilePath: string | undefined = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]
436465
): number {
437466
const rushJsonFolder: string = findRushJsonFolder();
438467
const rushCommonFolder: string = path.join(rushJsonFolder, 'common');
@@ -445,13 +474,14 @@ export function installAndRun(
445474

446475
if (!_isPackageAlreadyInstalled(packageInstallFolder)) {
447476
// The package isn't already installed
448-
_cleanInstallFolder(rushTempFolder, packageInstallFolder);
477+
_cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath);
449478

450479
const sourceNpmrcFolder: string = path.join(rushCommonFolder, 'config', 'rush');
451480
_syncNpmrc(logger, sourceNpmrcFolder, packageInstallFolder);
452481

453482
_createPackageJson(packageInstallFolder, packageName, packageVersion);
454-
_installPackage(logger, packageInstallFolder, packageName, packageVersion);
483+
const command: 'install' | 'ci' = lockFilePath ? 'ci' : 'install';
484+
_installPackage(logger, packageInstallFolder, packageName, packageVersion, command);
455485
_writeFlagFile(packageInstallFolder);
456486
}
457487

0 commit comments

Comments
 (0)
0