@empire-builder-kit/containers 0.0.1-alpha.4
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 +20 -0
- package/dist/executors.json +3 -0
- package/dist/generators/service/files-go/Dockerfile.template +11 -0
- package/dist/generators/service/files-go/README.md.template +11 -0
- package/dist/generators/service/files-go/cmd/main.go.template +34 -0
- package/dist/generators/service/files-go/docs/contracts.md.template +9 -0
- package/dist/generators/service/files-go/go.mod.template +3 -0
- package/dist/generators/service/files-python/Dockerfile.template +12 -0
- package/dist/generators/service/files-python/README.md.template +11 -0
- package/dist/generators/service/files-python/docs/contracts.md.template +9 -0
- package/dist/generators/service/files-python/pyproject.toml.template +15 -0
- package/dist/generators/service/files-python/src/main.py.template +20 -0
- package/dist/generators/service/files-rust/Cargo.toml.template +16 -0
- package/dist/generators/service/files-rust/Dockerfile.template +12 -0
- package/dist/generators/service/files-rust/README.md.template +11 -0
- package/dist/generators/service/files-rust/docs/contracts.md.template +9 -0
- package/dist/generators/service/files-rust/src/main.rs.template +29 -0
- package/dist/generators/service/files-typescript/Dockerfile.template +30 -0
- package/dist/generators/service/files-typescript/README.md.template +24 -0
- package/dist/generators/service/files-typescript/docs/architecture.md.template +18 -0
- package/dist/generators/service/files-typescript/docs/contracts.md.template +20 -0
- package/dist/generators/service/files-typescript/docs/operations.md.template +24 -0
- package/dist/generators/service/files-typescript/eslint.config.mjs.template +3 -0
- package/dist/generators/service/files-typescript/infra/service.ts.template +64 -0
- package/dist/generators/service/files-typescript/package.json.template +7 -0
- package/dist/generators/service/files-typescript/src/index.ts.template +2 -0
- package/dist/generators/service/files-typescript/src/main.ts.template +60 -0
- package/dist/generators/service/files-typescript/src/service.spec.ts.template +49 -0
- package/dist/generators/service/files-typescript/src/service.ts.template +57 -0
- package/dist/generators/service/files-typescript/tsconfig.app.json.template +12 -0
- package/dist/generators/service/files-typescript/tsconfig.json.template +7 -0
- package/dist/generators/service/files-typescript/tsconfig.spec.json.template +7 -0
- package/dist/generators/service/files-typescript/vitest.config.mts.template +17 -0
- package/dist/generators/service/schema.d.ts +8 -0
- package/dist/generators/service/schema.json +40 -0
- package/dist/generators/service/service.d.ts +5 -0
- package/dist/generators/service/service.d.ts.map +1 -0
- package/dist/generators/service/service.js +198 -0
- package/dist/generators/task/files-go/Dockerfile.template +10 -0
- package/dist/generators/task/files-go/README.md.template +11 -0
- package/dist/generators/task/files-go/cmd/main.go.template +22 -0
- package/dist/generators/task/files-go/docs/contracts.md.template +9 -0
- package/dist/generators/task/files-go/go.mod.template +3 -0
- package/dist/generators/task/files-python/Dockerfile.template +10 -0
- package/dist/generators/task/files-python/README.md.template +11 -0
- package/dist/generators/task/files-python/docs/contracts.md.template +9 -0
- package/dist/generators/task/files-python/pyproject.toml.template +12 -0
- package/dist/generators/task/files-python/src/main.py.template +26 -0
- package/dist/generators/task/files-rust/Cargo.toml.template +15 -0
- package/dist/generators/task/files-rust/Dockerfile.template +11 -0
- package/dist/generators/task/files-rust/README.md.template +11 -0
- package/dist/generators/task/files-rust/docs/contracts.md.template +9 -0
- package/dist/generators/task/files-rust/src/main.rs.template +12 -0
- package/dist/generators/task/files-typescript/Dockerfile.template +25 -0
- package/dist/generators/task/files-typescript/README.md.template +24 -0
- package/dist/generators/task/files-typescript/docs/architecture.md.template +18 -0
- package/dist/generators/task/files-typescript/docs/contracts.md.template +20 -0
- package/dist/generators/task/files-typescript/docs/operations.md.template +24 -0
- package/dist/generators/task/files-typescript/eslint.config.mjs.template +3 -0
- package/dist/generators/task/files-typescript/infra/task.ts.template +35 -0
- package/dist/generators/task/files-typescript/package.json.template +7 -0
- package/dist/generators/task/files-typescript/src/index.ts.template +6 -0
- package/dist/generators/task/files-typescript/src/main.ts.template +45 -0
- package/dist/generators/task/files-typescript/src/task.spec.ts.template +66 -0
- package/dist/generators/task/files-typescript/src/task.ts.template +71 -0
- package/dist/generators/task/files-typescript/tsconfig.app.json.template +13 -0
- package/dist/generators/task/files-typescript/tsconfig.json.template +19 -0
- package/dist/generators/task/files-typescript/tsconfig.spec.json.template +11 -0
- package/dist/generators/task/files-typescript/vitest.config.mts.template +9 -0
- package/dist/generators/task/schema.d.ts +8 -0
- package/dist/generators/task/schema.json +40 -0
- package/dist/generators/task/task.d.ts +5 -0
- package/dist/generators/task/task.d.ts.map +1 -0
- package/dist/generators/task/task.js +198 -0
- package/dist/generators.json +14 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/executors.json +3 -0
- package/generators.json +14 -0
- package/package.json +92 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
root: __dirname,
|
|
5
|
+
cacheDir: '<%= offsetFromRoot %>node_modules/.vite/<%= projectRoot %>',
|
|
6
|
+
test: {
|
|
7
|
+
name: '<%= projectName %>',
|
|
8
|
+
watch: false,
|
|
9
|
+
environment: 'node',
|
|
10
|
+
include: ['src/**/*.{test,spec}.ts'],
|
|
11
|
+
reporters: ['default'],
|
|
12
|
+
coverage: {
|
|
13
|
+
provider: 'v8',
|
|
14
|
+
reportsDirectory: './test-output/vitest/coverage',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "Service",
|
|
4
|
+
"title": "Generate an EBK container service",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"name": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Name for the service within the app group.",
|
|
10
|
+
"$default": { "$source": "argv", "index": 0 },
|
|
11
|
+
"x-prompt": "What name should the service have?"
|
|
12
|
+
},
|
|
13
|
+
"app": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Owning Empire Builder Kit app-group name.",
|
|
16
|
+
"x-prompt": "Which app group should receive the service?"
|
|
17
|
+
},
|
|
18
|
+
"language": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Programming language for the service.",
|
|
21
|
+
"enum": ["typescript", "rust", "go", "python"],
|
|
22
|
+
"default": "typescript"
|
|
23
|
+
},
|
|
24
|
+
"directory": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Base directory for app groups.",
|
|
27
|
+
"default": "packages"
|
|
28
|
+
},
|
|
29
|
+
"tags": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Comma-separated additional tags to apply to the project."
|
|
32
|
+
},
|
|
33
|
+
"skipFormat": {
|
|
34
|
+
"type": "boolean",
|
|
35
|
+
"description": "Skip formatting files.",
|
|
36
|
+
"default": false
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"required": ["name", "app"]
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/generators/service/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AA+MlD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,sBAAsB,iBA8ChC;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serviceGenerator = serviceGenerator;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const path = tslib_1.__importStar(require("node:path"));
|
|
7
|
+
function runtimeForLanguage(language) {
|
|
8
|
+
switch (language) {
|
|
9
|
+
case 'typescript':
|
|
10
|
+
return 'node';
|
|
11
|
+
case 'rust':
|
|
12
|
+
return 'native';
|
|
13
|
+
case 'go':
|
|
14
|
+
return 'native';
|
|
15
|
+
case 'python':
|
|
16
|
+
return 'python';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function targetsForLanguage(language, projectRoot, projectName, outputPath) {
|
|
20
|
+
const cwd = projectRoot;
|
|
21
|
+
switch (language) {
|
|
22
|
+
case 'typescript':
|
|
23
|
+
return {
|
|
24
|
+
build: {
|
|
25
|
+
executor: 'nx:run-commands',
|
|
26
|
+
outputs: [`{workspaceRoot}/${outputPath}`],
|
|
27
|
+
options: { cwd, command: 'tsc -p tsconfig.app.json' },
|
|
28
|
+
},
|
|
29
|
+
lint: {
|
|
30
|
+
executor: 'nx:run-commands',
|
|
31
|
+
options: { cwd, command: 'eslint .' },
|
|
32
|
+
},
|
|
33
|
+
typecheck: {
|
|
34
|
+
executor: 'nx:run-commands',
|
|
35
|
+
options: { cwd, command: 'tsc --noEmit -p tsconfig.json' },
|
|
36
|
+
},
|
|
37
|
+
test: {
|
|
38
|
+
executor: 'nx:run-commands',
|
|
39
|
+
options: {
|
|
40
|
+
cwd,
|
|
41
|
+
command: 'vitest run --config vitest.config.mts',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
dev: {
|
|
45
|
+
executor: 'nx:run-commands',
|
|
46
|
+
options: {
|
|
47
|
+
cwd,
|
|
48
|
+
command: 'node --watch --enable-source-maps --import @swc-node/register/esm-register src/main.ts',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
'docker-build': {
|
|
52
|
+
executor: 'nx:run-commands',
|
|
53
|
+
options: {
|
|
54
|
+
command: `docker build --tag ${projectName} ${projectRoot}`,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
case 'rust':
|
|
59
|
+
return {
|
|
60
|
+
build: {
|
|
61
|
+
executor: 'nx:run-commands',
|
|
62
|
+
options: { cwd, command: 'cargo build --release' },
|
|
63
|
+
},
|
|
64
|
+
lint: {
|
|
65
|
+
executor: 'nx:run-commands',
|
|
66
|
+
options: { cwd, command: 'cargo clippy -- -D warnings' },
|
|
67
|
+
},
|
|
68
|
+
test: {
|
|
69
|
+
executor: 'nx:run-commands',
|
|
70
|
+
options: { cwd, command: 'cargo test' },
|
|
71
|
+
},
|
|
72
|
+
dev: {
|
|
73
|
+
executor: 'nx:run-commands',
|
|
74
|
+
options: { cwd, command: 'cargo watch -x run' },
|
|
75
|
+
},
|
|
76
|
+
'docker-build': {
|
|
77
|
+
executor: 'nx:run-commands',
|
|
78
|
+
options: {
|
|
79
|
+
command: `docker build --tag ${projectName} ${projectRoot}`,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
case 'go':
|
|
84
|
+
return {
|
|
85
|
+
build: {
|
|
86
|
+
executor: 'nx:run-commands',
|
|
87
|
+
options: { cwd, command: 'go build -o bin/service ./cmd/...' },
|
|
88
|
+
},
|
|
89
|
+
lint: {
|
|
90
|
+
executor: 'nx:run-commands',
|
|
91
|
+
options: { cwd, command: 'golangci-lint run' },
|
|
92
|
+
},
|
|
93
|
+
typecheck: {
|
|
94
|
+
executor: 'nx:run-commands',
|
|
95
|
+
options: { cwd, command: 'go vet ./...' },
|
|
96
|
+
},
|
|
97
|
+
test: {
|
|
98
|
+
executor: 'nx:run-commands',
|
|
99
|
+
options: { cwd, command: 'go test ./...' },
|
|
100
|
+
},
|
|
101
|
+
dev: {
|
|
102
|
+
executor: 'nx:run-commands',
|
|
103
|
+
options: { cwd, command: 'go run ./cmd/...' },
|
|
104
|
+
},
|
|
105
|
+
'docker-build': {
|
|
106
|
+
executor: 'nx:run-commands',
|
|
107
|
+
options: {
|
|
108
|
+
command: `docker build --tag ${projectName} ${projectRoot}`,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
case 'python':
|
|
113
|
+
return {
|
|
114
|
+
lint: {
|
|
115
|
+
executor: 'nx:run-commands',
|
|
116
|
+
options: { cwd, command: 'ruff check .' },
|
|
117
|
+
},
|
|
118
|
+
typecheck: {
|
|
119
|
+
executor: 'nx:run-commands',
|
|
120
|
+
options: { cwd, command: 'mypy src/' },
|
|
121
|
+
},
|
|
122
|
+
test: {
|
|
123
|
+
executor: 'nx:run-commands',
|
|
124
|
+
options: { cwd, command: 'pytest' },
|
|
125
|
+
},
|
|
126
|
+
dev: {
|
|
127
|
+
executor: 'nx:run-commands',
|
|
128
|
+
options: { cwd, command: 'uvicorn src.main:app --reload' },
|
|
129
|
+
},
|
|
130
|
+
'docker-build': {
|
|
131
|
+
executor: 'nx:run-commands',
|
|
132
|
+
options: {
|
|
133
|
+
command: `docker build --tag ${projectName} ${projectRoot}`,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function normalizeOptions(options) {
|
|
140
|
+
const appNames = (0, devkit_1.names)(options.app);
|
|
141
|
+
const serviceNames = (0, devkit_1.names)(options.name);
|
|
142
|
+
const language = options.language ?? 'typescript';
|
|
143
|
+
const directory = (options.directory ?? 'packages').replace(/\\/g, '/');
|
|
144
|
+
const projectRoot = (0, devkit_1.joinPathFragments)(directory, appNames.fileName, 'apps', 'service', serviceNames.fileName);
|
|
145
|
+
const userTags = options.tags
|
|
146
|
+
?.split(',')
|
|
147
|
+
.map((tag) => tag.trim())
|
|
148
|
+
.filter(Boolean) ?? [];
|
|
149
|
+
return {
|
|
150
|
+
app: appNames.fileName,
|
|
151
|
+
appName: appNames.fileName,
|
|
152
|
+
className: appNames.className,
|
|
153
|
+
directory,
|
|
154
|
+
language,
|
|
155
|
+
name: serviceNames.fileName,
|
|
156
|
+
offsetFromRoot: (0, devkit_1.offsetFromRoot)(projectRoot),
|
|
157
|
+
outputPath: (0, devkit_1.joinPathFragments)('dist', projectRoot),
|
|
158
|
+
projectName: `${appNames.fileName}-service-${serviceNames.fileName}`,
|
|
159
|
+
projectRoot,
|
|
160
|
+
projectTitle: `${appNames.className} Service ${serviceNames.className}`,
|
|
161
|
+
skipFormat: options.skipFormat,
|
|
162
|
+
tags: [
|
|
163
|
+
`scope:${appNames.fileName}`,
|
|
164
|
+
'layer:app',
|
|
165
|
+
'type:service',
|
|
166
|
+
`runtime:${runtimeForLanguage(language)}`,
|
|
167
|
+
'deploy:container',
|
|
168
|
+
'visibility:internal',
|
|
169
|
+
...userTags,
|
|
170
|
+
],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function serviceGenerator(tree, options) {
|
|
174
|
+
const normalized = normalizeOptions(options);
|
|
175
|
+
const appRoot = (0, devkit_1.joinPathFragments)(normalized.directory, normalized.appName);
|
|
176
|
+
if (!tree.exists(appRoot)) {
|
|
177
|
+
throw new Error(`App group "${normalized.app}" does not exist at "${appRoot}". Generate the app group first.`);
|
|
178
|
+
}
|
|
179
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(normalized.projectRoot, 'project.json')) ||
|
|
180
|
+
tree.exists((0, devkit_1.joinPathFragments)(normalized.projectRoot, 'package.json'))) {
|
|
181
|
+
throw new Error(`Service "${normalized.name}" already exists at "${normalized.projectRoot}".`);
|
|
182
|
+
}
|
|
183
|
+
(0, devkit_1.addProjectConfiguration)(tree, normalized.projectName, {
|
|
184
|
+
root: normalized.projectRoot,
|
|
185
|
+
projectType: 'application',
|
|
186
|
+
sourceRoot: `${normalized.projectRoot}/src`,
|
|
187
|
+
tags: normalized.tags,
|
|
188
|
+
targets: targetsForLanguage(normalized.language, normalized.projectRoot, normalized.projectName, normalized.outputPath),
|
|
189
|
+
});
|
|
190
|
+
(0, devkit_1.generateFiles)(tree, path.join(__dirname, `files-${normalized.language}`), normalized.projectRoot, {
|
|
191
|
+
...normalized,
|
|
192
|
+
tmpl: '',
|
|
193
|
+
});
|
|
194
|
+
if (!normalized.skipFormat) {
|
|
195
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.default = serviceGenerator;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# <%= projectTitle %>
|
|
2
|
+
|
|
3
|
+
Go task for the `<%= app %>` app group.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `pnpm nx run <%= projectName %>:build` — compile binary
|
|
8
|
+
- `pnpm nx run <%= projectName %>:dev` — run locally
|
|
9
|
+
- `pnpm nx run <%= projectName %>:test` — run tests
|
|
10
|
+
- `pnpm nx run <%= projectName %>:lint` — run golangci-lint
|
|
11
|
+
- `pnpm nx run <%= projectName %>:docker-build` — build container image
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"log/slog"
|
|
5
|
+
"os"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
func main() {
|
|
9
|
+
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
|
10
|
+
slog.SetDefault(logger)
|
|
11
|
+
|
|
12
|
+
trigger := os.Getenv("TASK_TRIGGER")
|
|
13
|
+
if trigger == "" {
|
|
14
|
+
trigger = "manual"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
slog.Info("task started", "trigger", trigger, "task", "<%= projectName %>")
|
|
18
|
+
|
|
19
|
+
// Task logic goes here
|
|
20
|
+
|
|
21
|
+
slog.Info("task completed successfully")
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
FROM python:3.12-slim AS builder
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
COPY pyproject.toml ./
|
|
4
|
+
RUN pip install --no-cache-dir .
|
|
5
|
+
|
|
6
|
+
FROM python:3.12-slim
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
|
|
9
|
+
COPY src/ src/
|
|
10
|
+
CMD ["python", "src/main.py"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# <%= projectTitle %>
|
|
2
|
+
|
|
3
|
+
Python task for the `<%= app %>` app group.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `pnpm nx run <%= projectName %>:dev` — run locally
|
|
8
|
+
- `pnpm nx run <%= projectName %>:test` — run pytest
|
|
9
|
+
- `pnpm nx run <%= projectName %>:lint` — run ruff
|
|
10
|
+
- `pnpm nx run <%= projectName %>:typecheck` — run mypy
|
|
11
|
+
- `pnpm nx run <%= projectName %>:docker-build` — build container image
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""<%= projectTitle %> — task runner for the <%= app %> app group."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
logging.basicConfig(
|
|
9
|
+
stream=sys.stdout,
|
|
10
|
+
level=logging.INFO,
|
|
11
|
+
format="%(message)s",
|
|
12
|
+
)
|
|
13
|
+
logger = logging.getLogger("<%= projectName %>")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main():
|
|
17
|
+
trigger = os.environ.get("TASK_TRIGGER", "manual")
|
|
18
|
+
logger.info(json.dumps({"msg": "task started", "trigger": trigger, "task": "<%= projectName %>"}))
|
|
19
|
+
|
|
20
|
+
# Task logic goes here
|
|
21
|
+
|
|
22
|
+
logger.info(json.dumps({"msg": "task completed successfully"}))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "<%= projectName %>"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
|
|
6
|
+
[[bin]]
|
|
7
|
+
name = "task"
|
|
8
|
+
path = "src/main.rs"
|
|
9
|
+
|
|
10
|
+
[dependencies]
|
|
11
|
+
serde = { version = "1", features = ["derive"] }
|
|
12
|
+
serde_json = "1"
|
|
13
|
+
tokio = { version = "1", features = ["full"] }
|
|
14
|
+
tracing = "0.1"
|
|
15
|
+
tracing-subscriber = { version = "0.3", features = ["json"] }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
FROM rust:1-bookworm AS builder
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
COPY Cargo.toml Cargo.lock* ./
|
|
4
|
+
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
|
|
5
|
+
COPY src/ src/
|
|
6
|
+
RUN cargo build --release
|
|
7
|
+
|
|
8
|
+
FROM debian:bookworm-slim
|
|
9
|
+
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
|
|
10
|
+
COPY --from=builder /app/target/release/task /usr/local/bin/task
|
|
11
|
+
CMD ["task"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# <%= projectTitle %>
|
|
2
|
+
|
|
3
|
+
Rust task for the `<%= app %>` app group.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `pnpm nx run <%= projectName %>:build` — compile release binary
|
|
8
|
+
- `pnpm nx run <%= projectName %>:dev` — run locally
|
|
9
|
+
- `pnpm nx run <%= projectName %>:test` — run tests
|
|
10
|
+
- `pnpm nx run <%= projectName %>:lint` — run clippy
|
|
11
|
+
- `pnpm nx run <%= projectName %>:docker-build` — build container image
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
use std::env;
|
|
2
|
+
|
|
3
|
+
#[tokio::main]
|
|
4
|
+
async fn main() {
|
|
5
|
+
tracing_subscriber::fmt().json().init();
|
|
6
|
+
|
|
7
|
+
let trigger = env::var("TASK_TRIGGER").unwrap_or_else(|_| "manual".to_string());
|
|
8
|
+
tracing::info!(trigger = %trigger, task = "<%= projectName %>", "task started");
|
|
9
|
+
|
|
10
|
+
// Task logic goes here
|
|
11
|
+
tracing::info!("task completed successfully");
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.7
|
|
2
|
+
|
|
3
|
+
FROM node:22-bookworm-slim AS build
|
|
4
|
+
WORKDIR /workspace
|
|
5
|
+
|
|
6
|
+
ENV CI=true
|
|
7
|
+
|
|
8
|
+
RUN corepack enable
|
|
9
|
+
|
|
10
|
+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml nx.json tsconfig.base.json tsconfig.json eslint.config.mjs ./
|
|
11
|
+
COPY packages ./packages
|
|
12
|
+
COPY tools ./tools
|
|
13
|
+
|
|
14
|
+
RUN pnpm install --frozen-lockfile
|
|
15
|
+
RUN pnpm nx run <%= projectName %>:build
|
|
16
|
+
|
|
17
|
+
FROM node:22-bookworm-slim AS runtime
|
|
18
|
+
WORKDIR /app
|
|
19
|
+
|
|
20
|
+
ENV NODE_ENV=production
|
|
21
|
+
ENV TASK_NAME=<%= className %>Task
|
|
22
|
+
|
|
23
|
+
COPY --from=build /workspace/dist/<%= projectRoot %>/ ./
|
|
24
|
+
|
|
25
|
+
CMD ["node", "main.js"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# <%= projectTitle %>
|
|
2
|
+
|
|
3
|
+
TypeScript-first backend container task for the `<%= appName %>` app group.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This package provides a first mergeable ECS-style task slice for scheduled, queue-driven, and ad hoc operational work without forcing a broader multi-language preset decision yet.
|
|
8
|
+
|
|
9
|
+
## Nx Targets
|
|
10
|
+
|
|
11
|
+
- `pnpm nx run <%= projectName %>:build`
|
|
12
|
+
- `pnpm nx run <%= projectName %>:lint`
|
|
13
|
+
- `pnpm nx run <%= projectName %>:typecheck`
|
|
14
|
+
- `pnpm nx run <%= projectName %>:test`
|
|
15
|
+
- `pnpm nx run <%= projectName %>:dev`
|
|
16
|
+
- `pnpm nx run <%= projectName %>:docker-build`
|
|
17
|
+
|
|
18
|
+
## Current Conventions
|
|
19
|
+
|
|
20
|
+
- keep batch and worker logic in `src/`
|
|
21
|
+
- treat `src/main.ts` as the command entrypoint for local and container runs
|
|
22
|
+
- prefer structured JSON logs so ECS, EventBridge, and CloudWatch parsing stay predictable
|
|
23
|
+
- keep SST composition scaffolding in `infra/task.ts` so remote execution and local proxying use the same contract
|
|
24
|
+
- treat this package as app-group-internal until a supported SDK or API contract is published
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# <%= projectTitle %> Architecture
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
`<%= projectName %>` is the first TypeScript-first container task slice for `<%= appName %>`. It gives the app group a batch-oriented workload under `packages/<%= appName %>/apps/task` without introducing language-preset sprawl in the first milestone.
|
|
6
|
+
|
|
7
|
+
## Runtime Shape
|
|
8
|
+
|
|
9
|
+
- `src/main.ts` runs the task entrypoint and emits structured lifecycle logs
|
|
10
|
+
- `src/task.ts` keeps config, result creation, and task behavior testable
|
|
11
|
+
- `TASK_TRIGGER` provides a simple starting contract for schedule, queue, or manual execution context
|
|
12
|
+
- `infra/task.ts` captures the recommended SST `Cluster` + `Task` composition seam and `sst dev` proxy command contract
|
|
13
|
+
|
|
14
|
+
## Current Boundaries
|
|
15
|
+
|
|
16
|
+
- keep scheduled, queue-driven, and ad hoc operational work here
|
|
17
|
+
- publish cross-app contracts through the owning app group's SDK instead of importing internals directly
|
|
18
|
+
- compose this workload into the owning app group's root `infra/` entrypoint instead of letting runtime code instantiate SST resources ad hoc
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# <%= projectTitle %> Contracts
|
|
2
|
+
|
|
3
|
+
## Local Development
|
|
4
|
+
|
|
5
|
+
- `pnpm nx run <%= projectName %>:dev` is the canonical local command for this workload.
|
|
6
|
+
- `infra/task.ts` passes the same command to SST via `dev.command` so `sst dev` can proxy remote task runs back to local code.
|
|
7
|
+
- `TASK_NAME`, `TASK_VERSION`, and `TASK_TRIGGER` are the supported starter env overrides.
|
|
8
|
+
|
|
9
|
+
## Infra Composition
|
|
10
|
+
|
|
11
|
+
- import `register<%= className %>Task` from `apps/task/infra/task` into the owning app group's root `infra/` entrypoint
|
|
12
|
+
- provide an existing `sst.aws.Cluster` from app-group infrastructure instead of constructing a cluster inside runtime code
|
|
13
|
+
- pass linked SST resources through `link` so runtime code can consume them through `Resource.*`
|
|
14
|
+
- use `TASK_TRIGGER` as the starter trigger contract for local runs, EventBridge invocations, or task SDK calls
|
|
15
|
+
|
|
16
|
+
## Deployment Defaults
|
|
17
|
+
|
|
18
|
+
- image build context stays rooted at `packages/<%= appName %>/apps/task`
|
|
19
|
+
- local dev runs the same command SST uses when proxying task executions
|
|
20
|
+
- logging defaults to a one-month CloudWatch retention window until app-specific requirements are known
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# <%= projectTitle %> Operations
|
|
2
|
+
|
|
3
|
+
## Local Verification
|
|
4
|
+
|
|
5
|
+
- `pnpm nx run <%= projectName %>:build`
|
|
6
|
+
- `pnpm nx run <%= projectName %>:test`
|
|
7
|
+
- `pnpm nx run <%= projectName %>:dev`
|
|
8
|
+
- `node dist/<%= projectRoot %>/main.js`
|
|
9
|
+
|
|
10
|
+
Set `TASK_NAME`, `TASK_VERSION`, or `TASK_TRIGGER` in the environment to override the defaults exposed by the starter task.
|
|
11
|
+
|
|
12
|
+
`<%= projectName %>:dev` uses `@swc-node/register` so SST can proxy remote task invocations back to the same local command during `sst dev`.
|
|
13
|
+
|
|
14
|
+
## Container Workflow
|
|
15
|
+
|
|
16
|
+
- `pnpm nx run <%= projectName %>:docker-build`
|
|
17
|
+
- image build runs the workspace install plus `pnpm nx run <%= projectName %>:build`
|
|
18
|
+
- run the image with `docker run --rm -e TASK_TRIGGER=schedule <%= projectName %>` to exercise the starter command path
|
|
19
|
+
- `infra/task.ts` keeps the SST `Task` image path, linked-resource surface, and local proxy command aligned
|
|
20
|
+
|
|
21
|
+
## Next Steps
|
|
22
|
+
|
|
23
|
+
- replace the starter task body with app-specific batch or worker logic
|
|
24
|
+
- import `register<%= className %>Task` into the owning app group's `infra/` entrypoint when the workload is ready to deploy
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface Register<%= className %>TaskArgs {
|
|
2
|
+
cluster: sst.aws.Cluster;
|
|
3
|
+
environment?: Record<string, string>;
|
|
4
|
+
link?: any[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function register<%= className %>Task({
|
|
8
|
+
cluster,
|
|
9
|
+
environment = {},
|
|
10
|
+
link = [],
|
|
11
|
+
}: Register<%= className %>TaskArgs) {
|
|
12
|
+
const task = new sst.aws.Task('<%= projectName %>', {
|
|
13
|
+
cluster,
|
|
14
|
+
image: {
|
|
15
|
+
context: './apps/task/<%= name %>',
|
|
16
|
+
dockerfile: 'Dockerfile',
|
|
17
|
+
},
|
|
18
|
+
dev: {
|
|
19
|
+
command: 'pnpm nx run <%= projectName %>:dev',
|
|
20
|
+
directory: '../../..',
|
|
21
|
+
},
|
|
22
|
+
environment: {
|
|
23
|
+
TASK_NAME: '<%= className %>Task',
|
|
24
|
+
TASK_VERSION: '0.0.1',
|
|
25
|
+
TASK_TRIGGER: 'manual',
|
|
26
|
+
...environment,
|
|
27
|
+
},
|
|
28
|
+
link,
|
|
29
|
+
logging: {
|
|
30
|
+
retention: '1 month',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return { task };
|
|
35
|
+
}
|