Skip to content

Commit

Permalink
feat(nx-python): automatically activate shared virtual environment (#138
Browse files Browse the repository at this point in the history
)

* feat(nx-python): automatically activate shared virtual environment

Changes all the `@nxlv/python` executors to first verify if the shared virtual environment is
available in the workspace, if yes, activate before running the commands, also adds a new
`@nxlv/python:run-commands` executors to wrap the `nx:run-commands` and activate the virtual
environment before running the commands, if you are using `@nxlv/python` version 16> you can use
this following command to migrate all your `nx:run-commands` to `@nxlv/python:run-commands`: `npx nx
migrate @nxlv/python`

re #132
  • Loading branch information
lucasvieirasilva authored Jul 3, 2023
1 parent 297244e commit e275534
Show file tree
Hide file tree
Showing 40 changed files with 763 additions and 110 deletions.
7 changes: 6 additions & 1 deletion packages/nx-python/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
"rules": {}
},
{
"files": ["./package.json", "./generators.json", "./executors.json"],
"files": [
"./package.json",
"./generators.json",
"./executors.json",
"./migrations.json"
],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/nx-plugin-checks": "error"
Expand Down
28 changes: 25 additions & 3 deletions packages/nx-python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ npx nx generate @nxlv/python:migrate-to-shared-venv

**Options**:

| Option | Type | Description | Required | Default |
| ----------------------- | :-------: | ------------------------------------------------------------------------------------------------ | -------- | ------- |
| `--moveDevDependencies` | `boolean` | Specifies if migration moves the dev dependencies from the projects to the root `pyproject.toml` | `true` | `true` |
| Option | Type | Description | Required | Default |
| ----------------------- | :-------: | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
| `--moveDevDependencies` | `boolean` | Specifies if migration moves the dev dependencies from the projects to the root `pyproject.toml` | `true` | `true` |
| `--autoActivate` | `boolean` | Adds the `autoActivate` config in the root `pyproject.toml`, this flag is used to auto-activate the venv when the `@nxlv/python` executors are called | `true` | `true` |

After the migration is completed, the workspace does not have the `pyproject.toml` in the root directory, and all the local projects are referencing the root `pyproject.toml` file.

Expand Down Expand Up @@ -495,3 +496,24 @@ The `@nxlv/python:install` handles the `poetry install` command for a project.
| `--cacheDir` | `string` | Custom poetry install cache directory | `false` | |
| `--verbose` | `boolean` | Use verbose mode in the install `poetry install -vv` | `false` | `false` |
| `--debug` | `boolean` | Use debug mode in the install `poetry install -vvv` | `false` | `false` |

#### run-commands (same as `nx:run-commands`)

The `@nxlv/python:run-commands` wraps the `nx:run-commands` default Nx executor and if the `autoActivate` option is set to `true` in the root `pyproject.toml` file, it will verify the the virtual environment is not activated, if no, it will activate the virtual environment before running the commands.

> NOTE: This executor only changes the default `nx:run-commands` if the workspace is configured to use the Shared virtual environment mode and the `autoActivate` option is set to `true` in the root `pyproject.toml` file.
> NOTE: The `autoActivate` option is set to `false` by default.

root `pyproject.toml`

```toml
...
[tool.nx]
autoActivate = true
...
```

The options and behavior are the same as the `nx:run-commands` executor.

[See the Nx documentation for more information](https://nx.dev/packages/nx/executors/run-commands)
5 changes: 5 additions & 0 deletions packages/nx-python/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
"implementation": "./src/executors/sls-package/executor",
"schema": "./src/executors/sls-package/schema.json",
"description": "Serverless Package Wrapper Executor"
},
"run-commands": {
"implementation": "./src/executors/run-commands/executor",
"schema": "./src/executors/run-commands/schema.json",
"description": "Python Venv Run Commands Executor"
}
}
}
10 changes: 10 additions & 0 deletions packages/nx-python/migrations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"generators": {
"16-1-0-replace-nx-run-commands": {
"version": "16.1.0",
"description": "Migrate all nx:run-commands to @nxlv/python:run-commands",
"cli": "nx",
"implementation": "./src/migrations/update-16-1-0/replace-nx-run-commands"
}
}
}
3 changes: 3 additions & 0 deletions packages/nx-python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
},
"peerDependencies": {
"@nx/devkit": "^16.0.0"
},
"nx-migrations": {
"migrations": "./migrations.json"
}
}
8 changes: 7 additions & 1 deletion packages/nx-python/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
"input": "./packages/nx-python",
"glob": "executors.json",
"output": "."
},
{
"input": "./packages/nx-python",
"glob": "migrations.json",
"output": "."
}
]
}
Expand All @@ -44,7 +49,8 @@
"packages/nx-python/**/*.ts",
"packages/nx-python/generators.json",
"packages/nx-python/executors.json",
"packages/nx-python/package.json"
"packages/nx-python/package.json",
"packages/nx-python/migrations.json"
]
}
},
Expand Down
27 changes: 22 additions & 5 deletions packages/nx-python/src/executors/add/executor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import dedent from 'string-dedent';

describe('Add Executor', () => {
let checkPoetryExecutableMock: jest.SpyInstance;
let activateVenvMock: jest.SpyInstance;

beforeAll(() => {
console.log(chalk`init chalk`);
});

beforeEach(() => {
checkPoetryExecutableMock = jest.spyOn(
poetryUtils,
'checkPoetryExecutable'
);
checkPoetryExecutableMock.mockResolvedValue(undefined);
checkPoetryExecutableMock = jest
.spyOn(poetryUtils, 'checkPoetryExecutable')
.mockResolvedValue(undefined);
activateVenvMock = jest
.spyOn(poetryUtils, 'activateVenv')
.mockReturnValue(undefined);
spawnSyncMock.mockReturnValue({ status: 0 });
});

Expand Down Expand Up @@ -54,6 +56,7 @@ describe('Add Executor', () => {

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).not.toHaveBeenCalled();
expect(output.success).toBe(false);
});
Expand Down Expand Up @@ -100,6 +103,7 @@ describe('Add Executor', () => {

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['add', 'numpy'], {
cwd: 'apps/app',
shell: false,
Expand Down Expand Up @@ -151,6 +155,7 @@ describe('Add Executor', () => {

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledWith(
'poetry',
['add', 'numpy', '--group', 'dev'],
Expand Down Expand Up @@ -206,6 +211,7 @@ describe('Add Executor', () => {

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledWith(
'poetry',
['add', 'numpy', '--extras=dev'],
Expand Down Expand Up @@ -256,6 +262,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).not.toHaveBeenCalled();
expect(output.success).toBe(false);
});
Expand Down Expand Up @@ -302,6 +309,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['add', 'numpy'], {
cwd: 'apps/app',
shell: false,
Expand Down Expand Up @@ -402,6 +410,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(4);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -538,6 +547,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(4);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -632,6 +642,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(1);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -697,6 +708,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(1);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -766,6 +778,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(1);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -836,6 +849,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(1);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -901,6 +915,7 @@ version = "1.0.0"
const output = await executor(options, context);
expect(output.success).toBe(true);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledTimes(1);
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
Expand Down Expand Up @@ -964,6 +979,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenCalledWith(
'poetry',
['add', 'numpy', '--group', 'dev'],
Expand Down Expand Up @@ -1024,6 +1040,7 @@ version = "1.0.0"

const output = await executor(options, context);
expect(checkPoetryExecutableMock).toHaveBeenCalled();
expect(activateVenvMock).toHaveBeenCalledWith('.');
expect(spawnSyncMock).toHaveBeenNthCalledWith(
1,
'poetry',
Expand Down
2 changes: 2 additions & 0 deletions packages/nx-python/src/executors/add/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { updateDependencyTree } from '../../dependency/update-dependency';
import { existsSync } from 'fs-extra';
import path from 'path';
import {
activateVenv,
addLocalProjectToPoetryProject,
checkPoetryExecutable,
getLocalDependencyConfig,
Expand All @@ -19,6 +20,7 @@ export default async function executor(
const workspaceRoot = context.root;
process.chdir(workspaceRoot);
try {
activateVenv(workspaceRoot);
await checkPoetryExecutable();
const projectConfig = context.workspace.projects[context.projectName];
const rootPyprojectToml = existsSync('pyproject.toml');
Expand Down
Loading

0 comments on commit e275534

Please sign in to comment.