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

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 26 additions & 28 deletions packages/devkit/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
{
"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": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
"rules": {
"@typescript-eslint/explicit-module-boundary-types": ["error"],
"@typescript-eslint/no-restricted-imports": [
Copy link
Collaborator

Choose a reason for hiding this comment

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

Move these up to the previous .ts block

"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"],
Expand All @@ -38,9 +38,7 @@
},
{
"files": ["*.ts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": ["error"]
}
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
Expand Down
17 changes: 15 additions & 2 deletions packages/devkit/nx.ts
Original file line number Diff line number Diff line change
@@ -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 {
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 {
// Remove in Nx V17, devkit should not support Nx < 16 at that point.
return require('./nx-reexports-pre16');
}
}
5 changes: 4 additions & 1 deletion packages/devkit/src/utils/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
getPackageManagerCommand,
workspaceRoot,
detectPackageManager,
createTempNpmDirectory,
} = requireNx();

const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION';
Expand Down Expand Up @@ -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}...`);
const packageManager = detectPackageManager();
Expand Down
6 changes: 6 additions & 0 deletions packages/nx/src/devkit-internals.ts
Original file line number Diff line number Diff line change
@@ -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';
32 changes: 24 additions & 8 deletions packages/nx/src/utils/package-manager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { exec, execSync } from 'child_process';
import { copyFileSync, existsSync } from 'fs';
import { remove } from 'fs-extra';
import { dirname, join } from 'path';
import { dirname, join, relative } from 'path';
import { dirSync } from 'tmp';
import { promisify } from 'util';
import { writeJsonFile } from './fileutils';
import { readModulePackageJson } from './package-json';
import { gte, lt } from 'semver';
import { workspaceRoot } from './workspace-root';

const execAsync = promisify(exec);

Expand Down Expand Up @@ -118,16 +119,35 @@ export function getPackageManagerVersion(
* 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.
*/
export function checkForNPMRC(
export function findFileInPackageJsonDirectory(
file: string,
directory: string = process.cwd()
): string | null {
while (!existsSync(join(directory, 'package.json'))) {
directory = dirname(directory);
}
const path = join(directory, '.npmrc');
const path = join(directory, file);
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.
*
Expand All @@ -140,11 +160,7 @@ export function createTempNpmDirectory() {

// A package.json is needed for pnpm pack and for .npmrc to resolve
writeJsonFile(`${dir}/package.json`, {});
const npmrc = checkForNPMRC();
if (npmrc) {
// Copy npmrc if it exists, so that npm still follows it.
copyFileSync(npmrc, `${dir}/.npmrc`);
}
copyPackageManagerConfigurationFiles(workspaceRoot, dir);

const cleanup = async () => {
try {
Expand Down