create-asaje-go-vue 0.3.1 → 0.3.3
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 +23 -11
- package/bin/create-asaje-go-vue.js +130 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,15 @@ npx -p create-asaje-go-vue@latest asaje setup-railway ./my-app --dry-run
|
|
|
82
82
|
npx -p create-asaje-go-vue@latest asaje update-railway ./my-app --yes
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
By default this manages four Railway app services:
|
|
86
|
+
|
|
87
|
+
- `api`
|
|
88
|
+
- `worker`
|
|
89
|
+
- `realtime-gateway`
|
|
90
|
+
- `admin`
|
|
91
|
+
|
|
92
|
+
The default `worker` service reuses `api/Dockerfile` and starts with `API_COMMAND=worker`.
|
|
93
|
+
|
|
85
94
|
### Sync Railway app variables
|
|
86
95
|
|
|
87
96
|
```bash
|
|
@@ -127,6 +136,7 @@ npx -p create-asaje-go-vue@latest asaje diff-railway-config ./my-app --file ./sn
|
|
|
127
136
|
|
|
128
137
|
```bash
|
|
129
138
|
npx -p create-asaje-go-vue@latest asaje deploy-railway ./my-app
|
|
139
|
+
npx -p create-asaje-go-vue@latest asaje deploy-railway ./my-app --service worker
|
|
130
140
|
npx -p create-asaje-go-vue@latest asaje deploy-railway ./my-app --service api
|
|
131
141
|
npx -p create-asaje-go-vue@latest asaje deploy-railway ./my-app --services api,admin --dry-run
|
|
132
142
|
```
|
|
@@ -195,9 +205,9 @@ npx -p create-asaje-go-vue@latest asaje destroy-railway ./my-app --scope project
|
|
|
195
205
|
- reads the linked Railway project context
|
|
196
206
|
- provisions PostgreSQL, RabbitMQ, and S3-compatible object storage on Railway
|
|
197
207
|
- creates missing Railway app services for the configured app service list
|
|
198
|
-
- defaults to `api`, `realtime-gateway`, and `admin` when no custom Railway service config is present
|
|
208
|
+
- defaults to `api`, `worker`, `realtime-gateway`, and `admin` when no custom Railway service config is present
|
|
199
209
|
- applies Railway variables from `asaje.config.json` when configured
|
|
200
|
-
- keeps the legacy automatic variable wiring for `api`, `realtime-gateway`, and `admin` unless `railway.variablesMode` is set to `replace`
|
|
210
|
+
- keeps the legacy automatic variable wiring for `api`, `worker`, `realtime-gateway`, and `admin` unless `railway.variablesMode` is set to `replace`
|
|
201
211
|
- triggers the first Railway deployment for each app service using the service-local `Dockerfile` and `railway.json`
|
|
202
212
|
- generates missing app secrets such as `JWT_SECRET` and `SWAGGER_PASSWORD`, while reusing existing Railway values when present
|
|
203
213
|
- supports `--dry-run` to preview provisioning and variable changes without applying them
|
|
@@ -218,7 +228,7 @@ npx -p create-asaje-go-vue@latest asaje destroy-railway ./my-app --scope project
|
|
|
218
228
|
- reads the linked Railway project context
|
|
219
229
|
- discovers existing Railway app and infra services
|
|
220
230
|
- syncs configured Railway variables without provisioning infra resources
|
|
221
|
-
- keeps the legacy automatic variable wiring for `api`, `realtime-gateway`, and `admin` unless `railway.variablesMode` is set to `replace`
|
|
231
|
+
- keeps the legacy automatic variable wiring for `api`, `worker`, `realtime-gateway`, and `admin` unless `railway.variablesMode` is set to `replace`
|
|
222
232
|
- supports `--diff` to show what would be added or changed compared with the current Railway variables
|
|
223
233
|
- supports `--dry-run` to preview variable changes without applying them
|
|
224
234
|
|
|
@@ -263,7 +273,7 @@ npx -p create-asaje-go-vue@latest asaje destroy-railway ./my-app --scope project
|
|
|
263
273
|
- reads the linked Railway project context
|
|
264
274
|
- discovers the existing Railway app services from the linked project or `asaje.railway.json`
|
|
265
275
|
- triggers fresh Railway builds/deployments for the configured app service list from the current local source tree
|
|
266
|
-
- defaults to `api`, `realtime-gateway`, and `admin` when no custom Railway service config is present
|
|
276
|
+
- defaults to `api`, `worker`, `realtime-gateway`, and `admin` when no custom Railway service config is present
|
|
267
277
|
- supports `--service` and `--services` to redeploy only selected app services
|
|
268
278
|
- supports `--dry-run` to preview which services would be redeployed
|
|
269
279
|
|
|
@@ -285,6 +295,13 @@ If the `railway` block is omitted, the CLI keeps the default built-in services a
|
|
|
285
295
|
"directory": "api",
|
|
286
296
|
"dockerfile": "api/Dockerfile"
|
|
287
297
|
},
|
|
298
|
+
{
|
|
299
|
+
"key": "worker",
|
|
300
|
+
"directory": "api",
|
|
301
|
+
"baseName": "worker",
|
|
302
|
+
"aliases": ["worker", "api-worker"],
|
|
303
|
+
"dockerfile": "api/Dockerfile"
|
|
304
|
+
},
|
|
288
305
|
{
|
|
289
306
|
"key": "admin",
|
|
290
307
|
"directory": "admin",
|
|
@@ -297,12 +314,6 @@ If the `railway` block is omitted, the CLI keeps the default built-in services a
|
|
|
297
314
|
"aliases": ["realtime-gateway"],
|
|
298
315
|
"dockerfile": "realtime-gateway/Dockerfile"
|
|
299
316
|
},
|
|
300
|
-
{
|
|
301
|
-
"key": "worker",
|
|
302
|
-
"directory": "worker-api",
|
|
303
|
-
"baseName": "worker",
|
|
304
|
-
"dockerfile": "worker-api/Dockerfile"
|
|
305
|
-
},
|
|
306
317
|
{
|
|
307
318
|
"key": "marketing",
|
|
308
319
|
"directory": "marketing",
|
|
@@ -403,7 +414,8 @@ Notes:
|
|
|
403
414
|
- the service directory should contain the `Dockerfile` Railway will build from
|
|
404
415
|
- custom services are provisioned and deployed by `setup-railway` and `deploy-railway`
|
|
405
416
|
- `sync-railway-env` can now apply declarative variables to any managed service key, including custom services
|
|
406
|
-
- with `variablesMode: "merge"`, the core services `api`, `realtime-gateway`, and `admin` still receive the legacy generated defaults unless you override them
|
|
417
|
+
- with `variablesMode: "merge"`, the core services `api`, `worker`, `realtime-gateway`, and `admin` still receive the legacy generated defaults unless you override them
|
|
418
|
+
- the default `worker` service reuses the `api` image and starts with `API_COMMAND=worker`
|
|
407
419
|
- with `variablesMode: "replace"`, only the variables declared in `asaje.config.json` are applied
|
|
408
420
|
- after changing the Railway config, run `asaje update-railway ./my-app --yes` to reconcile the linked Railway project with the new configuration
|
|
409
421
|
- you can target a custom service with `asaje deploy-railway ./my-app --service worker`
|
|
@@ -34,6 +34,12 @@ const DEFAULT_RAILWAY_APP_SERVICE_SPECS = [
|
|
|
34
34
|
directory: "api",
|
|
35
35
|
key: "api",
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
aliases: ["worker", "api-worker"],
|
|
39
|
+
baseName: "worker",
|
|
40
|
+
directory: "api",
|
|
41
|
+
key: "worker",
|
|
42
|
+
},
|
|
37
43
|
{
|
|
38
44
|
aliases: ["admin", "frontend", "web"],
|
|
39
45
|
baseName: "admin",
|
|
@@ -1258,10 +1264,11 @@ async function runSetupRailway(argv) {
|
|
|
1258
1264
|
const projectConfig = await loadProjectConfig(projectDir);
|
|
1259
1265
|
const projectSlug = resolveProjectSlug(projectDir, projectConfig);
|
|
1260
1266
|
const appServiceSpecs = resolveRailwayAppServiceSpecs(projectConfig);
|
|
1267
|
+
const selectedSpecs = resolveDeployRailwaySpecs(answers.services, appServiceSpecs);
|
|
1261
1268
|
const requestedRailwayEnvironment = resolveRequestedRailwayEnvironmentRef(projectConfig, answers.environment);
|
|
1262
1269
|
|
|
1263
1270
|
await ensureProjectStructure(projectDir);
|
|
1264
|
-
await ensureRailwayAppServiceTargets(projectDir,
|
|
1271
|
+
await ensureRailwayAppServiceTargets(projectDir, selectedSpecs);
|
|
1265
1272
|
await ensureRailwayCliInstalled();
|
|
1266
1273
|
await ensureRailwayAuthenticated(projectDir, requestedRailwayEnvironment);
|
|
1267
1274
|
await ensureRailwayEnvironmentLinked(projectDir, requestedRailwayEnvironment);
|
|
@@ -1337,7 +1344,7 @@ async function runSetupRailway(argv) {
|
|
|
1337
1344
|
|
|
1338
1345
|
console.log(pc.bold("\nApplication services"));
|
|
1339
1346
|
manifest.appServices ||= {};
|
|
1340
|
-
for (const spec of
|
|
1347
|
+
for (const spec of selectedSpecs) {
|
|
1341
1348
|
const serviceName = resolveRailwayServiceName(spec, projectSlug);
|
|
1342
1349
|
const serviceResult = await ensureRailwayAppService({
|
|
1343
1350
|
aliases: spec.aliases,
|
|
@@ -1382,7 +1389,7 @@ async function runSetupRailway(argv) {
|
|
|
1382
1389
|
projectDir,
|
|
1383
1390
|
projectSlug,
|
|
1384
1391
|
railwayContext,
|
|
1385
|
-
selectedSpecs
|
|
1392
|
+
selectedSpecs,
|
|
1386
1393
|
services: servicesAfterProvision,
|
|
1387
1394
|
});
|
|
1388
1395
|
deploySummary.push(...deploymentResults);
|
|
@@ -1752,10 +1759,12 @@ function parseDirectoryArgs(argv) {
|
|
|
1752
1759
|
function parseSetupRailwayArgs(argv) {
|
|
1753
1760
|
const options = {
|
|
1754
1761
|
bucket: DEFAULT_RAILWAY_BUCKET,
|
|
1762
|
+
bucketProvided: false,
|
|
1755
1763
|
directory: ".",
|
|
1756
1764
|
diff: false,
|
|
1757
1765
|
dryRun: false,
|
|
1758
1766
|
environment: undefined,
|
|
1767
|
+
services: [],
|
|
1759
1768
|
yes: false,
|
|
1760
1769
|
};
|
|
1761
1770
|
const positionals = [];
|
|
@@ -1780,12 +1789,14 @@ function parseSetupRailwayArgs(argv) {
|
|
|
1780
1789
|
|
|
1781
1790
|
if (arg === "--bucket") {
|
|
1782
1791
|
options.bucket = argv[index + 1] || options.bucket;
|
|
1792
|
+
options.bucketProvided = true;
|
|
1783
1793
|
index += 1;
|
|
1784
1794
|
continue;
|
|
1785
1795
|
}
|
|
1786
1796
|
|
|
1787
1797
|
if (arg.startsWith("--bucket=")) {
|
|
1788
1798
|
options.bucket = arg.split("=")[1] || options.bucket;
|
|
1799
|
+
options.bucketProvided = true;
|
|
1789
1800
|
continue;
|
|
1790
1801
|
}
|
|
1791
1802
|
|
|
@@ -1800,10 +1811,33 @@ function parseSetupRailwayArgs(argv) {
|
|
|
1800
1811
|
continue;
|
|
1801
1812
|
}
|
|
1802
1813
|
|
|
1814
|
+
if (arg === "--service") {
|
|
1815
|
+
options.services.push(argv[index + 1] || "");
|
|
1816
|
+
index += 1;
|
|
1817
|
+
continue;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
if (arg.startsWith("--service=")) {
|
|
1821
|
+
options.services.push(arg.split("=")[1] || "");
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
if (arg === "--services") {
|
|
1826
|
+
options.services.push(...splitCsv(argv[index + 1] || ""));
|
|
1827
|
+
index += 1;
|
|
1828
|
+
continue;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
if (arg.startsWith("--services=")) {
|
|
1832
|
+
options.services.push(...splitCsv(arg.split("=")[1] || ""));
|
|
1833
|
+
continue;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1803
1836
|
positionals.push(arg);
|
|
1804
1837
|
}
|
|
1805
1838
|
|
|
1806
1839
|
options.directory = positionals[0] || options.directory;
|
|
1840
|
+
options.services = [...new Set(options.services.map((service) => service.trim()).filter(Boolean))];
|
|
1807
1841
|
return options;
|
|
1808
1842
|
}
|
|
1809
1843
|
|
|
@@ -2194,19 +2228,23 @@ function parseDestroyRailwayArgs(argv) {
|
|
|
2194
2228
|
}
|
|
2195
2229
|
|
|
2196
2230
|
async function collectSetupRailwayAnswers(args) {
|
|
2231
|
+
const directory = args.directory;
|
|
2232
|
+
const bucketState = await resolveSetupRailwayBucketState(args, directory);
|
|
2233
|
+
|
|
2197
2234
|
if (args.yes) {
|
|
2198
2235
|
return {
|
|
2199
|
-
bucket:
|
|
2200
|
-
directory
|
|
2236
|
+
bucket: bucketState.bucket,
|
|
2237
|
+
directory,
|
|
2201
2238
|
diff: args.diff,
|
|
2202
2239
|
dryRun: args.dryRun,
|
|
2203
2240
|
environment: args.environment,
|
|
2241
|
+
services: args.services,
|
|
2204
2242
|
};
|
|
2205
2243
|
}
|
|
2206
2244
|
|
|
2207
|
-
const
|
|
2245
|
+
const selectedDirectory = await prompt(
|
|
2208
2246
|
text({
|
|
2209
|
-
defaultValue:
|
|
2247
|
+
defaultValue: directory,
|
|
2210
2248
|
message: "Project directory to configure on Railway?",
|
|
2211
2249
|
placeholder: ".",
|
|
2212
2250
|
validate(value) {
|
|
@@ -2215,18 +2253,23 @@ async function collectSetupRailwayAnswers(args) {
|
|
|
2215
2253
|
}),
|
|
2216
2254
|
);
|
|
2217
2255
|
|
|
2218
|
-
const
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2256
|
+
const selectedBucketState = await resolveSetupRailwayBucketState(args, selectedDirectory);
|
|
2257
|
+
let bucket = selectedBucketState.bucket;
|
|
2258
|
+
|
|
2259
|
+
if (!args.bucketProvided && !selectedBucketState.hasStoredBucket) {
|
|
2260
|
+
bucket = await prompt(
|
|
2261
|
+
text({
|
|
2262
|
+
defaultValue: selectedBucketState.bucket,
|
|
2263
|
+
message: "Object storage bucket name?",
|
|
2264
|
+
placeholder: DEFAULT_RAILWAY_BUCKET,
|
|
2265
|
+
validate(value) {
|
|
2266
|
+
return /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(value)
|
|
2267
|
+
? undefined
|
|
2268
|
+
: "Use 3-63 lowercase letters, numbers, dots, or hyphens";
|
|
2269
|
+
},
|
|
2270
|
+
}),
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2230
2273
|
|
|
2231
2274
|
let environment = args.environment;
|
|
2232
2275
|
if (!environment) {
|
|
@@ -2241,10 +2284,28 @@ async function collectSetupRailwayAnswers(args) {
|
|
|
2241
2284
|
|
|
2242
2285
|
return {
|
|
2243
2286
|
bucket,
|
|
2244
|
-
directory,
|
|
2287
|
+
directory: selectedDirectory,
|
|
2245
2288
|
diff: args.diff,
|
|
2246
2289
|
dryRun: args.dryRun,
|
|
2247
2290
|
environment: environment?.trim() || undefined,
|
|
2291
|
+
services: args.services,
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
async function resolveSetupRailwayBucketState(args, directory) {
|
|
2296
|
+
if (args.bucketProvided) {
|
|
2297
|
+
return {
|
|
2298
|
+
bucket: args.bucket,
|
|
2299
|
+
hasStoredBucket: true,
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
const projectDir = path.resolve(process.cwd(), directory || ".");
|
|
2304
|
+
const manifest = await readRailwayManifest(projectDir);
|
|
2305
|
+
const existingBucket = typeof manifest.bucket === "string" ? manifest.bucket.trim() : "";
|
|
2306
|
+
return {
|
|
2307
|
+
bucket: existingBucket || DEFAULT_RAILWAY_BUCKET,
|
|
2308
|
+
hasStoredBucket: Boolean(existingBucket),
|
|
2248
2309
|
};
|
|
2249
2310
|
}
|
|
2250
2311
|
|
|
@@ -3070,6 +3131,7 @@ async function resolveRailwayVariablePlan(config) {
|
|
|
3070
3131
|
admin: findRailwayServiceByKey(config.services, config.appServiceSpecs, config.manifest, "admin"),
|
|
3071
3132
|
api: findRailwayServiceByKey(config.services, config.appServiceSpecs, config.manifest, "api"),
|
|
3072
3133
|
realtime: findRailwayServiceByKey(config.services, config.appServiceSpecs, config.manifest, "realtime"),
|
|
3134
|
+
worker: findRailwayServiceByKey(config.services, config.appServiceSpecs, config.manifest, "worker"),
|
|
3073
3135
|
};
|
|
3074
3136
|
|
|
3075
3137
|
const serviceRegistry = {
|
|
@@ -3079,6 +3141,7 @@ async function resolveRailwayVariablePlan(config) {
|
|
|
3079
3141
|
postgres: infra.postgres ? { name: infra.postgres.name, variables: {} } : null,
|
|
3080
3142
|
rabbitmq: infra.rabbitmq ? { name: infra.rabbitmq.name, variables: {} } : null,
|
|
3081
3143
|
realtime: appServices.realtime ? { name: appServices.realtime.name, variables: {} } : null,
|
|
3144
|
+
worker: appServices.worker ? { name: appServices.worker.name, variables: {} } : null,
|
|
3082
3145
|
};
|
|
3083
3146
|
|
|
3084
3147
|
for (const spec of config.appServiceSpecs) {
|
|
@@ -3109,6 +3172,9 @@ async function resolveRailwayVariablePlan(config) {
|
|
|
3109
3172
|
if (!appServices.admin) {
|
|
3110
3173
|
notices.push("admin service not found, skipping admin variable wiring");
|
|
3111
3174
|
}
|
|
3175
|
+
if (!appServices.worker) {
|
|
3176
|
+
notices.push("worker service not found, skipping worker variable wiring");
|
|
3177
|
+
}
|
|
3112
3178
|
if (!infra.postgres) {
|
|
3113
3179
|
notices.push("postgres resource not found, DATABASE_URL wiring will be skipped");
|
|
3114
3180
|
}
|
|
@@ -3170,6 +3236,26 @@ async function resolveRailwayVariablePlan(config) {
|
|
|
3170
3236
|
mergeRailwayServiceVariables(serviceRegistry.admin, variables);
|
|
3171
3237
|
}
|
|
3172
3238
|
|
|
3239
|
+
if (variablesMode !== "replace" && appServices.worker) {
|
|
3240
|
+
const existingApiVariables = appServices.api?.name
|
|
3241
|
+
? await loadRailwayServiceVariables(config.projectDir, config.railwayContext.environmentRef, appServices.api.name)
|
|
3242
|
+
: {};
|
|
3243
|
+
const variables = {};
|
|
3244
|
+
const sharedSecrets = buildRailwaySharedSecrets(localEnv, existingApiVariables);
|
|
3245
|
+
Object.assign(variables, sharedSecrets.api);
|
|
3246
|
+
variables.API_COMMAND = "worker";
|
|
3247
|
+
if (infra.postgres?.name) {
|
|
3248
|
+
variables.DATABASE_URL = railwayReference(infra.postgres.name, "DATABASE_URL");
|
|
3249
|
+
}
|
|
3250
|
+
if (infra.rabbitmq?.name) {
|
|
3251
|
+
variables.RABBITMQ_URL = buildRabbitMqUrlReference(infra.rabbitmq.name);
|
|
3252
|
+
}
|
|
3253
|
+
if (infra.objectStorage?.name) {
|
|
3254
|
+
Object.assign(variables, buildObjectStorageVariables(infra.objectStorage.name));
|
|
3255
|
+
}
|
|
3256
|
+
mergeRailwayServiceVariables(serviceRegistry.worker, variables);
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3173
3259
|
if (declaredVariables.hasDeclaredVariables) {
|
|
3174
3260
|
if (Object.keys(declaredVariables.sharedVariables).length > 0) {
|
|
3175
3261
|
for (const entry of Object.values(serviceRegistry)) {
|
|
@@ -3909,6 +3995,7 @@ function printRailwaySetupSummary(config) {
|
|
|
3909
3995
|
if (config.railwayContext.environmentName || config.railwayContext.environmentId) {
|
|
3910
3996
|
console.log(`- Environment: ${pc.bold(config.railwayContext.environmentName || config.railwayContext.environmentId)}`);
|
|
3911
3997
|
}
|
|
3998
|
+
console.log(`- Managed services: ${pc.bold("api, worker, realtime-gateway, admin")}`);
|
|
3912
3999
|
console.log(`- Bucket: ${pc.bold(config.bucket)}`);
|
|
3913
4000
|
|
|
3914
4001
|
console.log(pc.bold("\nResources"));
|
|
@@ -3969,6 +4056,7 @@ function printRailwayDeploySummary(config) {
|
|
|
3969
4056
|
if (config.railwayContext.environmentName || config.railwayContext.environmentId) {
|
|
3970
4057
|
console.log(`- Environment: ${pc.bold(config.railwayContext.environmentName || config.railwayContext.environmentId)}`);
|
|
3971
4058
|
}
|
|
4059
|
+
console.log(`- Default managed services: ${pc.bold("api, worker, realtime-gateway, admin")}`);
|
|
3972
4060
|
console.log(`- Services: ${pc.bold(config.selectedServices.join(", "))}`);
|
|
3973
4061
|
|
|
3974
4062
|
console.log(pc.bold("\nDeployments"));
|
|
@@ -4244,17 +4332,38 @@ async function scanProjectForManagedRailwayServices(projectDir) {
|
|
|
4244
4332
|
const dockerfiles = [];
|
|
4245
4333
|
await collectDockerfiles(projectDir, "", dockerfiles);
|
|
4246
4334
|
|
|
4247
|
-
const
|
|
4335
|
+
const scannedSpecs = dockerfiles
|
|
4248
4336
|
.map((dockerfilePath) => buildScannedRailwayServiceSpec(projectDir, dockerfilePath))
|
|
4249
4337
|
.filter(Boolean)
|
|
4250
4338
|
.sort((left, right) => left.directory.localeCompare(right.directory));
|
|
4251
4339
|
|
|
4340
|
+
const serviceSpecs = synthesizeDerivedRailwayServices(scannedSpecs);
|
|
4341
|
+
|
|
4252
4342
|
return {
|
|
4253
4343
|
dockerfiles,
|
|
4254
4344
|
serviceSpecs,
|
|
4255
4345
|
};
|
|
4256
4346
|
}
|
|
4257
4347
|
|
|
4348
|
+
function synthesizeDerivedRailwayServices(serviceSpecs) {
|
|
4349
|
+
const nextSpecs = [...serviceSpecs];
|
|
4350
|
+
const hasAPI = serviceSpecs.some((spec) => spec.key === "api" && spec.directory === "api");
|
|
4351
|
+
const hasWorker = serviceSpecs.some((spec) => spec.key === "worker");
|
|
4352
|
+
if (hasAPI && !hasWorker) {
|
|
4353
|
+
nextSpecs.push({
|
|
4354
|
+
aliases: ["worker", "api-worker"],
|
|
4355
|
+
baseName: "worker",
|
|
4356
|
+
directory: "api",
|
|
4357
|
+
dockerfile: "api/Dockerfile",
|
|
4358
|
+
key: "worker",
|
|
4359
|
+
seedImage: "alpine:3.22",
|
|
4360
|
+
serviceName: null,
|
|
4361
|
+
});
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
return nextSpecs.sort((left, right) => `${left.directory}:${left.key}`.localeCompare(`${right.directory}:${right.key}`));
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4258
4367
|
async function collectDockerfiles(projectDir, relativeDir, results) {
|
|
4259
4368
|
const absoluteDir = path.join(projectDir, relativeDir);
|
|
4260
4369
|
const entries = await fs.readdir(absoluteDir, { withFileTypes: true });
|