@aws/nx-plugin 1.1.0 → 1.2.0
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 +30 -29
- package/generators.json +8 -0
- package/migrations.json +6 -1
- package/package.json +1 -1
- package/src/agentcore-harness/generator.d.ts +1 -1
- package/src/greengrass/component/common.d.ts +60 -0
- package/src/greengrass/component/common.js +191 -0
- package/src/greengrass/component/common.js.map +1 -0
- package/src/greengrass/component/dependencies.d.ts +101 -0
- package/src/greengrass/component/dependencies.js +37 -0
- package/src/greengrass/component/dependencies.js.map +1 -0
- package/src/greengrass/component/generator.d.ts +174 -0
- package/src/greengrass/component/generator.js +32 -0
- package/src/greengrass/component/generator.js.map +1 -0
- package/src/greengrass/component/metadata.d.ts +2 -0
- package/src/greengrass/component/metadata.js +14 -0
- package/src/greengrass/component/metadata.js.map +1 -0
- package/src/greengrass/component/python/__snapshots__/generator.spec.ts.snap +450 -0
- package/src/greengrass/component/python/files/component/main.py.template +60 -0
- package/src/greengrass/component/python/files/component/recipe.yaml.template +30 -0
- package/src/greengrass/component/python/files/gdk/gdk-config.json.template +13 -0
- package/src/greengrass/component/python/files/tests/test___componentSnakeCase__.py.template +37 -0
- package/src/greengrass/component/python/generator.d.ts +15 -0
- package/src/greengrass/component/python/generator.js +192 -0
- package/src/greengrass/component/python/generator.js.map +1 -0
- package/src/greengrass/component/schema.d.js +6 -0
- package/src/greengrass/component/schema.d.js.map +1 -0
- package/src/greengrass/component/schema.d.ts +18 -0
- package/src/greengrass/component/schema.json +82 -0
- package/src/greengrass/component/typescript/__snapshots__/generator.spec.ts.snap +275 -0
- package/src/greengrass/component/typescript/files/component/recipe.yaml.template +41 -0
- package/src/greengrass/component/typescript/files/entrypoint/main.ts.template +58 -0
- package/src/greengrass/component/typescript/files/gdk/gdk-config.json.template +13 -0
- package/src/greengrass/component/typescript/files/scripts/vendor-crt-addon.ts.template +115 -0
- package/src/greengrass/component/typescript/generator.d.ts +16 -0
- package/src/greengrass/component/typescript/generator.js +194 -0
- package/src/greengrass/component/typescript/generator.js.map +1 -0
- package/src/infra/app/generator.d.ts +1 -1
- package/src/init/generator.d.ts +1 -1
- package/src/internal/test-matrix/generator.js +42 -0
- package/src/internal/test-matrix/generator.js.map +1 -1
- package/src/license/dependency-check/pre-approved.js +2 -1
- package/src/license/dependency-check/pre-approved.js.map +1 -1
- package/src/migrations/latest/ts-agent-guardrails-synth-input/metadata.json +3 -0
- package/src/migrations/latest/ts-agent-guardrails-synth-input/migration.d.ts +22 -0
- package/src/migrations/latest/ts-agent-guardrails-synth-input/migration.js +42 -0
- package/src/migrations/latest/ts-agent-guardrails-synth-input/migration.js.map +1 -0
- package/src/open-api/py-client/generator.d.ts +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +2 -0
- package/src/preset/generator.d.ts +1 -1
- package/src/py/agent/a2a-connection/generator.d.ts +1 -1
- package/src/py/agent/gateway-connection/generator.d.ts +1 -1
- package/src/py/agent/mcp-connection/generator.d.ts +1 -1
- package/src/py/agent/react-connection/generator.d.ts +1 -1
- package/src/py/fast-api/react/generator.d.ts +1 -1
- package/src/py/project/generator.js +2 -0
- package/src/py/project/generator.js.map +1 -1
- package/src/sdk/greengrass.d.ts +6 -0
- package/src/sdk/greengrass.js +6 -0
- package/src/sdk/greengrass.js.map +1 -0
- package/src/smithy/project/generator.d.ts +1 -1
- package/src/smithy/react-connection/generator.d.ts +1 -1
- package/src/terraform/project/generator.d.ts +1 -1
- package/src/trpc/react/generator.d.ts +1 -1
- package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
- package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
- package/src/ts/agent/guardrails/generator.js +10 -1
- package/src/ts/agent/guardrails/generator.js.map +1 -1
- package/src/ts/agent/guardrails/synth-inputs.d.ts +19 -0
- package/src/ts/agent/guardrails/synth-inputs.js +50 -0
- package/src/ts/agent/guardrails/synth-inputs.js.map +1 -0
- package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
- package/src/ts/agent/react-connection/generator.d.ts +1 -1
- package/src/ts/astro-docs/generator.d.ts +1 -1
- package/src/ts/dcr-proxy/generator.d.ts +1 -1
- package/src/ts/dynamodb/generator.d.ts +1 -1
- package/src/ts/lambda-function/generator.d.ts +1 -1
- package/src/ts/lib/generator.d.ts +1 -1
- package/src/ts/nx-generator/generator.d.ts +1 -1
- package/src/ts/nx-migration/generator.d.ts +1 -1
- package/src/ts/nx-plugin/generator.d.ts +1 -1
- package/src/ts/rdb/generator.d.ts +1 -1
- package/src/ts/react-website/agui/generator.d.ts +1 -1
- package/src/utils/__snapshots__/shared-greengrass-scripts.spec.ts.snap +1279 -0
- package/src/utils/files/common/scripts/src/greengrass/build-artifact.ts.template +236 -0
- package/src/utils/files/common/scripts/src/greengrass/component-logs.ts.template +48 -0
- package/src/utils/files/common/scripts/src/greengrass/deploy-local.ts.template +497 -0
- package/src/utils/files/common/scripts/src/greengrass/recipe-utils.ts.template +356 -0
- package/src/utils/files/common/scripts/src/greengrass/zip-writer.ts.template +121 -0
- package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +3 -3
- package/src/utils/files/terraform/src/metrics/metrics.tf.template +1 -1
- package/src/utils/greengrass/constants.d.ts +58 -0
- package/src/utils/greengrass/constants.js +63 -0
- package/src/utils/greengrass/constants.js.map +1 -0
- package/src/utils/greengrass/naming.d.ts +46 -0
- package/src/utils/greengrass/naming.js +67 -0
- package/src/utils/greengrass/naming.js.map +1 -0
- package/src/utils/greengrass/recipe.d.ts +143 -0
- package/src/utils/greengrass/recipe.js +119 -0
- package/src/utils/greengrass/recipe.js.map +1 -0
- package/src/utils/greengrass-constructs/files/cdk/app/greengrass-component/__componentDirName__.ts.template +42 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/artifact-bucket.ts.template +82 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/component-version.ts.template +370 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/deployment.ts.template +276 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/index.ts.template +5 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/next-version.ts.template +119 -0
- package/src/utils/greengrass-constructs/files/cdk/core/greengrass/recipe.ts.template +90 -0
- package/src/utils/greengrass-constructs/files/next-version/__nextVersionFileName__.template +195 -0
- package/src/utils/greengrass-constructs/files/terraform/app/greengrass-component/__componentDirName__/__componentDirName__.tf.template +26 -0
- package/src/utils/greengrass-constructs/files/terraform/core/greengrass/artifact-bucket/main.tf.template +204 -0
- package/src/utils/greengrass-constructs/files/terraform/core/greengrass/component-version/main.tf.template +156 -0
- package/src/utils/greengrass-constructs/files/terraform/core/greengrass/deployment/main.tf.template +186 -0
- package/src/utils/greengrass-constructs/greengrass-constructs.d.ts +57 -0
- package/src/utils/greengrass-constructs/greengrass-constructs.js +154 -0
- package/src/utils/greengrass-constructs/greengrass-constructs.js.map +1 -0
- package/src/utils/guardrail-constructs/guardrail-constructs.d.ts +3 -1
- package/src/utils/guardrail-constructs/guardrail-constructs.js +3 -1
- package/src/utils/guardrail-constructs/guardrail-constructs.js.map +1 -1
- package/src/utils/nx.d.ts +15 -0
- package/src/utils/nx.js +32 -0
- package/src/utils/nx.js.map +1 -1
- package/src/utils/shared-greengrass-scripts.d.ts +21 -0
- package/src/utils/shared-greengrass-scripts.js +43 -0
- package/src/utils/shared-greengrass-scripts.js.map +1 -0
- package/src/utils/versions.d.ts +7 -0
- package/src/utils/versions.js +7 -0
- package/src/utils/versions.js.map +1 -1
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`greengrass#component generator (python) > multi-architecture (platform: linux-amd64-arm64) > should match snapshot for a multi-architecture component > multi-arch-snapshot 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"apps/test_project/greengrass/my-component/main.py": "import logging
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
logging.basicConfig(level=logging.INFO)
|
|
9
|
+
logger = logging.getLogger("com.proj.MyComponent")
|
|
10
|
+
|
|
11
|
+
RUN_INTERVAL_SECONDS = 30
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def run_once(sequence: int) -> None:
|
|
15
|
+
logger.info("com.proj.MyComponent heartbeat %s", sequence)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> None:
|
|
19
|
+
sequence = 0
|
|
20
|
+
while True:
|
|
21
|
+
run_once(sequence)
|
|
22
|
+
sequence += 1
|
|
23
|
+
time.sleep(RUN_INTERVAL_SECONDS)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
main()
|
|
28
|
+
",
|
|
29
|
+
"apps/test_project/greengrass/my-component/recipe.yaml": "RecipeFormatVersion: '2020-01-25'
|
|
30
|
+
ComponentName: com.proj.MyComponent
|
|
31
|
+
ComponentVersion: 1.0.0
|
|
32
|
+
ComponentDescription: com.proj.MyComponent Greengrass component using Python 3.14, generated by greengrass#component.
|
|
33
|
+
ComponentPublisher: proj
|
|
34
|
+
Manifests:
|
|
35
|
+
- Platform:
|
|
36
|
+
os: linux
|
|
37
|
+
architecture: amd64
|
|
38
|
+
Artifacts:
|
|
39
|
+
# Placeholders are substituted at publish time. The basename must stay
|
|
40
|
+
# my-component-amd64.zip, which is what the Run script below unarchives to.
|
|
41
|
+
- Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component-amd64.zip
|
|
42
|
+
Unarchive: ZIP
|
|
43
|
+
Lifecycle:
|
|
44
|
+
Run: python3.14 {artifacts:decompressedPath}/my-component-amd64/main.py
|
|
45
|
+
- Platform:
|
|
46
|
+
os: linux
|
|
47
|
+
architecture: aarch64
|
|
48
|
+
Artifacts:
|
|
49
|
+
# Placeholders are substituted at publish time. The basename must stay
|
|
50
|
+
# my-component-aarch64.zip, which is what the Run script below unarchives to.
|
|
51
|
+
- Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component-aarch64.zip
|
|
52
|
+
Unarchive: ZIP
|
|
53
|
+
Lifecycle:
|
|
54
|
+
Run: python3.14 {artifacts:decompressedPath}/my-component-aarch64/main.py
|
|
55
|
+
",
|
|
56
|
+
"apps/test_project/project.json": "{
|
|
57
|
+
"name": "test-project",
|
|
58
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
59
|
+
"sourceRoot": "apps/test_project/test_project",
|
|
60
|
+
"metadata": {
|
|
61
|
+
"components": [
|
|
62
|
+
{
|
|
63
|
+
"generator": "greengrass#component",
|
|
64
|
+
"path": "greengrass/my-component/main.py",
|
|
65
|
+
"name": "my-component",
|
|
66
|
+
"language": "python",
|
|
67
|
+
"componentName": "com.proj.MyComponent",
|
|
68
|
+
"componentVersion": "1.0.0",
|
|
69
|
+
"platform": "linux-amd64-arm64",
|
|
70
|
+
"ipc": false,
|
|
71
|
+
"gdkConfig": false
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
"targets": {
|
|
76
|
+
"assemble": {
|
|
77
|
+
"dependsOn": ["my-component-artifact"]
|
|
78
|
+
},
|
|
79
|
+
"build": {
|
|
80
|
+
"dependsOn": ["my-component-artifact"]
|
|
81
|
+
},
|
|
82
|
+
"my-component-artifact": {
|
|
83
|
+
"executor": "nx:run-commands",
|
|
84
|
+
"dependsOn": ["my-component-vendor"],
|
|
85
|
+
"cache": true,
|
|
86
|
+
"inputs": [
|
|
87
|
+
"production",
|
|
88
|
+
"^production",
|
|
89
|
+
"{workspaceRoot}/packages/common/scripts/src/greengrass/**/*"
|
|
90
|
+
],
|
|
91
|
+
"outputs": [
|
|
92
|
+
"{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/greengrass-build"
|
|
93
|
+
],
|
|
94
|
+
"options": {
|
|
95
|
+
"command": "tsx packages/common/scripts/src/greengrass/build-artifact.ts {projectRoot} my-component dist/{projectRoot}/greengrass/my-component --platforms=amd64,aarch64"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"my-component-deploy-local": {
|
|
99
|
+
"executor": "nx:run-commands",
|
|
100
|
+
"dependsOn": ["my-component-artifact"],
|
|
101
|
+
"options": {
|
|
102
|
+
"command": "tsx packages/common/scripts/src/greengrass/deploy-local.ts dist/{projectRoot}/greengrass/my-component"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"my-component-logs": {
|
|
106
|
+
"executor": "nx:run-commands",
|
|
107
|
+
"continuous": true,
|
|
108
|
+
"options": {
|
|
109
|
+
"command": "tsx packages/common/scripts/src/greengrass/component-logs.ts com.proj.MyComponent"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"my-component-vendor": {
|
|
113
|
+
"executor": "nx:run-commands",
|
|
114
|
+
"dependsOn": ["compile"],
|
|
115
|
+
"cache": true,
|
|
116
|
+
"inputs": ["production", "^production"],
|
|
117
|
+
"outputs": [
|
|
118
|
+
"{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/vendor"
|
|
119
|
+
],
|
|
120
|
+
"options": {
|
|
121
|
+
"commands": [
|
|
122
|
+
"shx rm -rf dist/{projectRoot}/greengrass/my-component/vendor",
|
|
123
|
+
"shx mkdir -p dist/{projectRoot}/greengrass/my-component/vendor",
|
|
124
|
+
"uv export --frozen --no-dev --no-editable --no-emit-project --project {projectRoot} --package test-project -o dist/{projectRoot}/greengrass/my-component/vendor/requirements.txt",
|
|
125
|
+
"uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --only-binary :all: --python-platform x86_64-manylinux_2_28 --python-version 3.14 --target dist/{projectRoot}/greengrass/my-component/vendor/amd64 -r dist/{projectRoot}/greengrass/my-component/vendor/requirements.txt",
|
|
126
|
+
"uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --only-binary :all: --python-platform aarch64-manylinux_2_28 --python-version 3.14 --target dist/{projectRoot}/greengrass/my-component/vendor/aarch64 -r dist/{projectRoot}/greengrass/my-component/vendor/requirements.txt"
|
|
127
|
+
],
|
|
128
|
+
"parallel": false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
",
|
|
134
|
+
"apps/test_project/tests/greengrass/test_my_component.py": "import importlib.util
|
|
135
|
+
from pathlib import Path
|
|
136
|
+
|
|
137
|
+
# main.py lives beside recipe.yaml under greengrass/<component>/, outside this
|
|
138
|
+
# project's importable package, so it is loaded directly by file path.
|
|
139
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
140
|
+
MAIN_PATH = PROJECT_ROOT / "greengrass" / "my-component" / "main.py"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _load_main():
|
|
144
|
+
spec = importlib.util.spec_from_file_location("my_component_main", MAIN_PATH)
|
|
145
|
+
assert spec is not None and spec.loader is not None
|
|
146
|
+
module = importlib.util.module_from_spec(spec)
|
|
147
|
+
spec.loader.exec_module(module)
|
|
148
|
+
return module
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_run_once_does_not_raise():
|
|
152
|
+
module = _load_main()
|
|
153
|
+
module.run_once(1)
|
|
154
|
+
",
|
|
155
|
+
"packages/common/scripts/project.json": "{
|
|
156
|
+
"name": "@proj/common-scripts",
|
|
157
|
+
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
158
|
+
"sourceRoot": "packages/common/scripts/src",
|
|
159
|
+
"projectType": "library",
|
|
160
|
+
"tags": [],
|
|
161
|
+
"metadata": {
|
|
162
|
+
"generator": "ts#project"
|
|
163
|
+
},
|
|
164
|
+
"targets": {
|
|
165
|
+
"assemble": {
|
|
166
|
+
"dependsOn": ["compile"]
|
|
167
|
+
},
|
|
168
|
+
"build": {
|
|
169
|
+
"dependsOn": ["lint", "compile", "test"]
|
|
170
|
+
},
|
|
171
|
+
"compile": {
|
|
172
|
+
"executor": "nx:run-commands",
|
|
173
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
|
|
174
|
+
"options": {
|
|
175
|
+
"command": "tsc --build tsconfig.lib.json",
|
|
176
|
+
"cwd": "{projectRoot}"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"format": {
|
|
180
|
+
"executor": "nx:run-commands",
|
|
181
|
+
"cache": true,
|
|
182
|
+
"inputs": ["biome"],
|
|
183
|
+
"options": {
|
|
184
|
+
"command": "biome format {projectRoot}"
|
|
185
|
+
},
|
|
186
|
+
"configurations": {
|
|
187
|
+
"fix": {
|
|
188
|
+
"command": "biome format --write {projectRoot}"
|
|
189
|
+
},
|
|
190
|
+
"skip-lint": {
|
|
191
|
+
"command": "node -e \\"\\""
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"lint": {
|
|
196
|
+
"executor": "nx:run-commands",
|
|
197
|
+
"cache": true,
|
|
198
|
+
"inputs": ["biome"],
|
|
199
|
+
"dependsOn": ["format"],
|
|
200
|
+
"options": {
|
|
201
|
+
"command": "biome lint {projectRoot}"
|
|
202
|
+
},
|
|
203
|
+
"configurations": {
|
|
204
|
+
"fix": {
|
|
205
|
+
"command": "biome check --write {projectRoot}"
|
|
206
|
+
},
|
|
207
|
+
"skip-lint": {
|
|
208
|
+
"command": "node -e \\"\\""
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
",
|
|
215
|
+
"pnpm-workspace.yaml": "packages:
|
|
216
|
+
- packages/*
|
|
217
|
+
- packages/common/*
|
|
218
|
+
catalog:
|
|
219
|
+
'@types/node': 26.6.5
|
|
220
|
+
vite: 8.3.4
|
|
221
|
+
vitest: 5.0.4
|
|
222
|
+
'@vitest/coverage-v8': 5.0.4
|
|
223
|
+
jsdom: 29.1.1
|
|
224
|
+
'@nx/vitest': 23.3.0
|
|
225
|
+
js-yaml: 4.3.2
|
|
226
|
+
'@types/js-yaml': 4.0.9
|
|
227
|
+
tsx: 4.23.15
|
|
228
|
+
shx: 0.4.0
|
|
229
|
+
",
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
exports[`greengrass#component generator (python) > should match snapshot > main-snapshot 1`] = `
|
|
234
|
+
{
|
|
235
|
+
"apps/test_project/greengrass/my-component/main.py": "import logging
|
|
236
|
+
import time
|
|
237
|
+
|
|
238
|
+
logging.basicConfig(level=logging.INFO)
|
|
239
|
+
logger = logging.getLogger("com.proj.MyComponent")
|
|
240
|
+
|
|
241
|
+
RUN_INTERVAL_SECONDS = 30
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def run_once(sequence: int) -> None:
|
|
245
|
+
logger.info("com.proj.MyComponent heartbeat %s", sequence)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def main() -> None:
|
|
249
|
+
sequence = 0
|
|
250
|
+
while True:
|
|
251
|
+
run_once(sequence)
|
|
252
|
+
sequence += 1
|
|
253
|
+
time.sleep(RUN_INTERVAL_SECONDS)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
if __name__ == "__main__":
|
|
257
|
+
main()
|
|
258
|
+
",
|
|
259
|
+
"apps/test_project/greengrass/my-component/recipe.yaml": "RecipeFormatVersion: '2020-01-25'
|
|
260
|
+
ComponentName: com.proj.MyComponent
|
|
261
|
+
ComponentVersion: 1.0.0
|
|
262
|
+
ComponentDescription: com.proj.MyComponent Greengrass component using Python 3.14, generated by greengrass#component.
|
|
263
|
+
ComponentPublisher: proj
|
|
264
|
+
Manifests:
|
|
265
|
+
- Platform:
|
|
266
|
+
os: linux
|
|
267
|
+
architecture: aarch64
|
|
268
|
+
Artifacts:
|
|
269
|
+
# Placeholders are substituted at publish time. The basename must stay
|
|
270
|
+
# my-component.zip, which is what the Run script below unarchives to.
|
|
271
|
+
- Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/my-component.zip
|
|
272
|
+
Unarchive: ZIP
|
|
273
|
+
Lifecycle:
|
|
274
|
+
Run: python3.14 {artifacts:decompressedPath}/my-component/main.py
|
|
275
|
+
",
|
|
276
|
+
"apps/test_project/project.json": "{
|
|
277
|
+
"name": "test-project",
|
|
278
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
279
|
+
"sourceRoot": "apps/test_project/test_project",
|
|
280
|
+
"metadata": {
|
|
281
|
+
"components": [
|
|
282
|
+
{
|
|
283
|
+
"generator": "greengrass#component",
|
|
284
|
+
"path": "greengrass/my-component/main.py",
|
|
285
|
+
"name": "my-component",
|
|
286
|
+
"language": "python",
|
|
287
|
+
"componentName": "com.proj.MyComponent",
|
|
288
|
+
"componentVersion": "1.0.0",
|
|
289
|
+
"platform": "linux-arm64",
|
|
290
|
+
"ipc": false,
|
|
291
|
+
"gdkConfig": false
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
"targets": {
|
|
296
|
+
"assemble": {
|
|
297
|
+
"dependsOn": ["my-component-artifact"]
|
|
298
|
+
},
|
|
299
|
+
"build": {
|
|
300
|
+
"dependsOn": ["my-component-artifact"]
|
|
301
|
+
},
|
|
302
|
+
"my-component-artifact": {
|
|
303
|
+
"executor": "nx:run-commands",
|
|
304
|
+
"dependsOn": ["my-component-vendor"],
|
|
305
|
+
"cache": true,
|
|
306
|
+
"inputs": [
|
|
307
|
+
"production",
|
|
308
|
+
"^production",
|
|
309
|
+
"{workspaceRoot}/packages/common/scripts/src/greengrass/**/*"
|
|
310
|
+
],
|
|
311
|
+
"outputs": [
|
|
312
|
+
"{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/greengrass-build"
|
|
313
|
+
],
|
|
314
|
+
"options": {
|
|
315
|
+
"command": "tsx packages/common/scripts/src/greengrass/build-artifact.ts {projectRoot} my-component dist/{projectRoot}/greengrass/my-component"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
"my-component-deploy-local": {
|
|
319
|
+
"executor": "nx:run-commands",
|
|
320
|
+
"dependsOn": ["my-component-artifact"],
|
|
321
|
+
"options": {
|
|
322
|
+
"command": "tsx packages/common/scripts/src/greengrass/deploy-local.ts dist/{projectRoot}/greengrass/my-component"
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
"my-component-logs": {
|
|
326
|
+
"executor": "nx:run-commands",
|
|
327
|
+
"continuous": true,
|
|
328
|
+
"options": {
|
|
329
|
+
"command": "tsx packages/common/scripts/src/greengrass/component-logs.ts com.proj.MyComponent"
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
"my-component-vendor": {
|
|
333
|
+
"executor": "nx:run-commands",
|
|
334
|
+
"dependsOn": ["compile"],
|
|
335
|
+
"cache": true,
|
|
336
|
+
"inputs": ["production", "^production"],
|
|
337
|
+
"outputs": [
|
|
338
|
+
"{workspaceRoot}/dist/{projectRoot}/greengrass/my-component/vendor"
|
|
339
|
+
],
|
|
340
|
+
"options": {
|
|
341
|
+
"commands": [
|
|
342
|
+
"shx rm -rf dist/{projectRoot}/greengrass/my-component/vendor",
|
|
343
|
+
"shx mkdir -p dist/{projectRoot}/greengrass/my-component/vendor",
|
|
344
|
+
"uv export --frozen --no-dev --no-editable --no-emit-project --project {projectRoot} --package test-project -o dist/{projectRoot}/greengrass/my-component/vendor/requirements.txt",
|
|
345
|
+
"uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --only-binary :all: --python-platform aarch64-manylinux_2_28 --python-version 3.14 --target dist/{projectRoot}/greengrass/my-component/vendor -r dist/{projectRoot}/greengrass/my-component/vendor/requirements.txt"
|
|
346
|
+
],
|
|
347
|
+
"parallel": false
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
",
|
|
353
|
+
"apps/test_project/tests/greengrass/test_my_component.py": "import importlib.util
|
|
354
|
+
from pathlib import Path
|
|
355
|
+
|
|
356
|
+
# main.py lives beside recipe.yaml under greengrass/<component>/, outside this
|
|
357
|
+
# project's importable package, so it is loaded directly by file path.
|
|
358
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
359
|
+
MAIN_PATH = PROJECT_ROOT / "greengrass" / "my-component" / "main.py"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _load_main():
|
|
363
|
+
spec = importlib.util.spec_from_file_location("my_component_main", MAIN_PATH)
|
|
364
|
+
assert spec is not None and spec.loader is not None
|
|
365
|
+
module = importlib.util.module_from_spec(spec)
|
|
366
|
+
spec.loader.exec_module(module)
|
|
367
|
+
return module
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def test_run_once_does_not_raise():
|
|
371
|
+
module = _load_main()
|
|
372
|
+
module.run_once(1)
|
|
373
|
+
",
|
|
374
|
+
"packages/common/scripts/project.json": "{
|
|
375
|
+
"name": "@proj/common-scripts",
|
|
376
|
+
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
377
|
+
"sourceRoot": "packages/common/scripts/src",
|
|
378
|
+
"projectType": "library",
|
|
379
|
+
"tags": [],
|
|
380
|
+
"metadata": {
|
|
381
|
+
"generator": "ts#project"
|
|
382
|
+
},
|
|
383
|
+
"targets": {
|
|
384
|
+
"assemble": {
|
|
385
|
+
"dependsOn": ["compile"]
|
|
386
|
+
},
|
|
387
|
+
"build": {
|
|
388
|
+
"dependsOn": ["lint", "compile", "test"]
|
|
389
|
+
},
|
|
390
|
+
"compile": {
|
|
391
|
+
"executor": "nx:run-commands",
|
|
392
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
|
|
393
|
+
"options": {
|
|
394
|
+
"command": "tsc --build tsconfig.lib.json",
|
|
395
|
+
"cwd": "{projectRoot}"
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
"format": {
|
|
399
|
+
"executor": "nx:run-commands",
|
|
400
|
+
"cache": true,
|
|
401
|
+
"inputs": ["biome"],
|
|
402
|
+
"options": {
|
|
403
|
+
"command": "biome format {projectRoot}"
|
|
404
|
+
},
|
|
405
|
+
"configurations": {
|
|
406
|
+
"fix": {
|
|
407
|
+
"command": "biome format --write {projectRoot}"
|
|
408
|
+
},
|
|
409
|
+
"skip-lint": {
|
|
410
|
+
"command": "node -e \\"\\""
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
"lint": {
|
|
415
|
+
"executor": "nx:run-commands",
|
|
416
|
+
"cache": true,
|
|
417
|
+
"inputs": ["biome"],
|
|
418
|
+
"dependsOn": ["format"],
|
|
419
|
+
"options": {
|
|
420
|
+
"command": "biome lint {projectRoot}"
|
|
421
|
+
},
|
|
422
|
+
"configurations": {
|
|
423
|
+
"fix": {
|
|
424
|
+
"command": "biome check --write {projectRoot}"
|
|
425
|
+
},
|
|
426
|
+
"skip-lint": {
|
|
427
|
+
"command": "node -e \\"\\""
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
",
|
|
434
|
+
"pnpm-workspace.yaml": "packages:
|
|
435
|
+
- packages/*
|
|
436
|
+
- packages/common/*
|
|
437
|
+
catalog:
|
|
438
|
+
'@types/node': 26.6.5
|
|
439
|
+
vite: 8.3.4
|
|
440
|
+
vitest: 5.0.4
|
|
441
|
+
'@vitest/coverage-v8': 5.0.4
|
|
442
|
+
jsdom: 29.1.1
|
|
443
|
+
'@nx/vitest': 23.3.0
|
|
444
|
+
js-yaml: 4.3.2
|
|
445
|
+
'@types/js-yaml': 4.0.9
|
|
446
|
+
tsx: 4.23.15
|
|
447
|
+
shx: 0.4.0
|
|
448
|
+
",
|
|
449
|
+
}
|
|
450
|
+
`;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<%_ if (ipc) { _%>
|
|
2
|
+
import logging
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
|
|
6
|
+
from awsiot.greengrasscoreipc.model import JsonMessage, PublishMessage
|
|
7
|
+
|
|
8
|
+
logging.basicConfig(level=logging.INFO)
|
|
9
|
+
logger = logging.getLogger("<%- componentName %>")
|
|
10
|
+
|
|
11
|
+
TOPIC = "<%- componentName %>/heartbeat"
|
|
12
|
+
PUBLISH_INTERVAL_SECONDS = 30
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def publish_heartbeat(client: GreengrassCoreIPCClientV2, sequence: int) -> None:
|
|
16
|
+
client.publish_to_topic(
|
|
17
|
+
topic=TOPIC,
|
|
18
|
+
publish_message=PublishMessage(
|
|
19
|
+
json_message=JsonMessage(message={"sequence": sequence})
|
|
20
|
+
),
|
|
21
|
+
)
|
|
22
|
+
logger.info("Published heartbeat %s to %s", sequence, TOPIC)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> None:
|
|
26
|
+
client = GreengrassCoreIPCClientV2()
|
|
27
|
+
sequence = 0
|
|
28
|
+
while True:
|
|
29
|
+
publish_heartbeat(client, sequence)
|
|
30
|
+
sequence += 1
|
|
31
|
+
time.sleep(PUBLISH_INTERVAL_SECONDS)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
main()
|
|
36
|
+
<%_ } else { _%>
|
|
37
|
+
import logging
|
|
38
|
+
import time
|
|
39
|
+
|
|
40
|
+
logging.basicConfig(level=logging.INFO)
|
|
41
|
+
logger = logging.getLogger("<%- componentName %>")
|
|
42
|
+
|
|
43
|
+
RUN_INTERVAL_SECONDS = 30
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def run_once(sequence: int) -> None:
|
|
47
|
+
logger.info("<%- componentName %> heartbeat %s", sequence)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main() -> None:
|
|
51
|
+
sequence = 0
|
|
52
|
+
while True:
|
|
53
|
+
run_once(sequence)
|
|
54
|
+
sequence += 1
|
|
55
|
+
time.sleep(RUN_INTERVAL_SECONDS)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
60
|
+
<%_ } _%>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
RecipeFormatVersion: '<%- recipeFormat %>'
|
|
2
|
+
ComponentName: <%- componentName %>
|
|
3
|
+
ComponentVersion: <%- version %>
|
|
4
|
+
ComponentDescription: <%- componentDescription %>
|
|
5
|
+
ComponentPublisher: <%- publisher %>
|
|
6
|
+
<%_ if (ipc) { _%>
|
|
7
|
+
ComponentConfiguration:
|
|
8
|
+
DefaultConfiguration:
|
|
9
|
+
accessControl:
|
|
10
|
+
aws.greengrass.ipc.pubsub:
|
|
11
|
+
<%- componentName %>:pubsub:1:
|
|
12
|
+
policyDescription: Allow publishing heartbeat messages to this component's own topic.
|
|
13
|
+
operations:
|
|
14
|
+
- aws.greengrass#PublishToTopic
|
|
15
|
+
resources:
|
|
16
|
+
- <%- componentName %>/heartbeat
|
|
17
|
+
<%_ } _%>
|
|
18
|
+
Manifests:
|
|
19
|
+
<%_ manifests.forEach((m) => { _%>
|
|
20
|
+
- Platform:
|
|
21
|
+
os: <%- m.os %>
|
|
22
|
+
architecture: <%- m.architecture %>
|
|
23
|
+
Artifacts:
|
|
24
|
+
# Placeholders are substituted at publish time. The basename must stay
|
|
25
|
+
# <%- m.artifactBaseName %>.zip, which is what the Run script below unarchives to.
|
|
26
|
+
- Uri: s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/<%- m.artifactBaseName %>.zip
|
|
27
|
+
Unarchive: ZIP
|
|
28
|
+
Lifecycle:
|
|
29
|
+
Run: python<%- pythonFloor %> {artifacts:decompressedPath}/<%- m.artifactBaseName %>/main.py
|
|
30
|
+
<%_ }); _%>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"component": {
|
|
3
|
+
"<%- componentName %>": {
|
|
4
|
+
"author": "<%- publisher %>",
|
|
5
|
+
"version": "<%- version %>",
|
|
6
|
+
"build": {
|
|
7
|
+
"build_system": "custom",
|
|
8
|
+
"custom_build_command": ["nx", "run", "<%- project %>:<%- componentDirName %>-artifact"]
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"gdk_version": "1.0.0"
|
|
13
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
# main.py lives beside recipe.yaml under greengrass/<component>/, outside this
|
|
5
|
+
# project's importable package, so it is loaded directly by file path.
|
|
6
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
7
|
+
MAIN_PATH = PROJECT_ROOT / "greengrass" / "<%- componentDirName %>" / "main.py"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _load_main():
|
|
11
|
+
spec = importlib.util.spec_from_file_location("<%- componentSnakeCase %>_main", MAIN_PATH)
|
|
12
|
+
assert spec is not None and spec.loader is not None
|
|
13
|
+
module = importlib.util.module_from_spec(spec)
|
|
14
|
+
spec.loader.exec_module(module)
|
|
15
|
+
return module
|
|
16
|
+
|
|
17
|
+
<%_ if (ipc) { _%>
|
|
18
|
+
|
|
19
|
+
def test_publish_heartbeat_publishes_to_own_topic():
|
|
20
|
+
module = _load_main()
|
|
21
|
+
calls = []
|
|
22
|
+
|
|
23
|
+
class FakeClient:
|
|
24
|
+
def publish_to_topic(self, **kwargs):
|
|
25
|
+
calls.append(kwargs)
|
|
26
|
+
|
|
27
|
+
module.publish_heartbeat(FakeClient(), 1)
|
|
28
|
+
|
|
29
|
+
assert len(calls) == 1
|
|
30
|
+
assert calls[0]["topic"] == module.TOPIC
|
|
31
|
+
assert module.TOPIC == "<%- componentName %>/heartbeat"
|
|
32
|
+
<%_ } else { _%>
|
|
33
|
+
|
|
34
|
+
def test_run_once_does_not_raise():
|
|
35
|
+
module = _load_main()
|
|
36
|
+
module.run_once(1)
|
|
37
|
+
<%_ } _%>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type GeneratorCallback, type Tree } from '@nx/devkit';
|
|
6
|
+
import type { NormalizedComponent } from '../common.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generates an AWS IoT Greengrass v2 component on an existing Python project:
|
|
9
|
+
* packaging and local-deployment targets (`<c>-vendor`, `<c>-artifact`,
|
|
10
|
+
* `<c>-deploy-local`, `<c>-logs`), plus, unless `--infra none`, a
|
|
11
|
+
* `GreengrassComponentVersion` CDK construct (or Terraform module, via the
|
|
12
|
+
* `hashicorp/awscc` provider) that publishes the built artifact.
|
|
13
|
+
*/
|
|
14
|
+
export declare const pythonGreengrassComponentGenerator: (tree: Tree, component: NormalizedComponent) => Promise<GeneratorCallback>;
|
|
15
|
+
export default pythonGreengrassComponentGenerator;
|