From 3fdd0cbf3082ea3c86718f51bea2b06a0ec425f2 Mon Sep 17 00:00:00 2001 From: Kyle Bjordahl <3489222+kylebjordahl@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:59:42 -0700 Subject: [PATCH] fix(nx-python): relock root when changing deps on grouped projects (#195) --- .../src/dependency/update-dependency.ts | 33 +++++++- .../src/executors/add/executor.spec.ts | 78 +++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/packages/nx-python/src/dependency/update-dependency.ts b/packages/nx-python/src/dependency/update-dependency.ts index d5db2c6..e80ad37 100644 --- a/packages/nx-python/src/dependency/update-dependency.ts +++ b/packages/nx-python/src/dependency/update-dependency.ts @@ -1,6 +1,10 @@ import { ExecutorContext, ProjectsConfigurations } from '@nx/devkit'; import chalk from 'chalk'; -import { getDependents, PyprojectToml } from '../graph/dependency-graph'; +import { + getDependents, + PyprojectToml, + PyprojectTomlDependencies, +} from '../graph/dependency-graph'; import { getProjectTomlPath, parseToml, @@ -27,7 +31,11 @@ export function updateDependencyTree(context: ExecutorContext) { readFileSync('pyproject.toml', { encoding: 'utf-8' }), ) as PyprojectToml; - if (rootPyprojectToml.tool.poetry.dependencies[pkgName]) { + const allRootDependencyNames = Object.keys( + getAllDependenciesFromPyprojectToml(rootPyprojectToml), + ); + + if (allRootDependencyNames.includes(pkgName)) { console.log( chalk`\nUpdating root {bold pyproject.toml} dependency {bold ${pkgName}}`, ); @@ -82,3 +90,24 @@ function getProjectPackageName(context: ExecutorContext, projectName: string) { return name; } + +/** + * Parses all dependency names from a Pyproject.toml file + * and returns a flattened collection of dependencies + * + * Optionally you may supply a list of groups to ignore + */ +export const getAllDependenciesFromPyprojectToml = ( + tomlData: PyprojectToml, + /** optional dependency groups to omit from collection */ + omitGroups: string[] = [], +): PyprojectTomlDependencies => { + return { + ...(tomlData.tool?.poetry?.dependencies ?? {}), + ...Object.fromEntries( + Object.entries(tomlData.tool?.poetry?.group ?? {}) + .filter(([name]) => !omitGroups.includes(name)) + .flatMap(([_, group]) => Object.entries(group.dependencies ?? {})), + ), + }; +}; diff --git a/packages/nx-python/src/executors/add/executor.spec.ts b/packages/nx-python/src/executors/add/executor.spec.ts index 4485a48..5d477fb 100644 --- a/packages/nx-python/src/executors/add/executor.spec.ts +++ b/packages/nx-python/src/executors/add/executor.spec.ts @@ -1066,4 +1066,82 @@ version = "1.0.0" }); expect(output.success).toBe(true); }); + + it('run add target and should add the dependency to the project using --lock when the root pyproject.toml is present when project is grouped in root', async () => { + fsMock({ + 'pyproject.toml': dedent` + [tool.poetry] + name = "app" + version = "1.0.0" + + [tool.poetry.dependencies] + python = "^3.8" + + [tool.poetry.group.foo.dependencies.app] + path = "apps/app" + develop = true + `, + 'apps/app/pyproject.toml': dedent` + [tool.poetry] + name = "app" + version = "1.0.0" + [[tool.poetry.packages]] + include = "app" + + [tool.poetry.dependencies] + python = "^3.8" + click = "click" + `, + }); + + const options = { + name: 'numpy', + local: false, + }; + + const context = { + cwd: '', + root: '.', + isVerbose: false, + projectName: 'app', + workspace: { + npmScope: 'nxlv', + version: 2, + projects: { + app: { + root: 'apps/app', + targets: {}, + }, + }, + }, + }; + + const output = await executor(options, context); + expect(checkPoetryExecutableMock).toHaveBeenCalled(); + expect(activateVenvMock).toHaveBeenCalledWith('.'); + expect(spawn.sync).toHaveBeenNthCalledWith( + 1, + 'poetry', + ['add', 'numpy', '--lock'], + { + cwd: 'apps/app', + shell: false, + stdio: 'inherit', + }, + ); + expect(spawn.sync).toHaveBeenNthCalledWith( + 2, + 'poetry', + ['lock', '--no-update'], + { + shell: false, + stdio: 'inherit', + }, + ); + expect(spawn.sync).toHaveBeenNthCalledWith(3, 'poetry', ['install'], { + shell: false, + stdio: 'inherit', + }); + expect(output.success).toBe(true); + }); });