@aws/nx-plugin 1.0.0-rc.89 → 1.0.0-rc.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/executors.json +5 -0
- package/generators.json +2 -1
- package/migrations.json +47 -2
- package/package.json +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +24 -12
- package/src/infra/app/generator.js +9 -7
- package/src/infra/app/generator.js.map +1 -1
- package/src/mcp-server/generator-info.d.ts +5 -0
- package/src/mcp-server/generator-info.js +6 -2
- package/src/mcp-server/generator-info.js.map +1 -1
- package/src/migrations/latest/add-assemble-target/metadata.json +3 -0
- package/src/migrations/latest/add-assemble-target/migration.d.ts +6 -0
- package/src/migrations/latest/add-assemble-target/migration.js +241 -0
- package/src/migrations/latest/add-assemble-target/migration.js.map +1 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/metadata.json +3 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.d.ts +6 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.js +94 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +1 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/metadata.json +3 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.d.ts +6 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js +67 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +1 -0
- package/src/migrations/latest/docker-target-cache-soundness/metadata.json +3 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.d.ts +6 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.js +95 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +1 -0
- package/src/migrations/latest/open-api-codegen-executor/metadata.json +3 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.d.ts +6 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.js +100 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.js.map +1 -0
- package/src/migrations/latest/python-test-input-scoping/metadata.json +3 -0
- package/src/migrations/latest/python-test-input-scoping/migration.d.ts +6 -0
- package/src/migrations/latest/python-test-input-scoping/migration.js +142 -0
- package/src/migrations/latest/python-test-input-scoping/migration.js.map +1 -0
- package/src/migrations/latest/terraform-fmt-check/metadata.json +3 -0
- package/src/migrations/latest/terraform-fmt-check/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-fmt-check/migration.js +165 -0
- package/src/migrations/latest/terraform-fmt-check/migration.js.map +1 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/metadata.json +3 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.js +164 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +1 -0
- package/src/migrations/latest/vitest-coverage-output-dir/metadata.json +3 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.d.ts +6 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.js +177 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +1 -0
- package/src/open-api/codegen/executor-schema.d.js +6 -0
- package/src/open-api/codegen/executor-schema.d.js.map +1 -0
- package/src/open-api/codegen/executor-schema.d.ts +18 -0
- package/src/open-api/codegen/executor-schema.json +33 -0
- package/src/open-api/codegen/executor.d.ts +18 -0
- package/src/open-api/codegen/executor.js +56 -0
- package/src/open-api/codegen/executor.js.map +1 -0
- package/src/preset/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/py/agent/generator.js +21 -22
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/agent/react-connection/generator.js +9 -0
- package/src/py/agent/react-connection/generator.js.map +1 -1
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +0 -30
- package/src/py/fast-api/react/open-api.js +19 -7
- package/src/py/fast-api/react/open-api.js.map +1 -1
- package/src/py/mcp-server/generator.js +4 -4
- package/src/py/mcp-server/generator.js.map +1 -1
- package/src/py/project/generator.d.ts +9 -0
- package/src/py/project/generator.js +51 -1
- package/src/py/project/generator.js.map +1 -1
- package/src/py/rdb/generator.js +10 -4
- package/src/py/rdb/generator.js.map +1 -1
- package/src/smithy/project/__snapshots__/generator.spec.ts.snap +15 -0
- package/src/smithy/project/generator.js +10 -0
- package/src/smithy/project/generator.js.map +1 -1
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +7 -0
- package/src/terraform/project/files/application/scripts/env.ts.template +11 -0
- package/src/terraform/project/files/application/scripts/init.ts.template +2 -1
- package/src/terraform/project/files/application/src/providers.tf.template +2 -2
- package/src/terraform/project/generator.d.ts +11 -1
- package/src/terraform/project/generator.js +104 -20
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/generator.js +2 -2
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/ts/agent/generator.js +4 -7
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/astro-docs/generator.js +5 -0
- package/src/ts/astro-docs/generator.js.map +1 -1
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +0 -30
- package/src/ts/dynamodb/generator.js +3 -0
- package/src/ts/dynamodb/generator.js.map +1 -1
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +10 -1
- package/src/ts/lib/__snapshots__/vitest.spec.ts.snap +1 -1
- package/src/ts/lib/generator.d.ts +16 -0
- package/src/ts/lib/generator.js +31 -5
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/vitest.d.ts +11 -0
- package/src/ts/lib/vitest.js +31 -2
- package/src/ts/lib/vitest.js.map +1 -1
- package/src/ts/mcp-server/generator.js +4 -7
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/rdb/generator.js +8 -5
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +27 -11
- package/src/ts/react-website/app/generator.js +9 -1
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/ts/sync/generator.js +19 -2
- package/src/ts/sync/generator.js.map +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js +3 -3
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/api-constructs/api-constructs.js +2 -2
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/open-api-metadata.js +15 -36
- package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
- package/src/utils/api-constructs/trpc-operations-metadata.js +9 -3
- package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -1
- package/src/utils/bundle/bundle.js +13 -4
- package/src/utils/bundle/bundle.js.map +1 -1
- package/src/utils/connection/open-api/react.js +7 -17
- package/src/utils/connection/open-api/react.js.map +1 -1
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +2 -2
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -1
- package/src/utils/docker.d.ts +22 -10
- package/src/utils/docker.js +27 -17
- package/src/utils/docker.js.map +1 -1
- package/src/utils/dynamodb-constructs/dynamodb-constructs.js +2 -2
- package/src/utils/dynamodb-constructs/dynamodb-constructs.js.map +1 -1
- package/src/utils/files/common/scripts/src/dynamodb/start-container.ts.template +0 -15
- package/src/utils/files/common/scripts/src/rdb/shared/start-container.ts.template +0 -15
- package/src/utils/format.d.ts +5 -0
- package/src/utils/format.js +5 -0
- package/src/utils/format.js.map +1 -1
- package/src/utils/function-constructs/function-constructs.js +2 -2
- package/src/utils/function-constructs/function-constructs.js.map +1 -1
- package/src/utils/generators.d.ts +33 -0
- package/src/utils/generators.js +18 -3
- package/src/utils/generators.js.map +1 -1
- package/src/utils/init.js +4 -6
- package/src/utils/init.js.map +1 -1
- package/src/utils/mock-project-graph.js +5 -2
- package/src/utils/mock-project-graph.js.map +1 -1
- package/src/utils/nx.d.ts +19 -0
- package/src/utils/nx.js +23 -0
- package/src/utils/nx.js.map +1 -1
- package/src/utils/open-api-codegen-target.d.ts +28 -0
- package/src/utils/open-api-codegen-target.js +31 -0
- package/src/utils/open-api-codegen-target.js.map +1 -0
- package/src/utils/rdb-constructs/rdb-constructs.js +2 -2
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
- package/src/utils/website-constructs/website-constructs.js +2 -2
- package/src/utils/website-constructs/website-constructs.js.map +1 -1
|
@@ -18,19 +18,31 @@ import { sortObjectKeys } from "../../../utils/object.js";
|
|
|
18
18
|
// Instrument the script as part of the fastapi project build
|
|
19
19
|
const fastApiOpenApiDist = joinPathFragments('dist', project.root, 'openapi');
|
|
20
20
|
const specPath = joinPathFragments(fastApiOpenApiDist, 'openapi.json');
|
|
21
|
+
const withOpenApi = (target)=>({
|
|
22
|
+
...project.targets?.[target],
|
|
23
|
+
dependsOn: [
|
|
24
|
+
...(project.targets?.[target]?.dependsOn ?? []).filter((t)=>t !== 'openapi'),
|
|
25
|
+
'openapi'
|
|
26
|
+
]
|
|
27
|
+
});
|
|
21
28
|
updateProjectConfiguration(tree, project.name, {
|
|
22
29
|
...project,
|
|
23
30
|
targets: sortObjectKeys({
|
|
24
31
|
...project.targets,
|
|
25
|
-
build:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
'openapi'
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
+
build: withOpenApi('build'),
|
|
33
|
+
// The spec is a deployable artifact: the infrastructure derives the API's
|
|
34
|
+
// routes from it, so a deploy needs it as much as a build does.
|
|
35
|
+
assemble: withOpenApi('assemble'),
|
|
32
36
|
openapi: {
|
|
33
37
|
cache: true,
|
|
38
|
+
// The spec serialises models a dependency may own, and this target has
|
|
39
|
+
// no `dependsOn` for `default`'s transitive `dependentTasksOutputFiles`
|
|
40
|
+
// to resolve against — so `^production` is the only edge to the
|
|
41
|
+
// dependency, and without it a model change there serves a stale spec.
|
|
42
|
+
inputs: [
|
|
43
|
+
'production',
|
|
44
|
+
'^production'
|
|
45
|
+
],
|
|
34
46
|
executor: 'nx:run-commands',
|
|
35
47
|
outputs: [
|
|
36
48
|
'{workspaceRoot}/dist/{projectRoot}/openapi'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/fast-api/react/open-api.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { snakeCase } from '../../../utils/names.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\n\nexport interface AddOpenApiGenerationOptions {\n project: ProjectConfiguration;\n}\n\n/**\n * Adds FastAPI -> OpenApi spec generation as part of the FastAPI project build\n */\nexport const addOpenApiGeneration = (\n tree: Tree,\n { project }: AddOpenApiGenerationOptions,\n): { specPath: string } => {\n const moduleName = getFastApiModuleName(project);\n\n // Add OpenAPI spec generation script to FastAPI spec, preserving an existing\n // copy so re-running does not reformat it nondeterministically\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files/fast-api'),\n project.root,\n {\n moduleName,\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Instrument the script as part of the fastapi project build\n const fastApiOpenApiDist = joinPathFragments('dist', project.root, 'openapi');\n const specPath = joinPathFragments(fastApiOpenApiDist, 'openapi.json');\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/fast-api/react/open-api.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { snakeCase } from '../../../utils/names.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\n\nexport interface AddOpenApiGenerationOptions {\n project: ProjectConfiguration;\n}\n\n/**\n * Adds FastAPI -> OpenApi spec generation as part of the FastAPI project build\n */\nexport const addOpenApiGeneration = (\n tree: Tree,\n { project }: AddOpenApiGenerationOptions,\n): { specPath: string } => {\n const moduleName = getFastApiModuleName(project);\n\n // Add OpenAPI spec generation script to FastAPI spec, preserving an existing\n // copy so re-running does not reformat it nondeterministically\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files/fast-api'),\n project.root,\n {\n moduleName,\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Instrument the script as part of the fastapi project build\n const fastApiOpenApiDist = joinPathFragments('dist', project.root, 'openapi');\n const specPath = joinPathFragments(fastApiOpenApiDist, 'openapi.json');\n const withOpenApi = (target: string) => ({\n ...project.targets?.[target],\n dependsOn: [\n ...(project.targets?.[target]?.dependsOn ?? []).filter(\n (t) => t !== 'openapi',\n ),\n 'openapi',\n ],\n });\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: sortObjectKeys({\n ...project.targets,\n build: withOpenApi('build'),\n // The spec is a deployable artifact: the infrastructure derives the API's\n // routes from it, so a deploy needs it as much as a build does.\n assemble: withOpenApi('assemble'),\n openapi: {\n cache: true,\n // The spec serialises models a dependency may own, and this target has\n // no `dependsOn` for `default`'s transitive `dependentTasksOutputFiles`\n // to resolve against — so `^production` is the only edge to the\n // dependency, and without it a model change there serves a stale spec.\n inputs: ['production', '^production'],\n executor: 'nx:run-commands',\n outputs: ['{workspaceRoot}/dist/{projectRoot}/openapi'],\n options: {\n commands: [\n 'uv run python {projectRoot}/scripts/generate_open_api.py \"dist/{projectRoot}/openapi/openapi.json\"',\n ],\n },\n },\n }),\n });\n\n return { specPath };\n};\n\nconst getFastApiModuleName = (projectConfig: ProjectConfiguration): string => {\n if (projectConfig.sourceRoot) {\n const sourceRootParts = projectConfig.sourceRoot.split('/');\n return sourceRootParts[sourceRootParts.length - 1];\n }\n const apiName = (projectConfig.metadata as any)?.apiName;\n if (apiName) {\n return snakeCase(apiName);\n }\n new Error(`Could not determine sourceRoot for project ${projectConfig.name}`);\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","snakeCase","sortObjectKeys","addOpenApiGeneration","tree","project","moduleName","getFastApiModuleName","dirname","root","overwriteStrategy","KeepExisting","fastApiOpenApiDist","specPath","withOpenApi","target","targets","dependsOn","filter","t","name","build","assemble","openapi","cache","inputs","executor","outputs","options","commands","projectConfig","sourceRoot","sourceRootParts","split","length","apiName","metadata","Error"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,EAGjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,SAAS,QAAQ,0BAA0B;AACpD,SAASC,cAAc,QAAQ,2BAA2B;AAM1D;;CAEC,GACD,OAAO,MAAMC,uBAAuB,CAClCC,MACA,EAAEC,OAAO,EAA+B;IAExC,MAAMC,aAAaC,qBAAqBF;IAExC,6EAA6E;IAC7E,+DAA+D;IAC/DR,cACEO,MACAN,kBAAkB,YAAYU,OAAO,EAAE,mBACvCH,QAAQI,IAAI,EACZ;QACEH;IACF,GACA;QACEI,mBAAmBX,kBAAkBY,YAAY;IACnD;IAGF,6DAA6D;IAC7D,MAAMC,qBAAqBd,kBAAkB,QAAQO,QAAQI,IAAI,EAAE;IACnE,MAAMI,WAAWf,kBAAkBc,oBAAoB;IACvD,MAAME,cAAc,CAACC,SAAoB,CAAA;YACvC,GAAGV,QAAQW,OAAO,EAAE,CAACD,OAAO;YAC5BE,WAAW;mBACN,AAACZ,CAAAA,QAAQW,OAAO,EAAE,CAACD,OAAO,EAAEE,aAAa,EAAE,AAAD,EAAGC,MAAM,CACpD,CAACC,IAAMA,MAAM;gBAEf;aACD;QACH,CAAA;IACAnB,2BAA2BI,MAAMC,QAAQe,IAAI,EAAE;QAC7C,GAAGf,OAAO;QACVW,SAASd,eAAe;YACtB,GAAGG,QAAQW,OAAO;YAClBK,OAAOP,YAAY;YACnB,0EAA0E;YAC1E,gEAAgE;YAChEQ,UAAUR,YAAY;YACtBS,SAAS;gBACPC,OAAO;gBACP,uEAAuE;gBACvE,wEAAwE;gBACxE,gEAAgE;gBAChE,uEAAuE;gBACvEC,QAAQ;oBAAC;oBAAc;iBAAc;gBACrCC,UAAU;gBACVC,SAAS;oBAAC;iBAA6C;gBACvDC,SAAS;oBACPC,UAAU;wBACR;qBACD;gBACH;YACF;QACF;IACF;IAEA,OAAO;QAAEhB;IAAS;AACpB,EAAE;AAEF,MAAMN,uBAAuB,CAACuB;IAC5B,IAAIA,cAAcC,UAAU,EAAE;QAC5B,MAAMC,kBAAkBF,cAAcC,UAAU,CAACE,KAAK,CAAC;QACvD,OAAOD,eAAe,CAACA,gBAAgBE,MAAM,GAAG,EAAE;IACpD;IACA,MAAMC,UAAWL,cAAcM,QAAQ,EAAUD;IACjD,IAAIA,SAAS;QACX,OAAOlC,UAAUkC;IACnB;IACA,IAAIE,MAAM,CAAC,2CAA2C,EAAEP,cAAcV,IAAI,EAAE;AAC9E"}
|
|
@@ -7,7 +7,7 @@ import { addMcpServerInfra } from "../../utils/agent-core-constructs/agent-core-
|
|
|
7
7
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
8
8
|
import { resolveContainers } from "../../utils/containers.js";
|
|
9
9
|
import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
|
|
10
|
-
import { addDockerScanTarget, DOCKER_DEPENDENCIES } from "../../utils/docker.js";
|
|
10
|
+
import { addDockerScanTarget, DOCKER_DEPENDENCIES, IMAGE_BUILD_CACHE } from "../../utils/docker.js";
|
|
11
11
|
import { formatFilesInSubtree } from "../../utils/format.js";
|
|
12
12
|
import { FS_DEPENDENCIES, FsCommands } from "../../utils/fs.js";
|
|
13
13
|
import { resolveIac } from "../../utils/iac.js";
|
|
@@ -15,7 +15,7 @@ import { installDependencies } from "../../utils/install.js";
|
|
|
15
15
|
import { addGeneratorMetricsIfApplicable } from "../../utils/metrics.js";
|
|
16
16
|
import { kebabCase, toClassName, toSnakeCase } from "../../utils/names.js";
|
|
17
17
|
import { getNpmScope } from "../../utils/npm-scope.js";
|
|
18
|
-
import { addComponentDevTarget, addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../utils/nx.js";
|
|
18
|
+
import { addArtifactDependencyToTargets, addComponentDevTarget, addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../utils/nx.js";
|
|
19
19
|
import { toProjectRelativePath } from "../../utils/paths.js";
|
|
20
20
|
import { registerPnpmBuiltDependencies } from "../../utils/pnpm-workspace.js";
|
|
21
21
|
import { assignPort } from "../../utils/port.js";
|
|
@@ -109,7 +109,7 @@ export const pyMcpServerGenerator = async (tree, options)=>{
|
|
|
109
109
|
// Add a docker target that prepares the docker context and builds the image
|
|
110
110
|
const fs = new FsCommands(tree, DEPENDENCIES);
|
|
111
111
|
project.targets[dockerTargetName] = {
|
|
112
|
-
cache:
|
|
112
|
+
cache: IMAGE_BUILD_CACHE,
|
|
113
113
|
executor: 'nx:run-commands',
|
|
114
114
|
options: {
|
|
115
115
|
commands: [
|
|
@@ -126,7 +126,7 @@ export const pyMcpServerGenerator = async (tree, options)=>{
|
|
|
126
126
|
]
|
|
127
127
|
};
|
|
128
128
|
addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
|
|
129
|
-
|
|
129
|
+
addArtifactDependencyToTargets(project, 'docker');
|
|
130
130
|
addDockerScanTarget(tree, {
|
|
131
131
|
project,
|
|
132
132
|
containerEngine: containers,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { toProjectRelativePath } from '../../utils/paths.js';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace.js';\nimport { assignPort } from '../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n // The MCP inspector has a postinstall script that cascades installs into its\n // client packages, which no-ops when the package is installed as a dependency.\n // Register it as an explicitly-rejected build so pnpm 11's default\n // `strictDepBuilds=true` skips it instead of failing the install.\n registerPnpmBuiltDependencies(tree, {\n '@modelcontextprotocol/inspector': false,\n });\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","registerPnpmBuiltDependencies","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n IMAGE_BUILD_CACHE,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addArtifactDependencyToTargets,\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { toProjectRelativePath } from '../../utils/paths.js';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace.js';\nimport { assignPort } from '../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: IMAGE_BUILD_CACHE,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addArtifactDependencyToTargets(project, 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n // The MCP inspector has a postinstall script that cascades installs into its\n // client packages, which no-ops when the package is installed as a dependency.\n // Register it as an explicitly-rejected build so pnpm 11's default\n // `strictDepBuilds=true` skips it instead of failing the install.\n registerPnpmBuiltDependencies(tree, {\n '@modelcontextprotocol/inspector': false,\n });\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","IMAGE_BUILD_CACHE","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addArtifactDependencyToTargets","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","registerPnpmBuiltDependencies","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
|
|
@@ -19,6 +19,15 @@ export declare const DEPENDENCIES: import("../../utils/declared-dependencies.js"
|
|
|
19
19
|
readonly root: true;
|
|
20
20
|
}]>;
|
|
21
21
|
export declare const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo;
|
|
22
|
+
export declare const PYTHON_TEST_FILE_EXCLUSIONS: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Excludes Python test files from the `production` named input, preserving any
|
|
25
|
+
* entries already present (including user additions).
|
|
26
|
+
*
|
|
27
|
+
* The input is created when absent: the Python targets reference `production`,
|
|
28
|
+
* and Nx fails hard on a named input that is not defined.
|
|
29
|
+
*/
|
|
30
|
+
export declare const addPythonTestExclusionsToProductionInput: (tree: Tree) => void;
|
|
22
31
|
export interface PyProjectDetails {
|
|
23
32
|
/**
|
|
24
33
|
* Fully qualified Nx project id including scope, in dot notation (eg foo.bar).
|
|
@@ -54,6 +54,47 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
|
|
|
54
54
|
'pytest-cache-files-*',
|
|
55
55
|
'.ruff_cache'
|
|
56
56
|
];
|
|
57
|
+
// Python test files, excluded from the `production` named input so that editing
|
|
58
|
+
// a test does not invalidate targets whose output cannot contain it.
|
|
59
|
+
//
|
|
60
|
+
// Anchored to the `tests` directory, which is where the generated project puts
|
|
61
|
+
// them and the only path the build excludes (`ignorePaths` is matched against
|
|
62
|
+
// the project root's top-level entries). An unanchored `**/test_*.py` would also
|
|
63
|
+
// match a production module inside the packaged source directory — a
|
|
64
|
+
// `test_data_loader.py` helper ships in the wheel, so excluding it would leave
|
|
65
|
+
// the wheel stale after a fix to it.
|
|
66
|
+
export const PYTHON_TEST_FILE_EXCLUSIONS = [
|
|
67
|
+
'!{projectRoot}/tests/**/*'
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* Excludes Python test files from the `production` named input, preserving any
|
|
71
|
+
* entries already present (including user additions).
|
|
72
|
+
*
|
|
73
|
+
* The input is created when absent: the Python targets reference `production`,
|
|
74
|
+
* and Nx fails hard on a named input that is not defined.
|
|
75
|
+
*/ export const addPythonTestExclusionsToProductionInput = (tree)=>{
|
|
76
|
+
const nxJson = readNxJson(tree);
|
|
77
|
+
if (!nxJson) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const production = nxJson.namedInputs?.production ?? [
|
|
81
|
+
'default'
|
|
82
|
+
];
|
|
83
|
+
const missing = PYTHON_TEST_FILE_EXCLUSIONS.filter((exclusion)=>!production.includes(exclusion));
|
|
84
|
+
if (missing.length === 0 && nxJson.namedInputs?.production) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
updateNxJson(tree, {
|
|
88
|
+
...nxJson,
|
|
89
|
+
namedInputs: {
|
|
90
|
+
...nxJson.namedInputs,
|
|
91
|
+
production: [
|
|
92
|
+
...production,
|
|
93
|
+
...missing
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
};
|
|
57
98
|
/**
|
|
58
99
|
* Returns details about the Python project to be created
|
|
59
100
|
*/ export const getPyProjectDetails = (tree, schema)=>{
|
|
@@ -78,6 +119,7 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
|
|
|
78
119
|
*/ export const pyProjectGenerator = async (tree, schema)=>{
|
|
79
120
|
const { dir, normalizedModuleName, fullyQualifiedName, distributionName } = getPyProjectDetails(tree, schema);
|
|
80
121
|
addTsDependencies(tree, DEPENDENCIES);
|
|
122
|
+
addPythonTestExclusionsToProductionInput(tree);
|
|
81
123
|
const pythonPlugin = withVersions(DEPENDENCIES, [
|
|
82
124
|
'@nxlv/python'
|
|
83
125
|
]);
|
|
@@ -159,8 +201,10 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
|
|
|
159
201
|
const buildTarget = projectConfiguration.targets.build;
|
|
160
202
|
projectConfiguration.targets.compile = {
|
|
161
203
|
...buildTarget,
|
|
204
|
+
// `tests` is in `ignorePaths` below, so test files cannot reach the built
|
|
205
|
+
// distribution and must not invalidate it.
|
|
162
206
|
inputs: [
|
|
163
|
-
'
|
|
207
|
+
'production',
|
|
164
208
|
'^production'
|
|
165
209
|
],
|
|
166
210
|
outputs: [
|
|
@@ -196,6 +240,12 @@ const PYTHON_TRANSIENT_ARTIFACTS = [
|
|
|
196
240
|
outputPath
|
|
197
241
|
}
|
|
198
242
|
};
|
|
243
|
+
// The artifact-only sibling of build, which the deploy targets depend on.
|
|
244
|
+
projectConfiguration.targets.assemble = {
|
|
245
|
+
dependsOn: [
|
|
246
|
+
'compile'
|
|
247
|
+
]
|
|
248
|
+
};
|
|
199
249
|
}
|
|
200
250
|
projectConfiguration.targets.typecheck = {
|
|
201
251
|
cache: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { declareDependencies } from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python.js';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { updateToml } from '../../utils/toml.js';\nimport {\n pyenvPythonVersion,\n pyprojectPythonDependency,\n withVersions,\n} from '../../utils/versions.js';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const DEPENDENCIES = declareDependencies()({\n ts: [{ name: '@nxlv/python', dev: true, root: true }],\n py: [\n // The linting and type checking tools live in the workspace root pyproject.\n // Pinned to the version generation-time formatting uses, so generated files\n // stay `ruff format --check`-clean across ruff releases.\n { name: 'ruff', group: 'dev', root: true },\n { name: 'ty', group: 'dev', root: true },\n ],\n});\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n const pythonPlugin = withVersions(DEPENDENCIES, ['@nxlv/python']);\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n inputs: ['default', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n addPyDependencies(tree, DEPENDENCIES);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","addPyDependencies","addTsDependencies","declareDependencies","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","updateToml","pyenvPythonVersion","pyprojectPythonDependency","withVersions","DEPENDENCIES","ts","name","dev","root","py","group","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","getPyProjectDetails","tree","schema","scope","normalizedName","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","nxJson","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","filter","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n ensurePackage,\n type GeneratorCallback,\n joinPathFragments,\n readNxJson,\n readProjectConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addLicenseCheckToLintTarget,\n ensurePythonLicenseCollector,\n} from '../../license/config.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { declareDependencies } from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { normalizeDistributionName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport type { UVPyprojectToml } from '../../utils/nxlv-python.js';\nimport {\n migrateToSharedVenvGenerator,\n uvProjectGenerator,\n} from '../../utils/nxlv-python.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { updateToml } from '../../utils/toml.js';\nimport {\n pyenvPythonVersion,\n pyprojectPythonDependency,\n withVersions,\n} from '../../utils/versions.js';\nimport type { PyProjectGeneratorSchema } from './schema';\n\nexport const DEPENDENCIES = declareDependencies()({\n ts: [{ name: '@nxlv/python', dev: true, root: true }],\n py: [\n // The linting and type checking tools live in the workspace root pyproject.\n // Pinned to the version generation-time formatting uses, so generated files\n // stay `ruff format --check`-clean across ruff releases.\n { name: 'ruff', group: 'dev', root: true },\n { name: 'ty', group: 'dev', root: true },\n ],\n});\n\nexport const PY_PROJECT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\n// Transient artifacts that pytest, coverage and ruff create and remove while\n// the test, typecheck and compile targets run concurrently. `.coverage.*` are\n// the per-process data files pytest-cov writes (`.coverage.<host>.<pid>.<rand>`)\n// before combining them. Both `ty` (which respects .gitignore) and the\n// `@nxlv/python:build` copy (which respects `ignorePaths`) would otherwise fail\n// when they read one of these mid-deletion.\nconst PYTHON_TRANSIENT_ARTIFACTS = [\n '__pycache__',\n '.coverage',\n '.coverage.*',\n '.pytest_cache',\n 'pytest-cache-files-*',\n '.ruff_cache',\n];\n\n// Python test files, excluded from the `production` named input so that editing\n// a test does not invalidate targets whose output cannot contain it.\n//\n// Anchored to the `tests` directory, which is where the generated project puts\n// them and the only path the build excludes (`ignorePaths` is matched against\n// the project root's top-level entries). An unanchored `**/test_*.py` would also\n// match a production module inside the packaged source directory — a\n// `test_data_loader.py` helper ships in the wheel, so excluding it would leave\n// the wheel stale after a fix to it.\nexport const PYTHON_TEST_FILE_EXCLUSIONS = ['!{projectRoot}/tests/**/*'];\n\n/**\n * Excludes Python test files from the `production` named input, preserving any\n * entries already present (including user additions).\n *\n * The input is created when absent: the Python targets reference `production`,\n * and Nx fails hard on a named input that is not defined.\n */\nexport const addPythonTestExclusionsToProductionInput = (tree: Tree) => {\n const nxJson = readNxJson(tree);\n if (!nxJson) {\n return;\n }\n const production = nxJson.namedInputs?.production ?? ['default'];\n const missing = PYTHON_TEST_FILE_EXCLUSIONS.filter(\n (exclusion) => !production.includes(exclusion),\n );\n if (missing.length === 0 && nxJson.namedInputs?.production) {\n return;\n }\n updateNxJson(tree, {\n ...nxJson,\n namedInputs: {\n ...nxJson.namedInputs,\n production: [...production, ...missing],\n },\n });\n};\n\nexport interface PyProjectDetails {\n /**\n * Fully qualified Nx project id including scope, in dot notation (eg foo.bar).\n * This is the identifier Nx uses (readProjectConfiguration, the project\n * graph, target references) and is intentionally kept dotted.\n */\n readonly fullyQualifiedName: string;\n /**\n * PEP 503 normalised Python distribution name (eg foo-bar). This is the name\n * written to the project's `[project].name`, the root `[tool.uv.sources]`\n * key, and any inter-project dependency string. It is hyphenated (not dotted)\n * so `uv` and `@nxlv/python` can match it: uv writes `uv.lock` keyed by the\n * PEP 503 hyphenated name, and `@nxlv/python`'s dependency inference splits a\n * dotted name on `.` and so would otherwise drop the edge entirely. Keeping\n * the distribution name decoupled from `fullyQualifiedName` is what lets the\n * workspace dependency edge appear in the Nx project graph.\n */\n readonly distributionName: string;\n /**\n * Directory of the library relative to the root\n */\n readonly dir: string;\n /**\n * Module name for the project\n */\n readonly normalizedModuleName: string;\n}\n\n/**\n * Returns details about the Python project to be created\n */\nexport const getPyProjectDetails = (\n tree: Tree,\n schema: {\n name: string;\n directory?: string;\n subDirectory?: string;\n moduleName?: string;\n },\n): PyProjectDetails => {\n const scope = toSnakeCase(getNpmScope(tree));\n const normalizedName = toSnakeCase(schema.name);\n const normalizedModuleName = toSnakeCase(\n schema.moduleName ?? `${scope}_${normalizedName}`,\n );\n const fullyQualifiedName = `${scope}.${normalizedName}`;\n // The Python distribution name is the PEP 503 normalised form of the\n // fully qualified name: hyphenated, never dotted. See PyProjectDetails.\n const distributionName = normalizeDistributionName(fullyQualifiedName);\n // NB: interactive nx generator cli can pass empty string\n const dir = joinPathFragments(\n schema.directory || '.',\n schema.subDirectory || normalizedName,\n );\n return { dir, fullyQualifiedName, distributionName, normalizedModuleName };\n};\n\n/**\n * Generates a Python project\n */\nexport const pyProjectGenerator = async (\n tree: Tree,\n schema: PyProjectGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const { dir, normalizedModuleName, fullyQualifiedName, distributionName } =\n getPyProjectDetails(tree, schema);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n addPythonTestExclusionsToProductionInput(tree);\n\n const pythonPlugin = withVersions(DEPENDENCIES, ['@nxlv/python']);\n Object.entries(pythonPlugin).forEach(([name, version]) =>\n ensurePackage(name, version),\n );\n\n const nxJson = readNxJson(tree);\n\n // Only rewrite nx.json when the plugin needs adding, so re-running does not\n // reserialize (and reformat) the file when nothing has changed.\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === '@nxlv/python'\n : p.plugin === '@nxlv/python',\n )\n ) {\n nxJson.plugins = [\n ...(nxJson.plugins ?? []),\n {\n plugin: '@nxlv/python',\n options: {\n packageManager: 'uv',\n },\n },\n ];\n updateNxJson(tree, nxJson);\n }\n\n // Only scaffold the project when it does not already exist so re-running with\n // the same name does not throw. The rest of the generator still runs to apply\n // any changed options to the existing project.\n if (!projectExists(tree, fullyQualifiedName)) {\n if (!tree.exists('uv.lock')) {\n await migrateToSharedVenvGenerator(tree, {\n autoActivate: true,\n packageManager: 'uv',\n moveDevDependencies: false,\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n });\n }\n\n await uvProjectGenerator(tree, {\n // The Nx project id (and `uv.workspace.members` etc.) keys off `name`, so\n // keep it dotted. `packageName` is the separate PEP 503 distribution name\n // written to `[project].name` and the root `[tool.uv.sources]` key; it is\n // hyphenated so `@nxlv/python` infers the workspace dependency edge (it\n // splits a dotted name on `.` and would otherwise drop it). This split is\n // the whole fix (see PyProjectDetails.distributionName).\n name: fullyQualifiedName,\n packageName: distributionName,\n publishable: false,\n buildLockedVersions: true,\n buildBundleLocalDependencies: true,\n linter: 'ruff',\n rootPyprojectDependencyGroup: 'main',\n pyenvPythonVersion: pyenvPythonVersion(),\n pyprojectPythonDependency: pyprojectPythonDependency(),\n projectType: schema.type,\n projectNameAndRootFormat: 'as-provided',\n moduleName: normalizedModuleName,\n directory: dir,\n unitTestRunner: 'pytest',\n codeCoverage: true,\n codeCoverageHtmlReport: true,\n codeCoverageXmlReport: true,\n unitTestHtmlReport: true,\n unitTestJUnitReport: true,\n buildSystem: 'hatch',\n srcDir: false,\n });\n\n // Remove generated hello.py and test_hello.py as they are not needed\n [\n joinPathFragments(dir, normalizedModuleName, 'hello.py'),\n joinPathFragments(dir, 'tests', 'test_hello.py'),\n ].forEach((f) => tree.delete(f));\n\n // Add a placeholder test so pytest doesn't fail with \"no tests collected\"\n tree.write(\n joinPathFragments(dir, 'tests', 'test_noop.py'),\n 'def test_noop():\\n pass\\n',\n );\n }\n\n const outputPath = '{workspaceRoot}/dist/{projectRoot}';\n const buildOutputPath = joinPathFragments(outputPath, 'build');\n const projectConfiguration = readProjectConfiguration(\n tree,\n fullyQualifiedName,\n );\n projectConfiguration.name = fullyQualifiedName;\n // Derive the compile target from the uv build target, and rewrite build to\n // orchestrate the other targets. This only runs on first creation: on re-run\n // build has already been transformed, so re-deriving would corrupt compile\n // and duplicate the build dependencies.\n if (!projectConfiguration.targets.compile) {\n const buildTarget = projectConfiguration.targets.build;\n projectConfiguration.targets.compile = {\n ...buildTarget,\n // `tests` is in `ignorePaths` below, so test files cannot reach the built\n // distribution and must not invalidate it.\n inputs: ['production', '^production'],\n outputs: [buildOutputPath],\n options: {\n ...buildTarget.options,\n outputPath: buildOutputPath,\n // The build executor copies the project to a temp folder; exclude the\n // executor defaults plus transient artifacts so the copy does not race\n // a concurrent test/typecheck target deleting a file mid-copy.\n ignorePaths: ['.venv', '.tox', 'tests', ...PYTHON_TRANSIENT_ARTIFACTS],\n },\n };\n projectConfiguration.targets.build = {\n inputs: ['default', '^production'],\n dependsOn: [\n 'lint',\n 'compile',\n 'test',\n 'typecheck',\n ...(buildTarget.dependsOn ?? []),\n ],\n options: {\n outputPath,\n },\n };\n // The artifact-only sibling of build, which the deploy targets depend on.\n projectConfiguration.targets.assemble = {\n dependsOn: ['compile'],\n };\n }\n projectConfiguration.targets.typecheck = {\n cache: true,\n inputs: ['default', '^production'],\n executor: '@nxlv/python:run-commands',\n options: {\n command: 'uv run ty check',\n cwd: '{projectRoot}',\n },\n };\n\n // Set the default line length to 120, as 88 is a little too strict\n updateToml(\n tree,\n joinPathFragments(dir, 'pyproject.toml'),\n (pyProjectToml: UVPyprojectToml) => {\n if ((pyProjectToml.tool as any)?.ruff) {\n (pyProjectToml.tool as any).ruff['line-length'] = 120;\n }\n return pyProjectToml;\n },\n );\n\n addPyDependencies(tree, DEPENDENCIES);\n\n // Base format target checks rather than writes (so build/lint don't rewrite\n // source); `fix` writes, and `skip-lint` writes without failing so it stays\n // a no-op when propagated through the lint -> format dependency.\n projectConfiguration.targets.format = {\n ...projectConfiguration.targets.format,\n cache: true,\n inputs: ['default', '^production'],\n options: {\n ...projectConfiguration.targets.format?.options,\n check: true,\n },\n configurations: {\n ...projectConfiguration.targets.format?.configurations,\n fix: {\n check: false,\n },\n 'skip-lint': {\n check: false,\n },\n },\n };\n\n // Add a dependency on the format target for lint in order to reduce the number of\n // fixable lint errors (eg line too long)\n projectConfiguration.targets.lint = {\n ...projectConfiguration.targets.lint,\n cache: true,\n inputs: ['default', '^production'],\n configurations: {\n ...projectConfiguration.targets.lint?.configurations,\n fix: {\n fix: true,\n },\n 'skip-lint': {\n exitZero: true,\n },\n },\n };\n // Append `format` without moving an existing entry, so re-running does not\n // reorder lint dependencies (e.g. relative to a later-added license-check).\n addDependencyToTargetIfNotPresent(projectConfiguration, 'lint', 'format');\n\n projectConfiguration.targets = sortObjectKeys(projectConfiguration.targets);\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfiguration);\n\n addGeneratorMetadata(tree, fullyQualifiedName, PY_PROJECT_GENERATOR_INFO);\n\n // Update root .gitignore\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '/reports']);\n\n // Update project level .gitignore. The cache directories are also kept out\n // of type checking: `ty` respects .gitignore, and pytest creates and removes\n // transient `pytest-cache-files-*` directories while the test and typecheck\n // targets run concurrently, which would otherwise make `ty` fail with an I/O\n // error when it scans one mid-deletion.\n updateGitIgnore(tree, dir, (patterns) => [\n ...patterns,\n '**/__pycache__',\n ...PYTHON_TRANSIENT_ARTIFACTS.filter((p) => p !== '__pycache__'),\n ]);\n\n await addGeneratorMetricsIfApplicable(tree, [PY_PROJECT_GENERATOR_INFO]);\n\n await ensurePythonLicenseCollector(tree);\n\n // If license checking is configured, make this project's lint target depend\n // on the root license-check target. No-op if license checking isn't set up;\n // the license generator wires up existing projects itself, so the dependency\n // is added regardless of which generator runs first.\n addLicenseCheckToLintTarget(tree, fullyQualifiedName);\n\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\nexport default pyProjectGenerator;\n"],"names":["ensurePackage","joinPathFragments","readNxJson","readProjectConfiguration","updateNxJson","updateProjectConfiguration","addLicenseCheckToLintTarget","ensurePythonLicenseCollector","addPyDependencies","addTsDependencies","declareDependencies","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","normalizeDistributionName","toSnakeCase","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","migrateToSharedVenvGenerator","uvProjectGenerator","sortObjectKeys","updateToml","pyenvPythonVersion","pyprojectPythonDependency","withVersions","DEPENDENCIES","ts","name","dev","root","py","group","PY_PROJECT_GENERATOR_INFO","filename","PYTHON_TRANSIENT_ARTIFACTS","PYTHON_TEST_FILE_EXCLUSIONS","addPythonTestExclusionsToProductionInput","tree","nxJson","production","namedInputs","missing","filter","exclusion","includes","length","getPyProjectDetails","schema","scope","normalizedName","normalizedModuleName","moduleName","fullyQualifiedName","distributionName","dir","directory","subDirectory","pyProjectGenerator","pythonPlugin","Object","entries","forEach","version","plugins","find","p","plugin","options","packageManager","exists","autoActivate","moveDevDependencies","packageName","publishable","buildLockedVersions","buildBundleLocalDependencies","linter","rootPyprojectDependencyGroup","projectType","type","projectNameAndRootFormat","unitTestRunner","codeCoverage","codeCoverageHtmlReport","codeCoverageXmlReport","unitTestHtmlReport","unitTestJUnitReport","buildSystem","srcDir","f","delete","write","outputPath","buildOutputPath","projectConfiguration","targets","compile","buildTarget","build","inputs","outputs","ignorePaths","dependsOn","assemble","typecheck","cache","executor","command","cwd","pyProjectToml","tool","ruff","format","check","configurations","fix","lint","exitZero","patterns","preferInstallDependencies","languages"],"mappings":"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"}
|
package/src/py/rdb/generator.js
CHANGED
|
@@ -8,7 +8,7 @@ import { addPythonReExport } from "../../utils/agent-connection/agent-connection
|
|
|
8
8
|
import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
|
|
9
9
|
import { resolveContainers } from "../../utils/containers.js";
|
|
10
10
|
import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
|
|
11
|
-
import { addDockerScanTarget, DOCKER_DEPENDENCIES } from "../../utils/docker.js";
|
|
11
|
+
import { addDockerScanTarget, DOCKER_DEPENDENCIES, IMAGE_BUILD_CACHE } from "../../utils/docker.js";
|
|
12
12
|
import { formatFilesInSubtree } from "../../utils/format.js";
|
|
13
13
|
import { FS_DEPENDENCIES, FsCommands } from "../../utils/fs.js";
|
|
14
14
|
import { resolveIac } from "../../utils/iac.js";
|
|
@@ -16,7 +16,7 @@ import { installDependencies } from "../../utils/install.js";
|
|
|
16
16
|
import { addGeneratorMetricsIfApplicable } from "../../utils/metrics.js";
|
|
17
17
|
import { kebabCase, snakeCase, toClassName } from "../../utils/names.js";
|
|
18
18
|
import { getNpmScope } from "../../utils/npm-scope.js";
|
|
19
|
-
import { addDependencyToTargetIfNotPresent, addGeneratorMetadata, getGeneratorInfo, projectExists } from "../../utils/nx.js";
|
|
19
|
+
import { addArtifactDependencyToTargets, addDependencyToTargetIfNotPresent, addGeneratorMetadata, getGeneratorInfo, projectExists } from "../../utils/nx.js";
|
|
20
20
|
import { assignPort } from "../../utils/port.js";
|
|
21
21
|
import { addRdbInfra } from "../../utils/rdb-constructs/rdb-constructs.js";
|
|
22
22
|
import { SHARED_CONSTRUCTS_DEPENDENCIES, sharedConstructsGenerator } from "../../utils/shared-constructs.js";
|
|
@@ -186,6 +186,9 @@ export const pyRdbGenerator = async (tree, options)=>{
|
|
|
186
186
|
});
|
|
187
187
|
projectConfig.targets['bundle-migration'] = {
|
|
188
188
|
cache: true,
|
|
189
|
+
inputs: [
|
|
190
|
+
'default'
|
|
191
|
+
],
|
|
189
192
|
outputs: [
|
|
190
193
|
'{workspaceRoot}/dist/{projectRoot}/docker/migration'
|
|
191
194
|
],
|
|
@@ -207,6 +210,9 @@ export const pyRdbGenerator = async (tree, options)=>{
|
|
|
207
210
|
};
|
|
208
211
|
projectConfig.targets['bundle-create-db-user'] = {
|
|
209
212
|
cache: true,
|
|
213
|
+
inputs: [
|
|
214
|
+
'default'
|
|
215
|
+
],
|
|
210
216
|
outputs: [
|
|
211
217
|
'{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'
|
|
212
218
|
],
|
|
@@ -286,7 +292,7 @@ export const pyRdbGenerator = async (tree, options)=>{
|
|
|
286
292
|
if (options.infra !== 'none') {
|
|
287
293
|
if (iac === 'terraform') {
|
|
288
294
|
projectConfig.targets.docker = {
|
|
289
|
-
cache:
|
|
295
|
+
cache: IMAGE_BUILD_CACHE,
|
|
290
296
|
executor: 'nx:run-commands',
|
|
291
297
|
options: {
|
|
292
298
|
commands: [
|
|
@@ -300,7 +306,7 @@ export const pyRdbGenerator = async (tree, options)=>{
|
|
|
300
306
|
'bundle-create-db-user'
|
|
301
307
|
]
|
|
302
308
|
};
|
|
303
|
-
|
|
309
|
+
addArtifactDependencyToTargets(projectConfig, 'docker');
|
|
304
310
|
addDockerScanTarget(tree, {
|
|
305
311
|
project: projectConfig,
|
|
306
312
|
containerEngine,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n writeJson,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addPythonReExport } from '../../utils/agent-connection/agent-connection.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport { assignPort } from '../../utils/port.js';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport {\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants.js';\nimport {\n SHARED_RDB_SCRIPTS_DEPENDENCIES,\n sharedRdbScriptsGenerator,\n} from '../../utils/shared-rdb-scripts.js';\nimport { PY_VERSIONS } from '../../utils/versions.js';\nimport pyProjectGenerator, {\n getPyProjectDetails,\n} from '../project/generator.js';\nimport type { PyRdbGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyRdbMetadata extends IacMetadata {\n readonly engine: PyRdbGeneratorSchema['engine'];\n}\n\n/** The Postgres engine, which MySQL takes none of. */\nconst isPostgres = (m: PyRdbMetadata) => m.engine !== 'mysql';\n\n// Each entry names the engine branch it belongs to, so the same declaration\n// drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyRdbMetadata>()({\n ts: [\n // The engine client the local dev script wait-for-*-db.ts imports.\n { name: 'mariadb', when: (m) => m.engine === 'mysql', root: true },\n { name: 'pg', when: isPostgres, root: true },\n { name: '@types/pg', when: isPostgres, dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_RDB_SCRIPTS_DEPENDENCIES),\n ],\n py: [\n { name: 'sqlmodel' },\n { name: 'alembic' },\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n { name: 'greenlet' },\n { name: 'aiomysql', when: (m) => m.engine === 'mysql' },\n { name: 'asyncpg', when: (m) => m.engine !== 'mysql' },\n { name: 'boto3' },\n { name: 'aws-lambda-powertools' },\n ],\n});\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n // Recorded in the metadata below so the version sync can tell a CDK project\n // from a Terraform one; undefined when no infrastructure was generated.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyRdbMetadata = { engine, ...(iac ? { iac } : {}) };\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n // Models, the connection module, the Alembic config and the migration env are\n // user-editable, so a re-run (to add infrastructure, or after a failed run)\n // must not clobber the user's schema and edits.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // The package barrel re-exports connection.py. `pyProjectGenerator` writes a\n // stub __init__.py when it creates the project, so the re-exports are added to\n // whatever is there rather than replacing it — which also leaves a user's own\n // additions to the barrel alone on a re-run.\n const initFilePath = joinPathFragments(\n dir,\n normalizedModuleName,\n '__init__.py',\n );\n for (const importName of ['get_engine', 'is_local_dev', 'session_context']) {\n await addPythonReExport(tree, initFilePath, '.connection', importName);\n }\n\n // config.json is framework-owned: it carries values derived from the\n // generator's options, so it converges on a re-run with changed options.\n writeJson(tree, joinPathFragments(dir, 'config.json'), {\n runtimeConfigKey: nameClassName,\n localDev: {\n containerEngine,\n containerName,\n image: dockerImage,\n port: localDbPort,\n host: localDbHost,\n dbName: databaseName,\n dbUser: localDbUser,\n dbPassword: localDbPassword,\n dbEngine: engine,\n },\n });\n\n await sharedRdbScriptsGenerator(tree, engine, DEPENDENCIES);\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree, DEPENDENCIES);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n },\n DEPENDENCIES,\n );\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n PY_RDB_GENERATOR_INFO,\n metadata,\n );\n\n if (options.infra !== 'none') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addPyDependencies(tree, DEPENDENCIES, { metadata, projectRoot: dir });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","generateFiles","joinPathFragments","OverwriteStrategy","readProjectConfiguration","updateProjectConfiguration","writeJson","addPyDependencies","addTsDependencies","addPythonReExport","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addRdbInfra","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","SHARED_RDB_SCRIPTS_DEPENDENCIES","sharedRdbScriptsGenerator","PY_VERSIONS","pyProjectGenerator","getPyProjectDetails","isPostgres","m","engine","DEPENDENCIES","ts","name","when","root","dev","py","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","iac","infra","undefined","metadata","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","overwriteStrategy","KeepExisting","initFilePath","importName","localDev","image","port","host","dbName","dbUser","dbPassword","dbEngine","scriptsDir","fs","migrationBundleDir","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n writeJson,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addPythonReExport } from '../../utils/agent-connection/agent-connection.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n IMAGE_BUILD_CACHE,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addArtifactDependencyToTargets,\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport { assignPort } from '../../utils/port.js';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport {\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants.js';\nimport {\n SHARED_RDB_SCRIPTS_DEPENDENCIES,\n sharedRdbScriptsGenerator,\n} from '../../utils/shared-rdb-scripts.js';\nimport { PY_VERSIONS } from '../../utils/versions.js';\nimport pyProjectGenerator, {\n getPyProjectDetails,\n} from '../project/generator.js';\nimport type { PyRdbGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyRdbMetadata extends IacMetadata {\n readonly engine: PyRdbGeneratorSchema['engine'];\n}\n\n/** The Postgres engine, which MySQL takes none of. */\nconst isPostgres = (m: PyRdbMetadata) => m.engine !== 'mysql';\n\n// Each entry names the engine branch it belongs to, so the same declaration\n// drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyRdbMetadata>()({\n ts: [\n // The engine client the local dev script wait-for-*-db.ts imports.\n { name: 'mariadb', when: (m) => m.engine === 'mysql', root: true },\n { name: 'pg', when: isPostgres, root: true },\n { name: '@types/pg', when: isPostgres, dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_RDB_SCRIPTS_DEPENDENCIES),\n ],\n py: [\n { name: 'sqlmodel' },\n { name: 'alembic' },\n // SQLAlchemy's async engine (used by connection.py for both engines)\n // requires greenlet at runtime. Vend it explicitly at a pinned version so\n // the dependency graph is fully determined and doesn't float to an\n // unpublished-wheel release at install time.\n { name: 'greenlet' },\n { name: 'aiomysql', when: (m) => m.engine === 'mysql' },\n { name: 'asyncpg', when: (m) => m.engine !== 'mysql' },\n { name: 'boto3' },\n { name: 'aws-lambda-powertools' },\n ],\n});\n\nexport const PY_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyRdbGenerator = async (\n tree: Tree,\n options: PyRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n\n const { fullyQualifiedName, dir, normalizedModuleName } = getPyProjectDetails(\n tree,\n {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n },\n );\n\n if (!projectExists(tree, fullyQualifiedName)) {\n await pyProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n type: 'library',\n });\n }\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n\n const { engine } = options;\n // Recorded in the metadata below so the version sync can tell a CDK project\n // from a Terraform one; undefined when no infrastructure was generated.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyRdbMetadata = { engine, ...(iac ? { iac } : {}) };\n const localDbPort = assignPort(\n tree,\n projectConfig,\n engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n name: normalizedModuleName,\n runtimeConfigKey: nameClassName,\n engine,\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n sqlmodelVersion: PY_VERSIONS.sqlmodel,\n alembicVersion: PY_VERSIONS.alembic,\n aiomysqlVersion: PY_VERSIONS.aiomysql,\n asyncpgVersion: PY_VERSIONS.asyncpg,\n boto3Version: PY_VERSIONS.boto3,\n awsLambdaPowertoolsVersion: PY_VERSIONS['aws-lambda-powertools'],\n };\n\n // Models, the connection module, the Alembic config and the migration env are\n // user-editable, so a re-run (to add infrastructure, or after a failed run)\n // must not clobber the user's schema and edits.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // The package barrel re-exports connection.py. `pyProjectGenerator` writes a\n // stub __init__.py when it creates the project, so the re-exports are added to\n // whatever is there rather than replacing it — which also leaves a user's own\n // additions to the barrel alone on a re-run.\n const initFilePath = joinPathFragments(\n dir,\n normalizedModuleName,\n '__init__.py',\n );\n for (const importName of ['get_engine', 'is_local_dev', 'session_context']) {\n await addPythonReExport(tree, initFilePath, '.connection', importName);\n }\n\n // config.json is framework-owned: it carries values derived from the\n // generator's options, so it converges on a re-run with changed options.\n writeJson(tree, joinPathFragments(dir, 'config.json'), {\n runtimeConfigKey: nameClassName,\n localDev: {\n containerEngine,\n containerName,\n image: dockerImage,\n port: localDbPort,\n host: localDbHost,\n dbName: databaseName,\n dbUser: localDbUser,\n dbPassword: localDbPassword,\n dbEngine: engine,\n },\n });\n\n await sharedRdbScriptsGenerator(tree, engine, DEPENDENCIES);\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const fs = new FsCommands(tree, DEPENDENCIES);\n\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'migration',\n );\n const createDbUserBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'docker',\n 'create-db-user',\n );\n const migrationDockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n const createDbUserDockerImageTag = `${getNpmScope(tree)}-${kebabCase(\n options.name,\n )}-create-db-user:latest`;\n\n if (options.infra !== 'none') {\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n projectConfig,\n { pythonPlatform: 'aarch64-manylinux_2_28' },\n );\n\n projectConfig.targets['bundle-migration'] = {\n cache: true,\n inputs: ['default'],\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/migration'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(migrationBundleDir),\n fs.mkdir(migrationBundleDir),\n fs.cp(bundleOutputDir, migrationBundleDir),\n fs.cp(\n joinPathFragments(dir, 'migrations'),\n joinPathFragments(migrationBundleDir, 'migrations'),\n ),\n fs.cp(\n joinPathFragments(dir, 'alembic.ini'),\n joinPathFragments(migrationBundleDir, 'alembic.ini'),\n ),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.migration'),\n joinPathFragments(migrationBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n projectConfig.targets['bundle-create-db-user'] = {\n cache: true,\n inputs: ['default'],\n outputs: ['{workspaceRoot}/dist/{projectRoot}/docker/create-db-user'],\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(createDbUserBundleDir),\n fs.mkdir(createDbUserBundleDir),\n fs.cp(bundleOutputDir, createDbUserBundleDir),\n fs.cp(\n joinPathFragments(dir, 'Dockerfile.create-db-user'),\n joinPathFragments(createDbUserBundleDir, 'Dockerfile'),\n ),\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'bundle',\n 'bundle-create-db-user',\n );\n }\n\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n dependsOn: ['pull-image'],\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/wait-for-${engine}-db.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.migrate = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic upgrade head',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n projectConfig.targets.alembic = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n command: 'uv run alembic',\n cwd: '{projectRoot}',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n\n if (options.infra !== 'none') {\n if (iac === 'terraform') {\n projectConfig.targets.docker = {\n cache: IMAGE_BUILD_CACHE,\n executor: 'nx:run-commands',\n options: {\n commands: [\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${migrationDockerImageTag} ${migrationBundleDir}`,\n `${containerEngine} build --platform linux/arm64 --provenance=false -t ${createDbUserDockerImageTag} ${createDbUserBundleDir}`,\n ],\n parallel: false,\n },\n dependsOn: ['bundle-migration', 'bundle-create-db-user'],\n };\n addArtifactDependencyToTargets(projectConfig, 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project: projectConfig,\n containerEngine,\n trivyTargetName: 'trivy',\n dockerTargetName: 'docker',\n imageTags: [migrationDockerImageTag, createDbUserDockerImageTag],\n },\n DEPENDENCIES,\n );\n }\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-migration',\n );\n addDependencyToTargetIfNotPresent(\n projectConfig,\n 'build',\n 'bundle-create-db-user',\n );\n }\n\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n PY_RDB_GENERATOR_INFO,\n metadata,\n );\n\n if (options.infra !== 'none') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase: kebabCase(options.name),\n databasePackageAlias: normalizedModuleName,\n databaseName,\n adminUser: databaseUser,\n engine,\n migrationBundleDir,\n createDbUserBundleDir,\n framework: 'sqlmodel',\n createDbUserDockerImageTag,\n migrationDockerImageTag,\n containerEngine,\n });\n }\n\n addPyDependencies(tree, DEPENDENCIES, { metadata, projectRoot: dir });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n await addGeneratorMetricsIfApplicable(tree, [PY_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyRdbGenerator;\n"],"names":["relative","generateFiles","joinPathFragments","OverwriteStrategy","readProjectConfiguration","updateProjectConfiguration","writeJson","addPyDependencies","addTsDependencies","addPythonReExport","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","IMAGE_BUILD_CACHE","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","addArtifactDependencyToTargets","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","projectExists","assignPort","addRdbInfra","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","SHARED_RDB_SCRIPTS_DEPENDENCIES","sharedRdbScriptsGenerator","PY_VERSIONS","pyProjectGenerator","getPyProjectDetails","isPostgres","m","engine","DEPENDENCIES","ts","name","when","root","dev","py","PY_RDB_GENERATOR_INFO","filename","pyRdbGenerator","tree","options","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","normalizedModuleName","directory","subDirectory","type","projectConfig","iac","infra","undefined","metadata","localDbPort","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","localDbName","sqlmodelVersion","sqlmodel","alembicVersion","alembic","aiomysqlVersion","aiomysql","asyncpgVersion","asyncpg","boto3Version","boto3","awsLambdaPowertoolsVersion","dirname","overwriteStrategy","KeepExisting","initFilePath","importName","localDev","image","port","host","dbName","dbUser","dbPassword","dbEngine","scriptsDir","fs","migrationBundleDir","createDbUserBundleDir","migrationDockerImageTag","createDbUserDockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","targets","cache","inputs","outputs","executor","commands","rm","mkdir","cp","parallel","dependsOn","command","cwd","continuous","migrate","env","LOCAL_DEV","docker","project","trivyTargetName","dockerTargetName","imageTags","projectName","projectRoot","nameKebabCase","databasePackageAlias","adminUser","framework","preferInstallDependencies","languages"],"mappings":"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"}
|