Skip to content
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"doc:generate:json": "yarn update-doc-summary ./docs && yarn compodoc -e json -d .",
"start:modules": "yarn run build:dev:modules && yarn run watch:modules",
"verdaccio:start": "podman run -d -it --rm --name verdaccio -p 4873:4873 -v \"$(yarn get:current-dir)/.verdaccio/conf\":/verdaccio/conf verdaccio/verdaccio",
"verdaccio:start-local": "yarn verdaccio --config \"$(yarn get:current-dir)/.verdaccio/conf/config-without-podman.yaml\" --listen http://127.0.0.1:4873",
"verdaccio:start-local": "yarn verdaccio --config \"$(yarn get:current-dir)/.verdaccio/conf/config-without-docker.yaml\" --listen http://127.0.0.1:4873",
"verdaccio:start-persistent": "podman run -d -it --rm --name verdaccio -p 4873:4873 -v \"$(yarn get:current-dir)/.verdaccio/conf\":/verdaccio/conf -v \"$(yarn get:current-dir)/.verdaccio/storage\":/verdaccio/storage:z verdaccio/verdaccio",
"verdaccio:clean": "rimraf -g \".verdaccio/storage/@{o3r,ama-sdk,ama-mfe,ama-styling,o3r-training,ama-openapi,ama-mcp}\"",
"verdaccio:login": "yarn cpy .verdaccio/conf/.npmrc .verdaccio/conf --rename=.npmrc-logged --flat --dot && yarn npm-cli-login -u verdaccio -p verdaccio -e test@test.com -r http://127.0.0.1:4873 --config-path \".verdaccio/conf/.npmrc-logged\"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export function updateStore(
const workspaceProject = (options.projectName && workspaceConfig?.projects?.[options.projectName]) || undefined;
const projectDirectory = workspaceProject?.root || '.';
const projectPackageJson = tree.readJson(path.posix.join(projectDirectory, 'package.json')) as PackageJson;
// The dependencies are also added to the workspace root manifest, it is provided to detect the ones missing there
const rootPackageJson = projectDirectory === '.' ? undefined : tree.readJson('package.json') as PackageJson;

const appDeps = [ngrxEffectsDep, ngrxRouterStore, ngrxRouterStoreDevToolDep];
const corePeerDeps = [ngrxEntityDep, ngrxStoreDep];
Expand All @@ -92,7 +94,8 @@ export function updateStore(
devDependenciesToInstall: [],
o3rPackageJsonPath: corePackageJsonPath,
projectType,
projectPackageJson
projectPackageJson,
rootPackageJson
}, context.logger)
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export function updatePackageJson(
const workspaceProject = (projectName && workspaceConfig?.projects?.[projectName]) || undefined;
const projectDirectory = workspaceProject?.root || '.';
const projectPackageJson = tree.readJson(path.posix.join(projectDirectory, 'package.json')) as PackageJson;
// The dependencies are also added to the workspace root manifest, it is provided to detect the ones missing there
const rootPackageJson = projectDirectory === '.' ? undefined : tree.readJson('package.json') as PackageJson;

dependenciesSetupConfig.dependencies = {
...dependenciesSetupConfig.dependencies,
Expand All @@ -39,7 +41,8 @@ export function updatePackageJson(
devDependenciesToInstall,
o3rPackageJsonPath,
projectType: workspaceProject?.projectType,
projectPackageJson
projectPackageJson,
rootPackageJson
}, context.logger)
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ export const setupDependencies = (options: SetupDependenciesOptions): Rule => {
const packageManager = options.packageManager || getPackageManager();
const installId = isInstallNeeded()
? [
context.addTask(new NodePackageInstallTask({ packageManager, quiet: true, workingDirectory: options.workingDirectory }), options.runAfterTasks)
// `quiet` is kept to `false` to capture the package manager stdout (Yarn reports its errors on stdout),
// `hideOutput` ensures the captured output is only replayed in case of failure
context.addTask(new NodePackageInstallTask({ packageManager, quiet: false, hideOutput: true, workingDirectory: options.workingDirectory }), options.runAfterTasks)
]
: undefined;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ export function ngAddDependenciesRule(
const workspaceProject = options.projectName ? getWorkspaceConfig(tree)?.projects[options.projectName] : undefined;
const projectDirectory = workspaceProject?.root || '.';
const projectPackageJson = tree.readJson(path.posix.join(projectDirectory, 'package.json')) as PackageJson;
// The dependencies are also added to the workspace root manifest, it is provided to detect the ones missing there
const rootPackageJson = projectDirectory === '.' ? undefined : tree.readJson('package.json') as PackageJson;
depsInfo.o3rPeerDeps.push(...additionalNgAddToRun.filter((dep) => !depsInfo.o3rPeerDeps.includes(dep)));
const internalDependencies = depsInfo.o3rPeerDeps.reduce((acc, dep) => {
acc[dep] = {
Expand All @@ -228,7 +230,8 @@ export function ngAddDependenciesRule(
dependenciesToInstall,
o3rPackageJsonPath: packageJsonPath,
projectType: workspaceProject?.projectType,
projectPackageJson
projectPackageJson,
rootPackageJson
},
context.logger
);
Expand Down
40 changes: 40 additions & 0 deletions packages/@o3r/schematics/src/utility/dependencies.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,44 @@ describe('getExternalDependenciesInfo', () => {
}
});
});

it('should re-add a dependency of the sub-project which is missing from the workspace root', () => {
const result = getExternalDependenciesInfo({
o3rPackageJsonPath: join(__dirname, '..', '..', '/testing/mocks/external-dep-test.package.json'),
projectPackageJson: {
devDependencies: {
alreadyInstalledPackage: '~12.3.0'
}
},
rootPackageJson: {
devDependencies: {}
},
projectType: 'library',
dependenciesToInstall: [],
devDependenciesToInstall: ['alreadyInstalledPackage']
});

expect(result.alreadyInstalledPackage).toBeDefined();
});

it('should not re-add a dependency already satisfied in both the sub-project and the workspace root', () => {
const result = getExternalDependenciesInfo({
o3rPackageJsonPath: join(__dirname, '..', '..', '/testing/mocks/external-dep-test.package.json'),
projectPackageJson: {
devDependencies: {
alreadyInstalledPackage: '~12.3.0'
}
},
rootPackageJson: {
devDependencies: {
alreadyInstalledPackage: '~12.3.0'
}
},
projectType: 'library',
dependenciesToInstall: [],
devDependenciesToInstall: ['alreadyInstalledPackage']
});

expect(result.alreadyInstalledPackage).not.toBeDefined();
});
});
17 changes: 14 additions & 3 deletions packages/@o3r/schematics/src/utility/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ export function getNodeDependencyList<T extends string>(dependenciesVersions: Re
* @param params.projectPackageJson - The path to the package json of the project where the dependencies will be installed.
* @param params.projectType - The angular type of the project, either 'application' or 'library'.
* @param params.rootPackageJsonPath - Path to the root of the repository where the dependency will be installed
* @param params.rootPackageJson - Content of the workspace root `package.json`. When provided and different from
* `projectPackageJson`, a dependency is only skipped if it is already satisfied in both manifests.
* @param logger - The logger instance for logging information.
* @param isInstallRequired - Whether the package should be installed or not. By default, return true.
*/
Expand All @@ -170,14 +172,16 @@ export function getExternalDependenciesInfo<T extends string, U extends string>(
o3rPackageJsonPath,
projectPackageJson,
projectType,
rootPackageJsonPath
rootPackageJsonPath,
rootPackageJson
}: {
dependenciesToInstall: T[];
devDependenciesToInstall: U[];
o3rPackageJsonPath: string;
projectPackageJson: PackageJson;
projectType?: 'application' | 'library';
rootPackageJsonPath?: string;
rootPackageJson?: PackageJson;
},
logger?: logging.LoggerApi,
isInstallRequired = (_: string): undefined | boolean => undefined
Expand All @@ -187,6 +191,13 @@ export function getExternalDependenciesInfo<T extends string, U extends string>(
- Cannot install a dependency as there is no package.json in the project. ${JSON.stringify(devDependenciesToInstall)}`);
}
const rootPath = rootPackageJsonPath || 'package.json';
// A dependency added to a sub-project is also written to the workspace root manifest by `setupDependencies`.
// It is therefore only considered as already installed when satisfied in *both* manifests, otherwise a dependency
// pre-seeded in the sub-project (e.g. by the library generator) would never reach the root and would not be
// resolvable by the root scripts (`postinstall`, `harmonize`, ...) under a strict resolver such as Yarn PnP.
const isAlreadyInstalled = (name: string, inManifest: Required<DependencyInManifest>) =>
isDependencyAlreadyInstalled(name, projectPackageJson, inManifest)
&& (!rootPackageJson || isDependencyAlreadyInstalled(name, rootPackageJson, inManifest));
const peerDependenciesInfo = dependenciesToInstall.reduce((acc, name) => {
const rootVersion = [
name,
Expand All @@ -206,7 +217,7 @@ export function getExternalDependenciesInfo<T extends string, U extends string>(
types: projectType === 'application' ? [NodeDependencyType.Default] : [NodeDependencyType.Peer, NodeDependencyType.Dev]
};

if (isDependencyAlreadyInstalled(name, projectPackageJson, inManifest)) {
if (isAlreadyInstalled(name, inManifest)) {
return acc;
}
acc[name] = {
Expand Down Expand Up @@ -236,7 +247,7 @@ export function getExternalDependenciesInfo<T extends string, U extends string>(
range,
types: [NodeDependencyType.Dev]
};
if (isDependencyAlreadyInstalled(name, projectPackageJson, inManifest)) {
if (isAlreadyInstalled(name, inManifest)) {
return acc;
}

Expand Down
Loading