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

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

Merged
merged 2 commits into from
Jul 3, 2023
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
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