fix(core): misc. ng cli compat layer fixes (#8141)

* fix(core): misc. ng cli compat layer fixes

* chore(core): unit test fixes
This commit is contained in:
Craigory Coppola 2021-12-13 17:48:11 -06:00 committed by GitHub
parent 1f44bbeed9
commit a23284e9ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 49 deletions

View File

@ -1,12 +1,8 @@
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import {
updateJsonInTree,
readJsonInTree,
updateWorkspaceInTree,
readWorkspace,
getWorkspacePath,
} from '@nrwl/workspace';
import { readWorkspace } from '@nrwl/workspace';
import * as taoWorkspace from '@nrwl/tao/src/shared/workspace';
import * as path from 'path';
@ -14,6 +10,12 @@ describe('Update 8-5-0', () => {
let tree: Tree;
let schematicRunner: SchematicTestRunner;
beforeAll(() => {
jest
.spyOn(taoWorkspace, 'workspaceConfigName')
.mockReturnValue('workspace.json');
});
beforeEach(async () => {
tree = Tree.empty();
schematicRunner = new SchematicTestRunner(

View File

@ -238,6 +238,11 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
nxJson,
staticProjects.filter((x) => basename(x) !== 'package.json')
);
Object.entries(this.__nxInMemoryWorkspace.projects).forEach(
([project, config]) => {
this.__nxInMemoryWorkspace.projects[project] = config.root as any;
}
);
return of(this.__nxInMemoryWorkspace);
}
}
@ -359,7 +364,8 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
return of({
isWorkspaceConfig: true,
actualConfigFileName: null,
isNewFormat: false,
// AngularJson / WorkspaceJson v2 is always used for standalone project config
isNewFormat: true,
});
}
const actualConfigFileName = isAngularJson
@ -463,7 +469,7 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
config
) {
// copy to avoid removing inlined config files.
let writeObservable: Observable<void>;
const writeObservables: Observable<void>[] = [];
const configToWrite = {
...config,
projects: { ...config.projects },
@ -471,7 +477,7 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
const projects: [string, any][] = Object.entries(configToWrite.projects);
for (const [project, projectConfig] of projects) {
if (projectConfig.configFilePath) {
if (!isNewFormat) {
if (workspaceFileName && !isNewFormat) {
throw new Error(
'Attempted to write standalone project configuration into a v1 workspace'
);
@ -484,9 +490,7 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
configPath,
Buffer.from(serializeJson(fileConfigObject))
); // write back to the project.json file
writeObservable = writeObservable
? merge(writeObservable, projectJsonWrite)
: projectJsonWrite;
writeObservables.push(projectJsonWrite);
configToWrite.projects[project] = normalize(dirname(configPath)); // update the config object to point to the written file.
}
}
@ -496,11 +500,9 @@ export class NxScopedHost extends virtualFs.ScopedHost<any> {
workspaceFileName,
Buffer.from(serializeJson(configToWrite))
);
writeObservable = writeObservable
? merge(writeObservable, workspaceJsonWrite)
: workspaceJsonWrite;
writeObservables.push(workspaceJsonWrite);
}
return writeObservable;
return merge(...writeObservables);
}
protected resolveInlineProjectConfigurations(

View File

@ -11,6 +11,7 @@ const Module = require('module');
const originalRequire = Module.prototype.require;
let patched = false;
let loggedWriteWorkspaceWarning = false;
if (!patched) {
Module.prototype.require = function () {
@ -21,14 +22,34 @@ if (!patched) {
`@angular-devkit/core/src/workspace/core`,
]);
core._test_addWorkspaceFile('workspace.json', core.WorkspaceFormat.JSON);
const originalReadWorkspace = core.readWorkspace;
core.readWorkspace = (path, ...rest) => {
const configFile = workspaceConfigName(appRootPath);
if (!configFile) {
path = 'workspace.json';
}
return originalReadWorkspace.apply(this, [path, ...rest]);
};
const originalWriteWorkspace = core.writeWorkspace;
core.writeWorkspace = (...args) => {
const configFile = workspaceConfigName(appRootPath);
logger.warn(
`[NX] An Angular builder called \`writeWorkspace\`, this may have had unintended consequences in ${configFile}`
);
logger.warn(`[NX] Double check ${configFile} before proceeding`);
originalWriteWorkspace.apply(this, args);
if (!loggedWriteWorkspaceWarning) {
if (configFile) {
logger.warn(
`[NX] Angular devkit called \`writeWorkspace\`, this may have had unintended consequences in ${configFile}`
);
logger.warn(`[NX] Double check ${configFile} before proceeding`);
} else {
logger.warn(
`[NX] Angular devkit called \`writeWorkspace\`, this may have created 'workspace.json' or 'angular.json`
);
logger.warn(
`[NX] Double check workspace configuration before proceeding`
);
}
loggedWriteWorkspaceWarning = true;
}
return originalWriteWorkspace.apply(this, args);
};
// Patch readJsonWorkspace to inline project configurations
@ -37,20 +58,32 @@ if (!patched) {
`@angular-devkit/core/src/workspace/json/reader`,
]);
const originalReadJsonWorkspace = readJsonUtils.readJsonWorkspace;
readJsonUtils.readJsonWorkspace = () => {
// Read our v1 workspace schema
const w = resolveOldFormatWithInlineProjects(
new Workspaces(appRootPath).readWorkspaceConfiguration()
);
// readJsonWorkspace actually has AST parsing + more, so we
// still need to call it rather than just return our file
return originalReadJsonWorkspace.apply(this, [
'workspace.json', // path name, doesn't matter
{
// second arg is a host, only method used is readFile
readFile: () => JSON.stringify(w),
},
]);
readJsonUtils.readJsonWorkspace = (
path,
host: { readFile: (p) => Promise<string> }
) => {
try {
return originalReadJsonWorkspace(path, host);
} catch {
logger.debug(
'[NX] Angular devkit readJsonWorkspace fell back to Nx workspaces logic'
);
const w = new Workspaces(appRootPath);
// Read our v1 workspace schema
const workspaceConfiguration = resolveOldFormatWithInlineProjects(
w.readWorkspaceConfiguration()
);
// readJsonWorkspace actually has AST parsing + more, so we
// still need to call it rather than just return our file
return originalReadJsonWorkspace.apply(this, [
'workspace.json', // path name, doesn't matter
{
// second arg is a host, only method used is readFile
readFile: () => JSON.stringify(workspaceConfiguration),
},
]);
}
};
}
return result;

View File

@ -157,8 +157,10 @@ export interface TargetConfiguration {
export function workspaceConfigName(root: string) {
if (existsSync(path.join(root, 'angular.json'))) {
return 'angular.json';
} else {
} else if (existsSync(path.join(root, 'workspace.json'))) {
return 'workspace.json';
} else {
return null;
}
}
@ -290,14 +292,18 @@ export class Workspaces {
const nxJson = existsSync(nxJsonPath)
? readJsonFile<NxJsonConfiguration>(nxJsonPath)
: ({} as NxJsonConfiguration);
const workspacePath = path.join(this.root, workspaceConfigName(this.root));
const workspace = existsSync(workspacePath)
? this.readFromWorkspaceJson()
: buildWorkspaceConfigurationFromGlobs(
nxJson,
globForProjectFiles(this.root),
(path) => readJsonFile(join(this.root, path))
);
const workspaceFile = workspaceConfigName(this.root);
const workspacePath = workspaceFile
? path.join(this.root, workspaceFile)
: null;
const workspace =
workspacePath && existsSync(workspacePath)
? this.readFromWorkspaceJson()
: buildWorkspaceConfigurationFromGlobs(
nxJson,
globForProjectFiles(this.root),
(path) => readJsonFile(join(this.root, path))
);
assertValidWorkspaceConfiguration(nxJson);
return { ...workspace, ...nxJson };
@ -701,6 +707,7 @@ export function deduplicateProjectFiles(files: string[], ig?: Ignore) {
) {
return;
}
filtered.set(projectFolder, projectFile);
});
return Array.from(filtered.entries()).map(([folder, file]) =>

View File

@ -2,7 +2,6 @@ import { Tree } from '@angular-devkit/schematics';
import { createEmptyWorkspace } from '../../utils/testing-utils';
import { callRule, runMigration } from '../../utils/testing';
import { readJsonInTree, updateJsonInTree } from '../../utils/ast-utils';
import type { NxJsonConfiguration } from '@nrwl/devkit';
describe('Update 8.12.0', () => {
let tree: Tree;

View File

@ -9,11 +9,10 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
import { updateJsonInTree } from '../../utils/ast-utils';
import type { WorkspaceJsonConfiguration } from '@nrwl/devkit';
import { formatFiles } from '@nrwl/workspace/src/utils/rules/format-files';
import { workspaceConfigName } from '@nrwl/tao/src/shared/workspace';
const addE2eImplicitDependencies: Rule = (tree: Tree) =>
updateJsonInTree<WorkspaceJsonConfiguration>(
workspaceConfigName(tree.root.path),
'workspace.json', // ngcli-adapter should handle conversion of workspace file names
(json) => {
Object.keys(json.projects).forEach((proj) => {
const implicitE2eName = proj.replace(/-e2e$/, '');

View File

@ -3,12 +3,21 @@ import { Tree } from '@angular-devkit/schematics';
import * as prettier from 'prettier';
import * as path from 'path';
import * as taoWorkspace from '@nrwl/tao/src/shared/workspace';
import { formatFiles } from './format-files';
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
describe('formatFiles', () => {
let tree: Tree;
let schematicRunner: SchematicTestRunner;
beforeAll(() => {
jest
.spyOn(taoWorkspace, 'workspaceConfigName')
.mockReturnValue('workspace.json');
});
beforeEach(() => {
schematicRunner = new SchematicTestRunner(
'@nrwl/workspace',
@ -106,7 +115,7 @@ describe('formatFiles', () => {
});
it('should have a readable error when workspace file cannot be formatted', async () => {
tree.delete('workspace.json');
tree.overwrite('workspace.json', '{ invalidJson: true');
const errorSpy = jest.spyOn(console, 'error');