diff --git a/.github/ISSUE_TEMPLATE/1-bug.yml b/.github/ISSUE_TEMPLATE/1-bug.yml index 4e617f3..1b2e0b2 100644 --- a/.github/ISSUE_TEMPLATE/1-bug.yml +++ b/.github/ISSUE_TEMPLATE/1-bug.yml @@ -1,6 +1,6 @@ name: 🐞 Bug Report description: This form is to report unexpected behavior in of lucasvieirasilva/nx-plugins packages. -labels: ['type: bug'] +labels: ['bug', 'needs-triage'] body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/2-feature.md b/.github/ISSUE_TEMPLATE/2-feature.md index 9cdfd5e..f660597 100644 --- a/.github/ISSUE_TEMPLATE/2-feature.md +++ b/.github/ISSUE_TEMPLATE/2-feature.md @@ -1,7 +1,7 @@ --- name: "\U0001F680 Feature Request" about: Suggest a new feature. -labels: 'type: feature' +labels: ['enhancement', 'needs-triage'] --- diff --git a/.github/ISSUE_TEMPLATE/3-documentation.md b/.github/ISSUE_TEMPLATE/3-documentation.md index ff8a580..2446ee2 100644 --- a/.github/ISSUE_TEMPLATE/3-documentation.md +++ b/.github/ISSUE_TEMPLATE/3-documentation.md @@ -1,7 +1,7 @@ --- name: '📖 Documentation issue' about: Help improve our docs. -labels: 'type: docs' +labels: ['documentation', 'needs-triage'] --- ### Documentation issue diff --git a/packages/nx-python/generators.json b/packages/nx-python/generators.json index 52d4c66..7deebc1 100644 --- a/packages/nx-python/generators.json +++ b/packages/nx-python/generators.json @@ -6,12 +6,17 @@ "project": { "factory": "./src/generators/project/generator", "schema": "./src/generators/project/schema.json", - "description": "python project generator" + "description": "python project generator (Legacy)" }, "migrate-to-shared-venv": { "factory": "./src/generators/migrate-to-shared-venv/generator", "schema": "./src/generators/migrate-to-shared-venv/schema.json", "description": "Migrate Isolated Venv to Shared Venv" + }, + "poetry-project": { + "factory": "./src/generators/poetry-project/generator", + "schema": "./src/generators/poetry-project/schema.json", + "description": "Python Poetry Project" } } } diff --git a/packages/nx-python/jest.config.ts b/packages/nx-python/jest.config.ts index 0b062c0..ca63599 100644 --- a/packages/nx-python/jest.config.ts +++ b/packages/nx-python/jest.config.ts @@ -14,7 +14,7 @@ export default { moduleFileExtensions: ['ts', 'js', 'html'], coverageDirectory: '../../coverage/packages/nx-python', collectCoverage: true, - collectCoverageFrom: ['./src/**/*.ts', '!./src/types.ts'], + // collectCoverageFrom: ['./src/**/*.ts', '!./src/types.ts'], coverageReporters: [ 'text', 'html', diff --git a/packages/nx-python/src/generators/poetry-project/__snapshots__/generator.spec.ts.snap b/packages/nx-python/src/generators/poetry-project/__snapshots__/generator.spec.ts.snap new file mode 100644 index 0000000..ae68ace --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/__snapshots__/generator.spec.ts.snap @@ -0,0 +1,2579 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`application generator custom template dir should run successfully with custom template dir 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator custom template dir should run successfully with custom template dir 2`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + autopep8 = "^1.5.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator custom template dir should run successfully with custom template dir 3`] = ` +"[virtualenvs] +in-project = true +" +`; + +exports[`application generator individual package should run successfully minimal configuration 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully minimal configuration 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully minimal configuration 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully minimal configuration 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully minimal configuration 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully minimal configuration as a library 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "library", + "root": "libs/test", + "sourceRoot": "libs/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "libs/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "libs/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully minimal configuration as a library 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully minimal configuration as a library 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully minimal configuration as a library 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully minimal configuration as a library 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully minimal configuration custom directory 1`] = ` +{ + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "name": "subdir-test", + "projectType": "application", + "root": "apps/subdir/test", + "sourceRoot": "apps/subdir/test/subdir_test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/subdir/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/subdir/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully minimal configuration custom directory 2`] = ` +"# subdir-test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully minimal configuration custom directory 3`] = ` +"[tool.poetry] +name = "subdir-test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "subdir_test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully minimal configuration custom directory 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello subdir-test" +" +`; + +exports[`application generator individual package should run successfully minimal configuration custom directory 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully minimal configuration with tags 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [ + "one", + "two", + ], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully minimal configuration with tags 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully minimal configuration with tags 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully minimal configuration with tags 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully minimal configuration with tags 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-report html:'../../coverage/apps/test/html'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html coverage report 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-fail-under=100 --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-fail-under=100 --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml' --junitxml='../../reports/apps/test/unittests/junit.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-fail-under=100 --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml' --html='../../reports/apps/test/unittests/html/index.html' --junitxml='../../reports/apps/test/unittests/junit.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 8`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 9`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 10`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" + flake8 = "6.0.0" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 11`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 12`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 13`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with flake8 linter and pytest with no reports 14`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-fail-under=100 --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml' --html='../../reports/apps/test/unittests/html/index.html' --junitxml='../../reports/apps/test/unittests/junit.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies.shared-dev-lib] + path = "../../libs/shared/dev-lib" + develop = true + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 8`] = ` +"# shared-dev-lib + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 9`] = ` +"[tool.poetry] +name = "shared-dev-lib" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = "Proprietary" +readme = "README.md" + + [[tool.poetry.packages]] + include = "shared_dev_lib" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + flake8 = "6.0.0" + autopep8 = "2.0.2" + pytest = "7.3.1" + pytest-sugar = "0.9.7" + pytest-cov = "4.1.0" + pytest-html = "3.2.0" + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 10`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello shared-dev-lib" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with a dev dependency project 11`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/test/dist", + "publish": false, + }, + "outputs": [ + "{projectRoot}/dist", + ], + }, + "install": { + "executor": "@nxlv/python:install", + "options": { + "args": "", + "cacheDir": ".cache/pypoetry", + "debug": false, + "silent": false, + "verbose": false, + }, + }, + "lint": { + "executor": "@nxlv/python:flake8", + "options": { + "outputFile": "reports/apps/test/pylint.txt", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/pylint.txt", + ], + }, + "lock": { + "executor": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "poetry run pytest tests/", + "cwd": "apps/test", + }, + "outputs": [ + "{workspaceRoot}/reports/apps/test/unittests", + "{workspaceRoot}/coverage/apps/test", + ], + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 3`] = ` +"[tool.coverage.run] +branch = true +source = [ "test" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +[tool.pytest.ini_options] +addopts = "--cov --cov-fail-under=100 --cov-report html:'../../coverage/apps/test/html' --cov-report xml:'../../coverage/apps/test/coverage.xml' --html='../../reports/apps/test/unittests/html/index.html' --junitxml='../../reports/apps/test/unittests/junit.xml'" + +[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies.shared-dev-lib] + path = "../../libs/shared/dev-lib" + develop = true + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 5`] = ` +"3.9.5 +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 6`] = ` +"[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 7`] = ` +"from test.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello test" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 8`] = ` +"# shared-dev-lib + +Project description here. +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 9`] = ` +"[tool.poetry] +name = "shared-dev-lib" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = "Proprietary" +readme = "README.md" + + [[tool.poetry.packages]] + include = "shared_dev_lib" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + autopep8 = "^1.0.0" + pytest = "^1.0.0" + pytest-sugar = "^1.0.0" + pytest-cov = "^1.0.0" + pytest-html = "^1.0.0" + flake8 = "^1.0.0" + flake8-isort = "^1.0.0" + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 10`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello shared-dev-lib" +" +`; + +exports[`application generator individual package should run successfully with linting and testing options with an existing dev dependency project 11`] = ` +"3.9.5 +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 5`] = ` +"3.9.5 +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options 6`] = ` +"[tool.poetry] +name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.dependencies.test] + path = "apps/test" + develop = true + +[tool.poetry.group.dev.dependencies] +autopep8 = "2.0.2" + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 5`] = ` +"3.9.5 +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with custom rootPyprojectDependencyGroup 6`] = ` +"[tool.poetry] +name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[tool.poetry.group.dev.dependencies] +autopep8 = "2.0.2" + + [tool.poetry.group.dev.dependencies.test] + path = "apps/test" + develop = true + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 5`] = ` +"3.9.5 +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options with existing custom rootPyprojectDependencyGroup 6`] = ` +"[tool.poetry] +name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[tool.poetry.group.dev.dependencies] +flake8 = "6.0.0" +autopep8 = "2.0.2" + + [tool.poetry.group.dev.dependencies.test] + path = "apps/test" + develop = true + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 1`] = ` +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "test", + "projectType": "application", + "root": "apps/test", + "sourceRoot": "apps/test/test", + "tags": [], + "targets": { + "add": { + "executor": "@nxlv/python:add", + "options": {}, + }, + "build": { + "executor": "@nxlv/python:build", + "options": { + "bundleLocalDependencies": false, + "lockedVersions": false, + "outputPath": "apps/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": "nx:run-commands", + "options": { + "command": "poetry lock --no-update", + "cwd": "apps/test", + }, + }, + "remove": { + "executor": "@nxlv/python:remove", + "options": {}, + }, + "update": { + "executor": "@nxlv/python:update", + "options": {}, + }, + }, +} +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 2`] = ` +"# test + +Project description here. +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 3`] = ` +"[tool.poetry] +name = "test" +version = "1.0.0" +description = "Automatically generated by Nx." +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "test" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 4`] = ` +""""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello test" +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 5`] = ` +"3.9.5 +" +`; + +exports[`application generator shared virtual environment should run successfully with minimal options without rootPyprojectDependencyGroup 6`] = ` +"[tool.poetry] +name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.dependencies.test] + path = "apps/test" + develop = true + +[tool.poetry.group.dev.dependencies] +autopep8 = "2.0.2" + +[build-system] +requires = [ "poetry-core" ] +build-backend = "poetry.core.masonry.api" +" +`; diff --git a/packages/nx-python/src/generators/poetry-project/__test__/custom-template/poetry.toml b/packages/nx-python/src/generators/poetry-project/__test__/custom-template/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/__test__/custom-template/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/packages/nx-python/src/generators/poetry-project/__test__/custom-template/pyproject.toml b/packages/nx-python/src/generators/poetry-project/__test__/custom-template/pyproject.toml new file mode 100644 index 0000000..1d78213 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/__test__/custom-template/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "<%= packageName %>" +version = "1.0.0" +description = "<%= description %>" + + [[tool.poetry.packages]] + include = "<%= moduleName %>" + + [tool.poetry.dependencies] + python = "<%- pyprojectPythonDependency %>" + autopep8 = "^1.5.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/packages/nx-python/src/generators/poetry-project/files/base/README.md b/packages/nx-python/src/generators/poetry-project/files/base/README.md new file mode 100644 index 0000000..1a9566e --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/README.md @@ -0,0 +1,3 @@ +# <%= projectName %> + +Project description here. diff --git a/packages/nx-python/src/generators/poetry-project/files/base/__dot__python-version.template b/packages/nx-python/src/generators/poetry-project/files/base/__dot__python-version.template new file mode 100644 index 0000000..a8884cb --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/__dot__python-version.template @@ -0,0 +1 @@ +<%= pyenvPythonVersion %> diff --git a/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/__init__.py b/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/__init__.py new file mode 100644 index 0000000..6303732 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/__init__.py @@ -0,0 +1 @@ +"""<%= description %>""" diff --git a/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/hello.py b/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/hello.py new file mode 100644 index 0000000..59cd85b --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/__moduleName__/hello.py @@ -0,0 +1,6 @@ +"""Sample Hello World application.""" + + +def hello(): + """Return a friendly greeting.""" + return "Hello <%= projectName %>" diff --git a/packages/nx-python/src/generators/poetry-project/files/base/poetry.toml b/packages/nx-python/src/generators/poetry-project/files/base/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/packages/nx-python/src/generators/poetry-project/files/base/pyproject.toml b/packages/nx-python/src/generators/poetry-project/files/base/pyproject.toml new file mode 100644 index 0000000..bc0b110 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/base/pyproject.toml @@ -0,0 +1,56 @@ +<%if (codeCoverage) { -%> +[tool.coverage.run] +branch = true +source = [ "<%= moduleName %>" ] + +[tool.coverage.report] +exclude_lines = ['if TYPE_CHECKING:'] +show_missing = true + +<% } -%> +<%if (unitTestRunner === 'pytest' && pythonAddopts) { -%> +[tool.pytest.ini_options] +addopts = "<%- pythonAddopts %>" + +<% } -%> +[tool.poetry] +name = "<%= packageName %>" +version = "1.0.0" +description = "<%= description %>" +authors = [ ] +license = 'Proprietary' +readme = 'README.md' + + [[tool.poetry.packages]] + include = "<%= moduleName %>" + + [tool.poetry.dependencies] + python = "<%- pyprojectPythonDependency %>" + +<%if (((individualPackage && !devDependenciesProject) && linter === 'flake8') || ((individualPackage && !devDependenciesProject) && unitTestRunner === 'pytest')) { -%> + [tool.poetry.group.dev.dependencies] + autopep8 = "2.0.2" +<%if (individualPackage && !devDependenciesProject && linter === 'flake8') { -%> + flake8 = "6.0.0" +<% } -%> +<%if (individualPackage && !devDependenciesProject && unitTestRunner === 'pytest') { -%> + pytest = "7.3.1" + pytest-sugar = "0.9.7" +<% } -%> +<%if (individualPackage && !devDependenciesProject && unitTestRunner === 'pytest' && codeCoverage) { -%> + pytest-cov = "4.1.0" +<% } -%> +<%if (individualPackage && !devDependenciesProject && unitTestRunner === 'pytest' && codeCoverage && codeCoverageHtmlReport) { -%> + pytest-html = "3.2.0" +<% } -%> + +<% } -%> +<%if (devDependenciesProject !== '') { -%> + [tool.poetry.group.dev.dependencies.<%- devDependenciesProject %>] + path = "<%- devDependenciesProjectPath %>" + develop = true + +<% } -%> +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/packages/nx-python/src/generators/poetry-project/files/flake8/__dot__flake8.template b/packages/nx-python/src/generators/poetry-project/files/flake8/__dot__flake8.template new file mode 100644 index 0000000..3da962c --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/flake8/__dot__flake8.template @@ -0,0 +1,11 @@ +[flake8] +exclude = + .git, + __pycache__, + build, + dist, + .tox, + venv, + .venv, + .pytest_cache +max-line-length = 120 diff --git a/packages/nx-python/src/generators/poetry-project/files/pytest/tests/__init__.py b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/__init__.py new file mode 100644 index 0000000..d8e96c6 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/__init__.py @@ -0,0 +1 @@ +"""unit tests.""" diff --git a/packages/nx-python/src/generators/poetry-project/files/pytest/tests/conftest.py b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/conftest.py new file mode 100644 index 0000000..547aa99 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/conftest.py @@ -0,0 +1,3 @@ +"""Unit tests configuration module.""" + +pytest_plugins = [] diff --git a/packages/nx-python/src/generators/poetry-project/files/pytest/tests/test_hello.py b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/test_hello.py new file mode 100644 index 0000000..a21e579 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/files/pytest/tests/test_hello.py @@ -0,0 +1,6 @@ +from <%= moduleName %>.hello import hello + + +def test_hello(): + """Test the hello function.""" + assert hello() == "Hello <%= projectName %>" diff --git a/packages/nx-python/src/generators/poetry-project/generator.spec.ts b/packages/nx-python/src/generators/poetry-project/generator.spec.ts new file mode 100644 index 0000000..70b3cf5 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/generator.spec.ts @@ -0,0 +1,568 @@ +import { spawnSyncMock } from '../../utils/mocks/cross-spawn.mock'; +import * as poetryUtils from '../../executors/utils/poetry'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { Tree, readProjectConfiguration } from '@nrwl/devkit'; + +import generator from './generator'; +import { PoetryProjectGeneratorSchema } from './schema'; +import dedent from 'string-dedent'; +import { parse, stringify } from '@iarna/toml'; +import { PyprojectToml } from '../../graph/dependency-graph'; +import path from 'path'; + +describe('application generator', () => { + let checkPoetryExecutableMock: jest.SpyInstance; + let appTree: Tree; + const options: PoetryProjectGeneratorSchema = { + name: 'test', + projectType: 'application', + pyprojectPythonDependency: '', + pyenvPythonVersion: '', + publishable: false, + buildLockedVersions: false, + buildBundleLocalDependencies: false, + linter: 'none', + unitTestRunner: 'none', + rootPyprojectDependencyGroup: 'main', + unitTestHtmlReport: false, + unitTestJUnitReport: false, + codeCoverage: false, + codeCoverageHtmlReport: false, + codeCoverageXmlReport: false, + }; + + beforeEach(() => { + appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + checkPoetryExecutableMock = jest.spyOn( + poetryUtils, + 'checkPoetryExecutable' + ); + checkPoetryExecutableMock.mockResolvedValue(undefined); + spawnSyncMock.mockReturnValue({ status: 0 }); + }); + + it('should throw an exception when the poetry is not installed', async () => { + checkPoetryExecutableMock.mockRejectedValue(new Error('poetry not found')); + + expect(generator(appTree, options)).rejects.toThrow('poetry not found'); + + expect(checkPoetryExecutableMock).toHaveBeenCalled(); + }); + + describe('individual package', () => { + it('should run successfully minimal configuration', async () => { + await generator(appTree, options); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + }); + + it('should run successfully minimal configuration as a library', async () => { + await generator(appTree, { + ...options, + projectType: 'library', + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'libs/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + }); + + it('should run successfully minimal configuration with tags', async () => { + await generator(appTree, { + ...options, + tags: 'one,two', + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + }); + + it('should run successfully minimal configuration custom directory', async () => { + await generator(appTree, { + ...options, + directory: 'subdir', + }); + const config = readProjectConfiguration(appTree, 'subdir-test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/subdir/test'; + const moduleName = 'subdir_test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + }); + + it('should run successfully with flake8 linter', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with no reports', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with no reports', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with html coverage report', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with html,xml coverage reports', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with html,xml coverage reports and threshold', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + codeCoverageThreshold: 100, + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit report', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + codeCoverageThreshold: 100, + unitTestJUnitReport: true, + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with flake8 linter and pytest with html,xml coverage reports, threshold and junit,html report', async () => { + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + codeCoverageThreshold: 100, + unitTestJUnitReport: true, + unitTestHtmlReport: true, + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + }); + + it('should run successfully with linting and testing options with a dev dependency project', async () => { + await generator(appTree, { + ...options, + projectType: 'library', + name: 'dev-lib', + directory: 'shared', + }); + + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + codeCoverageThreshold: 100, + unitTestJUnitReport: true, + unitTestHtmlReport: true, + devDependenciesProject: 'shared-dev-lib', + }); + + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + + assertGeneratedFilesBase( + appTree, + 'libs/shared/dev-lib', + 'shared_dev_lib' + ); + }); + + it('should run successfully with linting and testing options with an existing dev dependency project', async () => { + await generator(appTree, { + ...options, + projectType: 'library', + name: 'dev-lib', + directory: 'shared', + }); + + const pyprojectToml = parse( + appTree.read('libs/shared/dev-lib/pyproject.toml', 'utf-8') + ) as PyprojectToml; + + pyprojectToml.tool.poetry.dependencies = { + python: '>=3.9,<3.11', + autopep8: '^1.0.0', + pytest: '^1.0.0', + 'pytest-sugar': '^1.0.0', + 'pytest-cov': '^1.0.0', + 'pytest-html': '^1.0.0', + flake8: '^1.0.0', + 'flake8-isort': '^1.0.0', + }; + + appTree.write( + 'libs/shared/dev-lib/pyproject.toml', + stringify(pyprojectToml) + ); + + await generator(appTree, { + ...options, + linter: 'flake8', + unitTestRunner: 'pytest', + codeCoverage: true, + codeCoverageHtmlReport: true, + codeCoverageXmlReport: true, + codeCoverageThreshold: 100, + unitTestJUnitReport: true, + unitTestHtmlReport: true, + devDependenciesProject: 'shared-dev-lib', + }); + + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + assertGeneratedFilesBase(appTree, 'apps/test', 'test'); + assertGeneratedFilesFlake8(appTree, 'apps/test'); + assertGeneratedFilesPyTest(appTree, 'apps/test'); + + assertGeneratedFilesBase( + appTree, + 'libs/shared/dev-lib', + 'shared_dev_lib' + ); + }); + }); + + describe('shared virtual environment', () => { + it('should run successfully with minimal options', async () => { + appTree.write( + 'pyproject.toml', + dedent` + [tool.poetry] + name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [build-system] + requires = ["poetry-core"] + build-backend = "poetry.core.masonry.api" + ` + ); + + const callbackTask = await generator(appTree, options); + callbackTask(); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + + expect(appTree.read('pyproject.toml', 'utf-8')).toMatchSnapshot(); + + expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['update', 'test'], { + shell: false, + stdio: 'inherit', + }); + }); + + it('should run successfully with minimal options without rootPyprojectDependencyGroup', async () => { + appTree.write( + 'pyproject.toml', + dedent` + [tool.poetry] + name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [build-system] + requires = ["poetry-core"] + build-backend = "poetry.core.masonry.api" + ` + ); + + const callbackTask = await generator(appTree, { + ...options, + rootPyprojectDependencyGroup: undefined, + }); + callbackTask(); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + + expect(appTree.read('pyproject.toml', 'utf-8')).toMatchSnapshot(); + + expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['update', 'test'], { + shell: false, + stdio: 'inherit', + }); + }); + + it('should run successfully with minimal options with custom rootPyprojectDependencyGroup', async () => { + appTree.write( + 'pyproject.toml', + dedent` + [tool.poetry] + name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [build-system] + requires = ["poetry-core"] + build-backend = "poetry.core.masonry.api" + ` + ); + + const callbackTask = await generator(appTree, { + ...options, + rootPyprojectDependencyGroup: 'dev', + }); + callbackTask(); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + + expect(appTree.read('pyproject.toml', 'utf-8')).toMatchSnapshot(); + + expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['update', 'test'], { + shell: false, + stdio: 'inherit', + }); + }); + + it('should run successfully with minimal options with existing custom rootPyprojectDependencyGroup', async () => { + appTree.write( + 'pyproject.toml', + dedent` + [tool.poetry] + name = "workspace" + + [tool.poetry.dependencies] + python = ">=3.9,<3.11" + + [tool.poetry.group.dev.dependencies] + flake8 = "6.0.0" + + [build-system] + requires = ["poetry-core"] + build-backend = "poetry.core.masonry.api" + ` + ); + + const callbackTask = await generator(appTree, { + ...options, + rootPyprojectDependencyGroup: 'dev', + }); + callbackTask(); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + const projectDirectory = 'apps/test'; + const moduleName = 'test'; + + assertGeneratedFilesBase(appTree, projectDirectory, moduleName); + + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeFalsy(); + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeFalsy(); + + expect(appTree.read('pyproject.toml', 'utf-8')).toMatchSnapshot(); + + expect(spawnSyncMock).toHaveBeenCalledWith('poetry', ['update', 'test'], { + shell: false, + stdio: 'inherit', + }); + }); + }); + + describe('custom template dir', () => { + it('should run successfully with custom template dir', async () => { + await generator(appTree, { + ...options, + templateDir: path.join(__dirname, '__test__/custom-template'), + }); + const config = readProjectConfiguration(appTree, 'test'); + expect(config).toMatchSnapshot(); + + expect( + appTree.read('apps/test/pyproject.toml', 'utf-8') + ).toMatchSnapshot(); + + expect(appTree.read('apps/test/poetry.toml', 'utf-8')).toMatchSnapshot(); + }); + }); +}); + +function assertGeneratedFilesBase( + appTree: Tree, + projectDirectory: string, + moduleName: string +) { + expect(appTree.exists(`${projectDirectory}/README.md`)).toBeTruthy(); + expect( + appTree.read(`${projectDirectory}/README.md`, 'utf8') + ).toMatchSnapshot(); + + expect(appTree.exists(`${projectDirectory}/pyproject.toml`)).toBeTruthy(); + expect( + appTree.read(`${projectDirectory}/pyproject.toml`, 'utf8') + ).toMatchSnapshot(); + + expect( + appTree.exists(`${projectDirectory}/${moduleName}/hello.py`) + ).toBeTruthy(); + + expect( + appTree.read(`${projectDirectory}/${moduleName}/hello.py`, 'utf-8') + ).toMatchSnapshot(); + + expect( + appTree.read(`${projectDirectory}/.python-version`, 'utf-8') + ).toMatchSnapshot(); +} + +function assertGeneratedFilesFlake8(appTree: Tree, projectDirectory: string) { + expect(appTree.exists(`${projectDirectory}/.flake8`)).toBeTruthy(); + expect( + appTree.read(`${projectDirectory}/.flake8`, 'utf-8') + ).toMatchSnapshot(); +} + +function assertGeneratedFilesPyTest(appTree: Tree, projectDirectory: string) { + expect( + appTree.exists(`${projectDirectory}/tests/test_hello.py`) + ).toBeTruthy(); + + expect( + appTree.read(`${projectDirectory}/tests/test_hello.py`, 'utf-8') + ).toMatchSnapshot(); +} diff --git a/packages/nx-python/src/generators/poetry-project/generator.ts b/packages/nx-python/src/generators/poetry-project/generator.ts new file mode 100644 index 0000000..7975ba7 --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/generator.ts @@ -0,0 +1,417 @@ +import { + addProjectConfiguration, + formatFiles, + generateFiles, + getWorkspaceLayout, + names, + offsetFromRoot, + ProjectConfiguration, + readProjectConfiguration, + Tree, +} from '@nrwl/devkit'; +import * as path from 'path'; +import { PoetryProjectGeneratorSchema } from './schema'; +import { checkPoetryExecutable, runPoetry } from '../../executors/utils/poetry'; +import { + PyprojectToml, + PyprojectTomlDependencies, +} from '../../graph/dependency-graph'; +import { parse, stringify } from '@iarna/toml'; +import chalk from 'chalk'; +import _ from 'lodash'; + +interface NormalizedSchema extends PoetryProjectGeneratorSchema { + projectName: string; + projectRoot: string; + projectDirectory: string; + individualPackage: boolean; + devDependenciesProjectPath?: string; + pythonAddopts?: string; + parsedTags: string[]; +} + +function normalizeOptions( + tree: Tree, + options: PoetryProjectGeneratorSchema +): NormalizedSchema { + const name = names(options.name).fileName; + const projectDirectory = options.directory + ? `${names(options.directory).fileName}/${name}` + : name; + const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); + const projectRoot = `${ + options.projectType === 'application' + ? getWorkspaceLayout(tree).appsDir + : getWorkspaceLayout(tree).libsDir + }/${projectDirectory}`; + const parsedTags = options.tags + ? options.tags.split(',').map((s) => s.trim()) + : []; + + const newOptions = _.clone(options) as NormalizedSchema; + + if (!options.pyprojectPythonDependency) { + newOptions.pyprojectPythonDependency = '>=3.9,<3.11'; + } + + if (!options.pyenvPythonVersion) { + newOptions.pyenvPythonVersion = '3.9.5'; + } + + if (!options.moduleName) { + newOptions.moduleName = projectName.replace(new RegExp('-', 'g'), '_'); + } + + if (!options.packageName) { + newOptions.packageName = projectName; + } + + if (!options.description) { + newOptions.description = 'Automatically generated by Nx.'; + } + if (options.devDependenciesProject) { + const projectConfig = readProjectConfiguration( + tree, + options.devDependenciesProject + ); + newOptions.devDependenciesProjectPath = path.relative( + projectRoot, + projectConfig.root + ); + } + + let pythonAddopts = undefined; + + if (options.unitTestRunner === 'pytest') { + const args = []; + const offset = offsetFromRoot(projectRoot); + if (options.codeCoverage) { + args.push('--cov'); + } + if (options.codeCoverageThreshold) { + args.push(`--cov-fail-under=${options.codeCoverageThreshold}`); + } + if (options.codeCoverage && options.codeCoverageHtmlReport) { + args.push(`--cov-report html:'${offset}coverage/${projectRoot}/html'`); + } + + if (options.codeCoverage && options.codeCoverageXmlReport) { + args.push( + `--cov-report xml:'${offset}coverage/${projectRoot}/coverage.xml'` + ); + } + + if (options.unitTestHtmlReport) { + args.push( + `--html='${offset}reports/${projectRoot}/unittests/html/index.html'` + ); + } + + if (options.unitTestJUnitReport) { + args.push( + `--junitxml='${offset}reports/${projectRoot}/unittests/junit.xml'` + ); + } + + pythonAddopts = args.join(' '); + } + + if (options.unitTestRunner === 'none') { + newOptions.unitTestHtmlReport = false; + newOptions.unitTestJUnitReport = false; + newOptions.codeCoverage = false; + newOptions.codeCoverageHtmlReport = false; + newOptions.codeCoverageXmlReport = false; + newOptions.codeCoverageThreshold = undefined; + } + + return { + ...options, + ...newOptions, + devDependenciesProject: options.devDependenciesProject || '', + individualPackage: !tree.exists('pyproject.toml'), + pythonAddopts, + projectName, + projectRoot, + projectDirectory, + parsedTags, + }; +} + +function addFiles(tree: Tree, options: NormalizedSchema) { + const templateOptions = { + ...options, + ...names(options.name), + offsetFromRoot: offsetFromRoot(options.projectRoot), + template: '', + dot: '.', + }; + if (options.templateDir) { + generateFiles( + tree, + path.join(options.templateDir), + options.projectRoot, + templateOptions + ); + return; + } + + generateFiles( + tree, + path.join(__dirname, 'files', 'base'), + options.projectRoot, + templateOptions + ); + + if (options.unitTestRunner === 'pytest') { + generateFiles( + tree, + path.join(__dirname, 'files', 'pytest'), + options.projectRoot, + templateOptions + ); + } + + if (options.linter === 'flake8') { + generateFiles( + tree, + path.join(__dirname, 'files', 'flake8'), + options.projectRoot, + templateOptions + ); + } +} + +function updateRootPyprojectToml( + host: Tree, + normalizedOptions: NormalizedSchema +) { + if (normalizedOptions.devDependenciesProject) { + const projectConfig = readProjectConfiguration( + host, + normalizedOptions.devDependenciesProject + ); + const devDepsPyprojectTomlPath = path.join( + projectConfig.root, + 'pyproject.toml' + ); + + const devDepsPyprojectToml = parse( + host.read(devDepsPyprojectTomlPath, 'utf-8') + ) as PyprojectToml; + + const { changed, dependencies } = addTestDependencies( + devDepsPyprojectToml.tool.poetry.dependencies, + normalizedOptions + ); + + if (changed) { + devDepsPyprojectToml.tool.poetry.dependencies = { + ...devDepsPyprojectToml.tool.poetry.dependencies, + ...dependencies, + }; + + host.write(devDepsPyprojectTomlPath, stringify(devDepsPyprojectToml)); + } + } + + if (!normalizedOptions.individualPackage) { + const rootPyprojectToml = parse( + host.read('./pyproject.toml', 'utf-8') + ) as PyprojectToml; + + const group = normalizedOptions.rootPyprojectDependencyGroup ?? 'main'; + + if (group === 'main') { + rootPyprojectToml.tool.poetry.dependencies[ + normalizedOptions.packageName + ] = { + path: normalizedOptions.projectRoot, + develop: true, + }; + } else { + rootPyprojectToml.tool.poetry.group = { + ...(rootPyprojectToml.tool.poetry.group || {}), + [group]: { + ...(rootPyprojectToml.tool.poetry.group?.[group] || {}), + dependencies: { + ...(rootPyprojectToml.tool.poetry.group?.[group]?.dependencies || + {}), + [normalizedOptions.packageName]: { + path: normalizedOptions.projectRoot, + develop: true, + }, + }, + }, + }; + } + + if (!normalizedOptions.devDependenciesProject) { + const { changed, dependencies } = addTestDependencies( + rootPyprojectToml.tool.poetry.group?.dev?.dependencies || {}, + normalizedOptions + ); + + if (changed) { + rootPyprojectToml.tool.poetry.group = { + ...(rootPyprojectToml.tool.poetry.group || {}), + dev: { + dependencies: dependencies, + }, + }; + } + } + + host.write('./pyproject.toml', stringify(rootPyprojectToml)); + } +} + +function addTestDependencies( + dependencies: PyprojectTomlDependencies, + normalizedOptions: NormalizedSchema +) { + const originalDependencies = _.clone(dependencies); + + if (normalizedOptions.linter === 'flake8' && !dependencies['flake8']) { + dependencies['flake8'] = '6.0.0'; + } + + if (!dependencies['autopep8']) { + dependencies['autopep8'] = '2.0.2'; + } + + if ( + normalizedOptions.unitTestRunner === 'pytest' && + !dependencies['pytest'] + ) { + dependencies['pytest'] = '7.3.1'; + } + if ( + normalizedOptions.unitTestRunner === 'pytest' && + !dependencies['pytest-sugar'] + ) { + dependencies['pytest-sugar'] = '0.9.7'; + } + + if ( + normalizedOptions.unitTestRunner === 'pytest' && + normalizedOptions.codeCoverage && + !dependencies['pytest-cov'] + ) { + dependencies['pytest-cov'] = '4.1.0'; + } + + if ( + normalizedOptions.unitTestRunner === 'pytest' && + normalizedOptions.codeCoverageHtmlReport && + !dependencies['pytest-html'] + ) { + dependencies['pytest-html'] = '3.2.0'; + } + + return { + changed: !_.isEqual(originalDependencies, dependencies), + dependencies, + }; +} + +function updateRootPoetryLock(host: Tree, normalizedOptions: NormalizedSchema) { + if (host.exists('./pyproject.toml')) { + console.log(chalk` Updating root {bgBlue poetry.lock}...`); + const updateArgs = ['update', normalizedOptions.packageName]; + runPoetry(updateArgs, { log: false }); + console.log(chalk`\n {bgBlue poetry.lock} updated.\n`); + } +} + +export default async function ( + tree: Tree, + options: PoetryProjectGeneratorSchema +) { + await checkPoetryExecutable(); + + const normalizedOptions = normalizeOptions(tree, options); + + const targets: ProjectConfiguration['targets'] = { + lock: { + executor: 'nx:run-commands', + options: { + command: 'poetry lock --no-update', + cwd: normalizedOptions.projectRoot, + }, + }, + add: { + executor: '@nxlv/python:add', + options: {}, + }, + update: { + executor: '@nxlv/python:update', + options: {}, + }, + remove: { + executor: '@nxlv/python:remove', + options: {}, + }, + build: { + executor: '@nxlv/python:build', + outputs: ['{projectRoot}/dist'], + options: { + outputPath: `${normalizedOptions.projectRoot}/dist`, + publish: normalizedOptions.publishable, + lockedVersions: normalizedOptions.buildLockedVersions, + bundleLocalDependencies: normalizedOptions.buildBundleLocalDependencies, + }, + }, + install: { + executor: '@nxlv/python:install', + options: { + silent: false, + args: '', + cacheDir: `.cache/pypoetry`, + verbose: false, + debug: false, + }, + }, + }; + + if (options.linter === 'flake8') { + targets.lint = { + executor: '@nxlv/python:flake8', + outputs: [ + `{workspaceRoot}/reports/${normalizedOptions.projectRoot}/pylint.txt`, + ], + options: { + outputFile: `reports/${normalizedOptions.projectRoot}/pylint.txt`, + }, + }; + } + + if (options.unitTestRunner === 'pytest') { + targets.test = { + executor: 'nx:run-commands', + outputs: [ + `{workspaceRoot}/reports/${normalizedOptions.projectRoot}/unittests`, + `{workspaceRoot}/coverage/${normalizedOptions.projectRoot}`, + ], + options: { + command: `poetry run pytest tests/`, + cwd: normalizedOptions.projectRoot, + }, + }; + } + + addProjectConfiguration(tree, normalizedOptions.projectName, { + root: normalizedOptions.projectRoot, + projectType: normalizedOptions.projectType, + sourceRoot: `${normalizedOptions.projectRoot}/${normalizedOptions.moduleName}`, + targets, + tags: normalizedOptions.parsedTags, + }); + addFiles(tree, normalizedOptions); + updateRootPyprojectToml(tree, normalizedOptions); + await formatFiles(tree); + + return () => { + updateRootPoetryLock(tree, normalizedOptions); + }; +} diff --git a/packages/nx-python/src/generators/poetry-project/schema.d.ts b/packages/nx-python/src/generators/poetry-project/schema.d.ts new file mode 100644 index 0000000..3b926bb --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/schema.d.ts @@ -0,0 +1,25 @@ +export interface PoetryProjectGeneratorSchema { + name: string; + projectType: 'application' | 'library'; + packageName?: string; + moduleName?: string; + description?: string; + pyprojectPythonDependency: string; + pyenvPythonVersion: string; + publishable: boolean; + buildLockedVersions: boolean; + buildBundleLocalDependencies: boolean; + linter: 'flake8' | 'none'; + unitTestRunner: 'pytest' | 'none'; + devDependenciesProject?: string; + rootPyprojectDependencyGroup: string; + unitTestHtmlReport: boolean; + unitTestJUnitReport: boolean; + codeCoverage: boolean; + codeCoverageHtmlReport: boolean; + codeCoverageXmlReport: boolean; + codeCoverageThreshold?: number; + tags?: string; + directory?: string; + templateDir?: string; +} diff --git a/packages/nx-python/src/generators/poetry-project/schema.json b/packages/nx-python/src/generators/poetry-project/schema.json new file mode 100644 index 0000000..8eda67f --- /dev/null +++ b/packages/nx-python/src/generators/poetry-project/schema.json @@ -0,0 +1,126 @@ +{ + "$schema": "http://json-schema.org/schema", + "cli": "nx", + "$id": "PoetryPythonProject", + "title": "Generate a new Poetry Python Project.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "", + "$default": { + "$source": "argv", + "index": 0 + }, + "x-prompt": "What name would you like to use?" + }, + "projectType": { + "type": "string", + "description": "Project type", + "default": "application", + "enum": ["application", "library"] + }, + "templateDir": { + "type": "string", + "description": "Custom template directory, this will override the default template, if not provided the default template will be used" + }, + "packageName": { + "type": "string", + "description": "Python package name" + }, + "moduleName": { + "type": "string", + "description": "Python module name" + }, + "description": { + "type": "string", + "description": "Project short description" + }, + "pyprojectPythonDependency": { + "type": "string", + "description": "Pyproject python dependency version range", + "default": ">=3.9,<3.11" + }, + "pyenvPythonVersion": { + "type": "string", + "description": "Pyenv .python-version content", + "default": "3.8.11" + }, + "publishable": { + "type": "boolean", + "description": "Project is publishable", + "default": true + }, + "buildLockedVersions": { + "type": "boolean", + "description": "Use locked versions for build dependencies", + "default": true + }, + "buildBundleLocalDependencies": { + "type": "boolean", + "description": "Bundle local dependencies", + "default": true + }, + "linter": { + "type": "string", + "description": "Project linter", + "default": "flake8", + "enum": ["flake8", "none"] + }, + "unitTestRunner": { + "type": "string", + "description": "Project unit test runner", + "default": "pytest", + "enum": ["pytest", "none"] + }, + "devDependenciesProject": { + "type": "string", + "description": "This approach installs all the missing dev dependencies in a separate project (optional)", + "x-dropdown": "projects" + }, + "rootPyprojectDependencyGroup": { + "type": "string", + "description": "If a shared pyproject.toml is used, which dependency group does this new project should belong to", + "default": "main" + }, + "unitTestHtmlReport": { + "type": "boolean", + "description": "Generate html report for unit tests", + "default": true + }, + "unitTestJUnitReport": { + "type": "boolean", + "description": "Generate junit report for unit tests", + "default": true + }, + "codeCoverage": { + "type": "boolean", + "description": "Generate code coverage report", + "default": true + }, + "codeCoverageHtmlReport": { + "type": "boolean", + "description": "Generate html report for code coverage", + "default": true + }, + "codeCoverageXmlReport": { + "type": "boolean", + "description": "Generate Xml report for code coverage", + "default": true + }, + "codeCoverageThreshold": { + "type": "number", + "description": "Code coverage threshold" + }, + "tags": { + "type": "string", + "description": "Add tags to the project (used for linting)", + "alias": "t" + }, + "directory": { + "type": "string", + "description": "A directory where the project is placed" + } + }, + "required": ["name", "projectType"] +} diff --git a/packages/nx-python/src/generators/project/schema.json b/packages/nx-python/src/generators/project/schema.json index 93b8cf9..78cc91c 100644 --- a/packages/nx-python/src/generators/project/schema.json +++ b/packages/nx-python/src/generators/project/schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/schema", "cli": "nx", "$id": "NxPythonProject", - "title": "", + "title": "Generate a Python project (Deprecated, please use 'poetry-project' generator)", "type": "object", "properties": { "name": { diff --git a/packages/nx-python/tsconfig.lib.json b/packages/nx-python/tsconfig.lib.json index 188872b..85c1f1c 100644 --- a/packages/nx-python/tsconfig.lib.json +++ b/packages/nx-python/tsconfig.lib.json @@ -11,6 +11,7 @@ "jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts", - "**/*.mock.ts" + "**/*.mock.ts", + "**/__test__/**/*" ] }