Skip to content

Commit

Permalink
feat(nx-python): add projectNameAndRootFormat parameter to poetry p…
Browse files Browse the repository at this point in the history
…roject generator (#186)

* feat(nx-python): add projectNameAndRootFormat parameter to poetry project generator

re #182

* refactor(nx-python): fix sonarcloud code smell
  • Loading branch information
lucasvieirasilva authored Nov 10, 2023
1 parent 4828ef8 commit e0dffbe
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 33 deletions.
66 changes: 66 additions & 0 deletions e2e/nx-python-e2e/tests/nx-python.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,72 @@ describe('nx-python e2e', () => {
).not.toThrow();
}, 3000000);

it('should create nx-python project with ruff and as-provided projectNameAndRootFormat', async () => {
const app1 = 'app1';
const lib1 = 'lib1';
ensureNxProject('@nxlv/python', 'dist/packages/nx-python');

const nxJson = readJson('nx.json');
nxJson.plugins = ['@nxlv/python'];

updateFile('nx.json', JSON.stringify(nxJson, null, 4));

await runNxCommandAsync(
[
'generate',
'@nxlv/python:poetry-project',
app1,
'--projectType',
'"application"',
'--packageName',
app1,
'--description',
app1,
'--directory',
'src/app1',
'--linter',
'ruff',
'--projectNameAndRootFormat',
'as-provided',
].join(' ')
);

await runNxCommandAsync(
[
'generate',
'@nxlv/python:poetry-project',
lib1,
'--projectType',
'"library"',
'--packageName',
lib1,
'--description',
lib1,
'--directory',
'src/lib1',
'--linter',
'ruff',
'--projectNameAndRootFormat',
'as-provided',
].join(' ')
);

await runNxCommandAsync(`run ${app1}:add --name ${lib1} --local`);

await runNxCommandAsync(`run ${lib1}:add --name pendulum`);

await runNxCommandAsync(`run ${app1}:lint`);

await runNxCommandAsync(`run ${app1}:build`);

expect(() =>
checkFilesExist(
`src/${app1}/dist/${app1.replace('-', '_')}-1.0.0-py3-none-any.whl`,
`src/${app1}/dist/${app1}-1.0.0.tar.gz`
)
).not.toThrow();
}, 3000000);

it('should create nx-python project with 3 levels', async () => {
const app1 = 'app1';
const lib1 = 'lib1';
Expand Down
73 changes: 52 additions & 21 deletions packages/nx-python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,60 @@ Example:
nx generate @nxlv/python:poetry-project myproject
```

**NOTE**: On Nx **v16.8.0** or higher, the generators are prompting the user to choose how Nx will calculate where the project should be located, by using the `--projectNameAndRootFormat` with `as-provided` or `derived`.

The `as-provided` option uses the `--directory` option to calculate the project root, so, if the `--directory` option is not provided, the project root will be the same as the project name, and the project name will be the same as provided in the `--name` option.

Example 1: `nx generate @nxlv/python:poetry-project myproject` will generate the project in the `myproject` folder with the name `myproject`.
Example 2: `nx generate @nxlv/python:poetry-project myproject --directory=api` will generate the project in the `api` folder with the name `myproject`.

The `derived` option uses the combination of the workspace layout, `--directory` option, and `--name` to calculate the name and root of the project.

Example 1: `nx generate @nxlv/python:poetry-project myproject` will generate the project in the `apps/myproject` folder with the name `myproject`.
Example 2: `nx generate @nxlv/python:poetry-project myproject --directory=api` will generate the project in the `apps/api/myproject` folder with the name `api-myproject`.

**NOTE**: The `derived` option is the default option for now, however, the `as-provided` option will be the default option in the future.

To make the `as-provided` option the default option, add the following configuration in the `nx.json` file:

```json
{
...
"generators": {
"@nxlv/python:poetry-project": {
"projectNameAndRootFormat": "as-provided"
}
}
...
}
```

Nx documentation reference: <https://nx.dev/deprecated/as-provided-vs-derived#project-generators>

#### Options

| Option | Type | Description | Required | Default |
| -------------------------------- | :-------: | ------------------------------------------------- | -------- | ---------------------------------------- |
| `--directory` | `string` | A directory where the project is placed | `false` | N/A |
| `--tags` | `string` | Add tags to the project | `false` | N/A |
| `--projectType` | `string` | Project type `application` or `library` | `true` | `application` |
| `--packageName` | `string` | Poetry Package name | `false` | `name` property (provided in the CLI) |
| `--moduleName` | `string` | Project Source Module | `false` | `name` property using `_` instead of `-` |
| `--description` | `string` | Project description | `false` | N/A |
| `--pyprojectPythonDependency` | `string` | Python version range used in the `pyproject.toml` | `false` | `>=3.9,<3.11` (Poetry syntax) |
| `--pyenvPythonVersion` | `string` | `.python-version` pyenv file content | `false` | `3.9.5` |
| `--publishable` | `boolean` | Specifies if the project is publishable or not | `false` | `true` |
| `--buildLockedVersions` | `boolean` | Use locked versions for build dependencies | `false` | `true` |
| `--buildBundleLocalDependencies` | `boolean` | Bundle local dependencies | `false` | `true` |
| `--linter` | `string` | Linter framework (`flake8`, `ruff` or `none`) | `false` | `flake8` |
| `--unitTestRunner` | `string` | Unit Test Runner (`pytest` or `none`) | `false` | `pytest` |
| `--unitTestHtmlReport` | `boolean` | Enable HTML Pytest Reports | `false` | `true` |
| `--unitTestJUnitReport` | `boolean` | Enable JUnit Pytest Reports | `false` | `true` |
| `--codeCoverage` | `boolean` | Enable Code Coverage Reports | `false` | `true` |
| `--codeCoverageHtmlReport` | `boolean` | Enable Code Coverage HTML Reports | `false` | `true` |
| `--codeCoverageXmlReport` | `boolean` | Enable Code Coverage XML Reports | `false` | `true` |
| `--codeCoverageThreshold` | `number` | Minimum Code Coverage Threshold | `false` | N/A |
| Option | Type | Description | Required | Default |
| -------------------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------- |
| `--directory` | `string` | A directory where the project is placed | `false` | N/A |
| `--tags` | `string` | Add tags to the project | `false` | N/A |
| `--projectType` | `string` | Project type `application` or `library` | `true` | `application` |
| `--packageName` | `string` | Poetry Package name | `false` | `name` property (provided in the CLI) |
| `--moduleName` | `string` | Project Source Module | `false` | `name` property using `_` instead of `-` |
| `--description` | `string` | Project description | `false` | N/A |
| `--pyprojectPythonDependency` | `string` | Python version range used in the `pyproject.toml` | `false` | `>=3.9,<3.11` (Poetry syntax) |
| `--pyenvPythonVersion` | `string` | `.python-version` pyenv file content | `false` | `3.9.5` |
| `--publishable` | `boolean` | Specifies if the project is publishable or not | `false` | `true` |
| `--buildLockedVersions` | `boolean` | Use locked versions for build dependencies | `false` | `true` |
| `--buildBundleLocalDependencies` | `boolean` | Bundle local dependencies | `false` | `true` |
| `--linter` | `string` | Linter framework (`flake8`, `ruff` or `none`) | `false` | `flake8` |
| `--unitTestRunner` | `string` | Unit Test Runner (`pytest` or `none`) | `false` | `pytest` |
| `--unitTestHtmlReport` | `boolean` | Enable HTML Pytest Reports | `false` | `true` |
| `--unitTestJUnitReport` | `boolean` | Enable JUnit Pytest Reports | `false` | `true` |
| `--codeCoverage` | `boolean` | Enable Code Coverage Reports | `false` | `true` |
| `--codeCoverageHtmlReport` | `boolean` | Enable Code Coverage HTML Reports | `false` | `true` |
| `--codeCoverageXmlReport` | `boolean` | Enable Code Coverage XML Reports | `false` | `true` |
| `--codeCoverageThreshold` | `number` | Minimum Code Coverage Threshold | `false` | N/A |
| `--projectNameAndRootFormat` | `string` | Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`). | `false` | `derived` |

##### rootPyprojectDependencyGroup

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,199 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`application generator as-provided should run successfully minimal configuration 1`] = `
{
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"name": "my-app-test",
"projectType": "application",
"root": "src/app/test",
"sourceRoot": "src/app/test/my_app_test",
"tags": [],
"targets": {
"add": {
"executor": "@nxlv/python:add",
"options": {},
},
"build": {
"executor": "@nxlv/python:build",
"options": {
"bundleLocalDependencies": false,
"lockedVersions": false,
"outputPath": "src/app/test/dist",
"publish": false,
},
"outputs": [
"{projectRoot}/dist",
],
},
"install": {
"executor": "@nxlv/python:install",
"options": {
"args": "",
"cacheDir": ".cache/pypoetry",
"debug": false,
"silent": false,
"verbose": false,
},
},
"lock": {
"executor": "@nxlv/python:run-commands",
"options": {
"command": "poetry lock --no-update",
"cwd": "src/app/test",
},
},
"remove": {
"executor": "@nxlv/python:remove",
"options": {},
},
"update": {
"executor": "@nxlv/python:update",
"options": {},
},
},
}
`;

exports[`application generator as-provided should run successfully minimal configuration 2`] = `
"# my-app-test
Project description here.
"
`;

exports[`application generator as-provided should run successfully minimal configuration 3`] = `
"[tool.poetry]
name = "my-app-test"
version = "1.0.0"
description = "Automatically generated by Nx."
authors = [ ]
license = 'Proprietary'
readme = 'README.md'
[[tool.poetry.packages]]
include = "my_app_test"
[tool.poetry.dependencies]
python = ">=3.9,<3.11"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
"
`;

exports[`application generator as-provided should run successfully minimal configuration 4`] = `
""""Sample Hello World application."""
def hello():
"""Return a friendly greeting."""
return "Hello my-app-test"
"
`;

exports[`application generator as-provided should run successfully minimal configuration 5`] = `
"3.9.5
"
`;

exports[`application generator as-provided should run successfully minimal configuration without directory 1`] = `
{
"$schema": "../node_modules/nx/schemas/project-schema.json",
"name": "my-app-test",
"projectType": "application",
"root": "my-app-test",
"sourceRoot": "my-app-test/my_app_test",
"tags": [],
"targets": {
"add": {
"executor": "@nxlv/python:add",
"options": {},
},
"build": {
"executor": "@nxlv/python:build",
"options": {
"bundleLocalDependencies": false,
"lockedVersions": false,
"outputPath": "my-app-test/dist",
"publish": false,
},
"outputs": [
"{projectRoot}/dist",
],
},
"install": {
"executor": "@nxlv/python:install",
"options": {
"args": "",
"cacheDir": ".cache/pypoetry",
"debug": false,
"silent": false,
"verbose": false,
},
},
"lock": {
"executor": "@nxlv/python:run-commands",
"options": {
"command": "poetry lock --no-update",
"cwd": "my-app-test",
},
},
"remove": {
"executor": "@nxlv/python:remove",
"options": {},
},
"update": {
"executor": "@nxlv/python:update",
"options": {},
},
},
}
`;

exports[`application generator as-provided should run successfully minimal configuration without directory 2`] = `
"# my-app-test
Project description here.
"
`;

exports[`application generator as-provided should run successfully minimal configuration without directory 3`] = `
"[tool.poetry]
name = "my-app-test"
version = "1.0.0"
description = "Automatically generated by Nx."
authors = [ ]
license = 'Proprietary'
readme = 'README.md'
[[tool.poetry.packages]]
include = "my_app_test"
[tool.poetry.dependencies]
python = ">=3.9,<3.11"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
"
`;

exports[`application generator as-provided should run successfully minimal configuration without directory 4`] = `
""""Sample Hello World application."""
def hello():
"""Return a friendly greeting."""
return "Hello my-app-test"
"
`;

exports[`application generator as-provided should run successfully minimal configuration without directory 5`] = `
"3.9.5
"
`;

exports[`application generator custom template dir should run successfully with custom template dir 1`] = `
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
Expand Down
Loading

0 comments on commit e0dffbe

Please sign in to comment.