fix(devkit): ensurePackage should obey npmrc and yarnrc.yml (#16652)

This commit is contained in:
Craigory Coppola 2023-05-01 17:28:12 -04:00 committed by GitHub
parent 179930fe18
commit 2381dd3cf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 39 deletions

View File

@ -1,34 +1,34 @@
{ {
"extends": "../../.eslintrc", "extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-restricted-imports": [
"error",
{
"paths": [
"@nx/workspace",
"@angular-devkit/core",
"@angular-devkit/architect",
"@angular-devkit/schematics"
],
"patterns": [
{
"group": ["nx/**/*"],
"message": "Use requireNx() from packages/devkit/nx.ts OR use a type import instead.",
"allowTypeImports": true
},
{
"group": ["@nx/devkit/**/*"],
"message": "Use a relative import"
}
]
}
]
},
"ignorePatterns": ["!**/*"], "ignorePatterns": ["!**/*"],
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {} "rules": {
"@typescript-eslint/explicit-module-boundary-types": ["error"],
"@typescript-eslint/no-restricted-imports": [
"error",
{
"paths": [
"@nx/workspace",
"@angular-devkit/core",
"@angular-devkit/architect",
"@angular-devkit/schematics"
],
"patterns": [
{
"group": ["nx/**/*"],
"message": "Use requireNx() from packages/devkit/nx.ts OR use a type import instead.",
"allowTypeImports": true
},
{
"group": ["@nx/devkit/**/*"],
"message": "Use a relative import"
}
]
}
]
}
}, },
{ {
"files": ["*.spec.ts"], "files": ["*.spec.ts"],
@ -38,9 +38,7 @@
}, },
{ {
"files": ["*.ts", "*.tsx"], "files": ["*.ts", "*.tsx"],
"rules": { "rules": {}
"@typescript-eslint/explicit-module-boundary-types": ["error"]
}
}, },
{ {
"files": ["*.js", "*.jsx"], "files": ["*.js", "*.jsx"],

View File

@ -1,7 +1,20 @@
export function requireNx(): typeof import('nx/src/devkit-exports') { // After Nx v18, this can be removed and replaced with either:
// - import {} from 'nx/src/devkit-exports'
// - import {} from 'nx/src/devkit-internals'
export function requireNx(): typeof import('nx/src/devkit-exports') &
Partial<typeof import('nx/src/devkit-internals')> {
try { try {
return require('nx/src/devkit-exports'); let result = { ...require('nx/src/devkit-exports') };
try {
result = {
...result,
// Remove in Nx v18, devkit should not support Nx v16.0.2 at that point.
...require('nx/src/devkit-internals'),
};
} catch {}
return result;
} catch { } catch {
// Remove in Nx V17, devkit should not support Nx < 16 at that point.
return require('./nx-reexports-pre16'); return require('./nx-reexports-pre16');
} }
} }

View File

@ -17,6 +17,7 @@ const {
getPackageManagerCommand, getPackageManagerCommand,
workspaceRoot, workspaceRoot,
detectPackageManager, detectPackageManager,
createTempNpmDirectory,
} = requireNx(); } = requireNx();
const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION'; const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION';
@ -450,7 +451,9 @@ export function ensurePackage<T extends any = any>(
); );
} }
const tempDir = dirSync().name; const { dir: tempDir } = createTempNpmDirectory?.() ?? {
dir: dirSync().name,
};
console.log(`Fetching ${pkg}...`); console.log(`Fetching ${pkg}...`);
const packageManager = detectPackageManager(); const packageManager = detectPackageManager();

View File

@ -0,0 +1,6 @@
/**
* Note to developers: STOP! These exports are available via requireNx in @nx/devkit.
*
* These may not be available in certain version of Nx, so be sure to check them first.
*/
export { createTempNpmDirectory } from './utils/package-manager';

View File

@ -1,12 +1,13 @@
import { exec, execSync } from 'child_process'; import { exec, execSync } from 'child_process';
import { copyFileSync, existsSync } from 'fs'; import { copyFileSync, existsSync } from 'fs';
import { remove } from 'fs-extra'; import { remove } from 'fs-extra';
import { dirname, join } from 'path'; import { dirname, join, relative } from 'path';
import { dirSync } from 'tmp'; import { dirSync } from 'tmp';
import { promisify } from 'util'; import { promisify } from 'util';
import { writeJsonFile } from './fileutils'; import { writeJsonFile } from './fileutils';
import { readModulePackageJson } from './package-json'; import { readModulePackageJson } from './package-json';
import { gte, lt } from 'semver'; import { gte, lt } from 'semver';
import { workspaceRoot } from './workspace-root';
const execAsync = promisify(exec); const execAsync = promisify(exec);
@ -118,16 +119,35 @@ export function getPackageManagerVersion(
* Checks for a project level npmrc file by crawling up the file tree until * Checks for a project level npmrc file by crawling up the file tree until
* hitting a package.json file, as this is how npm finds them as well. * hitting a package.json file, as this is how npm finds them as well.
*/ */
export function checkForNPMRC( export function findFileInPackageJsonDirectory(
file: string,
directory: string = process.cwd() directory: string = process.cwd()
): string | null { ): string | null {
while (!existsSync(join(directory, 'package.json'))) { while (!existsSync(join(directory, 'package.json'))) {
directory = dirname(directory); directory = dirname(directory);
} }
const path = join(directory, '.npmrc'); const path = join(directory, file);
return existsSync(path) ? path : null; return existsSync(path) ? path : null;
} }
export function copyPackageManagerConfigurationFiles(
root: string,
destination: string
) {
for (const packageManagerConfigFile of ['.npmrc', '.yarnrc', '.yarnrc.yml']) {
// f is an absolute path, including the {workspaceRoot}.
const f = findFileInPackageJsonDirectory(packageManagerConfigFile, root);
if (f) {
// Destination should be the same relative path from the {workspaceRoot},
// but now relative to the destination. `relative` makes `{workspaceRoot}/some/path`
// look like `./some/path`, and joining that gets us `{destination}/some/path
const destinationPath = join(destination, relative(root, f));
// Copy config file if it exists, so that the package manager still follows it.
copyFileSync(f, destinationPath);
}
}
}
/** /**
* Creates a temporary directory where you can run package manager commands safely. * Creates a temporary directory where you can run package manager commands safely.
* *
@ -140,11 +160,7 @@ export function createTempNpmDirectory() {
// A package.json is needed for pnpm pack and for .npmrc to resolve // A package.json is needed for pnpm pack and for .npmrc to resolve
writeJsonFile(`${dir}/package.json`, {}); writeJsonFile(`${dir}/package.json`, {});
const npmrc = checkForNPMRC(); copyPackageManagerConfigurationFiles(workspaceRoot, dir);
if (npmrc) {
// Copy npmrc if it exists, so that npm still follows it.
copyFileSync(npmrc, `${dir}/.npmrc`);
}
const cleanup = async () => { const cleanup = async () => {
try { try {