create-forgeon 0.3.12 → 0.3.15
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/package.json +1 -1
- package/src/modules/dependencies.test.mjs +1 -1
- package/src/modules/executor.mjs +1 -1
- package/src/modules/executor.test.mjs +2479 -2419
- package/src/modules/queue.mjs +69 -38
- package/src/modules/registry.mjs +1 -1
- package/src/modules/scheduler.mjs +1 -1
- package/src/run-add-module.mjs +4 -3
- package/src/utils/fs.mjs +31 -26
- package/templates/module-fragments/scheduler/20_scope.md +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/package.json +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/forgeon-scheduler.module.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/index.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/scheduler-config.loader.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/scheduler-config.module.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/scheduler-config.service.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/scheduler-env.schema.ts +1 -1
- package/templates/module-presets/scheduler/packages/scheduler/src/scheduler.service.ts +1 -1
package/src/modules/queue.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { copyRecursive, writeJson } from '../utils/fs.mjs';
|
|
4
4
|
import {
|
|
@@ -240,14 +240,77 @@ function patchApiDockerfile(targetRoot) {
|
|
|
240
240
|
content = ensureLineAfter(content, sourceAnchor, 'COPY packages/queue packages/queue');
|
|
241
241
|
|
|
242
242
|
content = content.replace(/^RUN pnpm --filter @forgeon\/queue build\r?\n?/gm, '');
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
const buildAnchors = [
|
|
244
|
+
'RUN pnpm --filter @forgeon/scheduler build',
|
|
245
|
+
'RUN pnpm --filter @forgeon/api prisma:generate',
|
|
246
|
+
'RUN pnpm --filter @forgeon/api build',
|
|
247
|
+
];
|
|
248
|
+
const buildAnchor = buildAnchors.find((line) => content.includes(line)) ?? 'RUN pnpm --filter @forgeon/api build';
|
|
246
249
|
content = ensureLineBefore(content, buildAnchor, 'RUN pnpm --filter @forgeon/queue build');
|
|
247
250
|
|
|
248
251
|
fs.writeFileSync(dockerfilePath, `${content.trimEnd()}\n`, 'utf8');
|
|
249
252
|
}
|
|
250
253
|
|
|
254
|
+
function ensureApiDependsOnRedis(apiBlock) {
|
|
255
|
+
let lines = apiBlock.replace(/\n$/, '').split('\n');
|
|
256
|
+
const buildIndex = lines.findIndex((line) => line === ' build:');
|
|
257
|
+
|
|
258
|
+
// Heal a previously broken queue patch where depends_on was injected inside the build block.
|
|
259
|
+
if (buildIndex >= 0 && lines[buildIndex + 1] === ' depends_on:') {
|
|
260
|
+
let malformedBlockEnd = lines.length;
|
|
261
|
+
for (let index = buildIndex + 2; index < lines.length; index += 1) {
|
|
262
|
+
if (lines[index].startsWith(' ') && !lines[index].startsWith(' ')) {
|
|
263
|
+
malformedBlockEnd = index;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const misplacedBuildLines = lines
|
|
269
|
+
.slice(buildIndex + 2, malformedBlockEnd)
|
|
270
|
+
.filter((line) => /^( context:| dockerfile:| args:| target:)/.test(line));
|
|
271
|
+
|
|
272
|
+
if (misplacedBuildLines.length > 0) {
|
|
273
|
+
lines = [
|
|
274
|
+
...lines.slice(0, buildIndex + 1),
|
|
275
|
+
...misplacedBuildLines,
|
|
276
|
+
...lines.slice(malformedBlockEnd),
|
|
277
|
+
];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const dependsOnIndex = lines.findIndex((line) => line === ' depends_on:');
|
|
282
|
+
|
|
283
|
+
if (dependsOnIndex < 0) {
|
|
284
|
+
const restartIndex = lines.findIndex((line) => line === ' restart: unless-stopped');
|
|
285
|
+
const environmentIndex = lines.findIndex((line) => line === ' environment:');
|
|
286
|
+
const insertAt = restartIndex >= 0 ? restartIndex + 1 : environmentIndex >= 0 ? environmentIndex : lines.length;
|
|
287
|
+
lines.splice(insertAt, 0, ' depends_on:', ' redis:', ' condition: service_healthy');
|
|
288
|
+
return `${lines.join('\n')}\n`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
let blockEnd = lines.length;
|
|
292
|
+
for (let index = dependsOnIndex + 1; index < lines.length; index += 1) {
|
|
293
|
+
if (lines[index].startsWith(' ') && !lines[index].startsWith(' ')) {
|
|
294
|
+
blockEnd = index;
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const dependsOnBlock = lines.slice(dependsOnIndex + 1, blockEnd);
|
|
300
|
+
const hasRedisMapping = dependsOnBlock.includes(' redis:');
|
|
301
|
+
const hasRedisList = dependsOnBlock.some((line) => line.trim() === '- redis');
|
|
302
|
+
if (hasRedisMapping || hasRedisList) {
|
|
303
|
+
return `${lines.join('\n')}\n`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const isListStyle = dependsOnBlock.some((line) => line.trimStart().startsWith('- '));
|
|
307
|
+
const insertLines = isListStyle
|
|
308
|
+
? [' - redis']
|
|
309
|
+
: [' redis:', ' condition: service_healthy'];
|
|
310
|
+
|
|
311
|
+
lines.splice(blockEnd, 0, ...insertLines);
|
|
312
|
+
return `${lines.join('\n')}\n`;
|
|
313
|
+
}
|
|
251
314
|
function patchCompose(targetRoot) {
|
|
252
315
|
const composePath = path.join(targetRoot, 'infra', 'docker', 'compose.yml');
|
|
253
316
|
if (!fs.existsSync(composePath)) {
|
|
@@ -300,45 +363,14 @@ function patchCompose(targetRoot) {
|
|
|
300
363
|
);
|
|
301
364
|
}
|
|
302
365
|
|
|
303
|
-
const apiBlockMatch = content.match(/^ api:\n[\s\S]*?(?=^ [a-zA-Z0-9_-]+:\n|^volumes:\n
|
|
366
|
+
const apiBlockMatch = content.match(/^ api:\n[\s\S]*?(?=^ [a-zA-Z0-9_-]+:\n|^volumes:\n|(?![\s\S]))/m);
|
|
304
367
|
if (apiBlockMatch) {
|
|
305
|
-
|
|
306
|
-
if (!/^\s{6}redis:\s*$/m.test(apiBlock) && !/^\s{6}-\s*redis\s*$/m.test(apiBlock)) {
|
|
307
|
-
if (/^\s{4}depends_on:\s*$/m.test(apiBlock)) {
|
|
308
|
-
if (/^\s{6}-\s+/m.test(apiBlock)) {
|
|
309
|
-
apiBlock = apiBlock.replace(
|
|
310
|
-
/^(\s{4}depends_on:\n(?:\s{6}-\s+.+\n)+)/m,
|
|
311
|
-
`$1 - redis
|
|
312
|
-
`,
|
|
313
|
-
);
|
|
314
|
-
} else {
|
|
315
|
-
apiBlock = apiBlock.replace(
|
|
316
|
-
/^(\s{4}depends_on:\n)/m,
|
|
317
|
-
`$1 redis:
|
|
318
|
-
condition: service_healthy
|
|
319
|
-
`,
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
} else {
|
|
323
|
-
const withDependsOn = apiBlock.replace(
|
|
324
|
-
/^(\s{4}environment:\n(?:\s{6}.+\n)+)/m,
|
|
325
|
-
`$1 depends_on:
|
|
326
|
-
redis:
|
|
327
|
-
condition: service_healthy
|
|
328
|
-
`,
|
|
329
|
-
);
|
|
330
|
-
apiBlock =
|
|
331
|
-
withDependsOn === apiBlock
|
|
332
|
-
? `${apiBlock.trimEnd()}\n depends_on:\n redis:\n condition: service_healthy\n`
|
|
333
|
-
: withDependsOn;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
368
|
+
const apiBlock = ensureApiDependsOnRedis(apiBlockMatch[0]);
|
|
336
369
|
content = content.replace(apiBlockMatch[0], apiBlock);
|
|
337
370
|
}
|
|
338
371
|
|
|
339
372
|
fs.writeFileSync(composePath, `${content.trimEnd()}\n`, 'utf8');
|
|
340
373
|
}
|
|
341
|
-
|
|
342
374
|
function patchReadme(targetRoot) {
|
|
343
375
|
const readmePath = path.join(targetRoot, 'README.md');
|
|
344
376
|
if (!fs.existsSync(readmePath)) {
|
|
@@ -409,4 +441,3 @@ export function applyQueueModule({ packageRoot, targetRoot }) {
|
|
|
409
441
|
'QUEUE_DEFAULT_BACKOFF_MS=1000',
|
|
410
442
|
]);
|
|
411
443
|
}
|
|
412
|
-
|
package/src/modules/registry.mjs
CHANGED
package/src/run-add-module.mjs
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
printOptionalIntegrationsWarning,
|
|
17
17
|
runIntegrationFlow,
|
|
18
18
|
} from './integrations/flow.mjs';
|
|
19
|
-
import { writeJson } from './utils/fs.mjs';
|
|
19
|
+
import { readJson, writeJson } from './utils/fs.mjs';
|
|
20
20
|
|
|
21
21
|
function printModuleList() {
|
|
22
22
|
const modules = listModulePresets();
|
|
@@ -63,7 +63,7 @@ function collectDependencyManifestState(targetRoot) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const filePath = path.join(currentDir, entry.name);
|
|
66
|
-
const packageJson =
|
|
66
|
+
const packageJson = readJson(filePath);
|
|
67
67
|
const snapshot = {
|
|
68
68
|
name: packageJson.name ?? null,
|
|
69
69
|
dependencies: toSortedObject(packageJson.dependencies),
|
|
@@ -114,7 +114,7 @@ function ensureSyncTooling({ packageRoot, targetRoot }) {
|
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
const packageJson =
|
|
117
|
+
const packageJson = readJson(packagePath);
|
|
118
118
|
if (!packageJson.scripts) {
|
|
119
119
|
packageJson.scripts = {};
|
|
120
120
|
}
|
|
@@ -309,3 +309,4 @@ export async function runAddModule(argv = process.argv.slice(2)) {
|
|
|
309
309
|
console.log('Next: run pnpm install');
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
|
+
|
package/src/utils/fs.mjs
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
export function copyRecursive(source, destination) {
|
|
5
|
-
const stat = fs.statSync(source);
|
|
6
|
-
|
|
7
|
-
if (stat.isDirectory()) {
|
|
8
|
-
fs.mkdirSync(destination, { recursive: true });
|
|
9
|
-
for (const entry of fs.readdirSync(source)) {
|
|
10
|
-
copyRecursive(path.join(source, entry), path.join(destination, entry));
|
|
11
|
-
}
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
fs.copyFileSync(source, destination);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function writeJson(filePath, data) {
|
|
19
|
-
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export function copyRecursive(source, destination) {
|
|
5
|
+
const stat = fs.statSync(source);
|
|
6
|
+
|
|
7
|
+
if (stat.isDirectory()) {
|
|
8
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
9
|
+
for (const entry of fs.readdirSync(source)) {
|
|
10
|
+
copyRecursive(path.join(source, entry), path.join(destination, entry));
|
|
11
|
+
}
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fs.copyFileSync(source, destination);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function writeJson(filePath, data) {
|
|
19
|
+
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function readJson(filePath) {
|
|
23
|
+
const raw = fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '');
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function removeIfExists(targetPath) {
|
|
28
|
+
if (fs.existsSync(targetPath)) {
|
|
29
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { SchedulerRegistry } from '@nestjs/schedule';
|
|
3
3
|
import { QueueService } from '@forgeon/queue';
|
|
4
4
|
import { CronJob } from 'cron';
|