create-forgeon 0.3.20 → 0.3.21
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/executor.test.mjs +550 -550
- package/src/modules/files-access.mjs +375 -375
- package/src/modules/files-image.mjs +512 -512
- package/src/modules/files-quotas.mjs +365 -365
- package/src/run-add-module.test.mjs +228 -228
- package/templates/module-presets/files-quotas/packages/files-quotas/package.json +20 -20
- package/templates/module-presets/files-quotas/packages/files-quotas/src/files-quotas.service.ts +118 -118
- package/templates/module-presets/files-quotas/packages/files-quotas/src/forgeon-files-quotas.module.ts +18 -18
|
@@ -1,230 +1,230 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { scaffoldProject } from './core/scaffold.mjs';
|
|
8
|
-
import { runAddModule } from './run-add-module.mjs';
|
|
9
|
-
|
|
10
|
-
function makeTempDir(prefix) {
|
|
11
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function readFile(filePath) {
|
|
15
|
-
return fs.readFileSync(filePath, 'utf8');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function writeJson(filePath, value) {
|
|
19
|
-
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function scaffoldBaseProject({ packageRoot, targetRoot, projectName, proxy }) {
|
|
23
|
-
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
24
|
-
scaffoldProject({
|
|
25
|
-
templateRoot,
|
|
26
|
-
packageRoot,
|
|
27
|
-
targetRoot,
|
|
28
|
-
projectName,
|
|
29
|
-
frontend: 'react',
|
|
30
|
-
db: 'prisma',
|
|
31
|
-
dbPrismaEnabled: false,
|
|
32
|
-
i18nEnabled: false,
|
|
33
|
-
proxy,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function stripSyncTooling(targetRoot) {
|
|
38
|
-
const packagePath = path.join(targetRoot, 'package.json');
|
|
39
|
-
const packageJson = JSON.parse(readFile(packagePath));
|
|
40
|
-
if (packageJson.scripts) {
|
|
41
|
-
delete packageJson.scripts['forgeon:sync-integrations'];
|
|
42
|
-
}
|
|
43
|
-
writeJson(packagePath, packageJson);
|
|
44
|
-
|
|
45
|
-
fs.rmSync(path.join(targetRoot, 'scripts', 'forgeon-sync-integrations.mjs'), { force: true });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function captureLogs(work) {
|
|
49
|
-
const lines = [];
|
|
50
|
-
const originalLog = console.log;
|
|
51
|
-
console.log = (...args) => {
|
|
52
|
-
lines.push(args.join(' '));
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await work(lines);
|
|
57
|
-
} finally {
|
|
58
|
-
console.log = originalLog;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return lines.join('\n');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
describe('runAddModule', () => {
|
|
65
|
-
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
66
|
-
const packageRoot = path.resolve(thisDir, '..');
|
|
67
|
-
|
|
68
|
-
it('lists implemented modules without status suffixes', async () => {
|
|
69
|
-
const output = await captureLogs(async () => {
|
|
70
|
-
await runAddModule(['--list']);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
assert.match(output, /Available modules:/);
|
|
74
|
-
assert.doesNotMatch(output, /\(implemented\)/);
|
|
75
|
-
assert.match(output, /- files - /);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('installs files stack non-interactively with provider selection and restores sync tooling', async () => {
|
|
79
|
-
const tempRoot = makeTempDir('forgeon-run-add-files-');
|
|
80
|
-
const targetRoot = path.join(tempRoot, 'demo-run-add-files');
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
scaffoldBaseProject({
|
|
84
|
-
packageRoot,
|
|
85
|
-
targetRoot,
|
|
86
|
-
projectName: 'demo-run-add-files',
|
|
87
|
-
proxy: 'nginx',
|
|
88
|
-
});
|
|
89
|
-
stripSyncTooling(targetRoot);
|
|
90
|
-
|
|
91
|
-
const output = await captureLogs(async () => {
|
|
92
|
-
await runAddModule([
|
|
93
|
-
'files',
|
|
94
|
-
'--project',
|
|
95
|
-
targetRoot,
|
|
96
|
-
'--with-required',
|
|
97
|
-
'--provider',
|
|
98
|
-
'files-storage-adapter=files-local',
|
|
99
|
-
]);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'db-prisma', 'package.json')), true);
|
|
103
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files-local', 'package.json')), true);
|
|
104
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files', 'package.json')), true);
|
|
105
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'scripts', 'forgeon-sync-integrations.mjs')), true);
|
|
106
|
-
|
|
107
|
-
const packageJson = JSON.parse(readFile(path.join(targetRoot, 'package.json')));
|
|
108
|
-
assert.equal(packageJson.scripts['forgeon:sync-integrations'], 'node scripts/forgeon-sync-integrations.mjs');
|
|
109
|
-
assert.equal(packageJson.scripts['add-all'], 'npx create-forgeon@latest add all --project .');
|
|
110
|
-
|
|
111
|
-
const compose = readFile(path.join(targetRoot, 'infra', 'docker', 'compose.yml'));
|
|
112
|
-
assert.match(compose, /^\s{2}nginx:\s*$/m);
|
|
113
|
-
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
114
|
-
|
|
115
|
-
const apiEnv = readFile(path.join(targetRoot, 'apps', 'api', '.env.example'));
|
|
116
|
-
assert.match(apiEnv, /DATABASE_URL=postgresql:\/\/postgres:postgres@localhost:5432\/app\?schema=public/);
|
|
117
|
-
assert.match(apiEnv, /FILES_STORAGE_DRIVER=local/);
|
|
118
|
-
|
|
119
|
-
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
120
|
-
assert.match(healthController, /@Post\('files'\)/);
|
|
121
|
-
|
|
122
|
-
assert.match(output, /Recommended companion modules are available:/);
|
|
123
|
-
assert.match(output, /No integration groups found\./);
|
|
124
|
-
assert.match(output, /Next: run pnpm install/);
|
|
125
|
-
} finally {
|
|
126
|
-
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('installs all implemented modules non-interactively with the recommended provider', async () => {
|
|
131
|
-
const tempRoot = makeTempDir('forgeon-run-add-all-');
|
|
132
|
-
const targetRoot = path.join(tempRoot, 'demo-run-add-all');
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
scaffoldBaseProject({
|
|
136
|
-
packageRoot,
|
|
137
|
-
targetRoot,
|
|
138
|
-
projectName: 'demo-run-add-all',
|
|
139
|
-
proxy: 'caddy',
|
|
140
|
-
});
|
|
141
|
-
stripSyncTooling(targetRoot);
|
|
142
|
-
|
|
143
|
-
const output = await captureLogs(async () => {
|
|
144
|
-
await runAddModule(['all', '--project', targetRoot]);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const expectedInstalledModules = [
|
|
148
|
-
'db-prisma',
|
|
149
|
-
'files-local',
|
|
150
|
-
'files',
|
|
151
|
-
'files-access',
|
|
152
|
-
'files-quotas',
|
|
153
|
-
'files-image',
|
|
154
|
-
'i18n',
|
|
155
|
-
'logger',
|
|
156
|
-
'swagger',
|
|
157
|
-
'accounts',
|
|
158
|
-
'rate-limit',
|
|
159
|
-
'rbac',
|
|
160
|
-
'queue',
|
|
161
|
-
'scheduler',
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
for (const moduleId of expectedInstalledModules) {
|
|
165
|
-
const packageDir =
|
|
166
|
-
moduleId === 'accounts'
|
|
167
|
-
? path.join(targetRoot, 'packages', 'accounts-api')
|
|
168
|
-
: path.join(targetRoot, 'packages', moduleId);
|
|
169
|
-
assert.equal(fs.existsSync(path.join(packageDir, 'package.json')), true, `expected ${moduleId}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files-s3', 'package.json')), false);
|
|
173
|
-
|
|
174
|
-
const packageJson = JSON.parse(readFile(path.join(targetRoot, 'package.json')));
|
|
175
|
-
assert.equal(packageJson.scripts['forgeon:sync-integrations'], 'node scripts/forgeon-sync-integrations.mjs');
|
|
176
|
-
assert.equal(packageJson.scripts['add-all'], 'npx create-forgeon@latest add all --project .');
|
|
177
|
-
|
|
178
|
-
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
179
|
-
assert.match(healthController, /@Post\('files'\)/);
|
|
180
|
-
assert.match(healthController, /@Get\('files-image'\)/);
|
|
181
|
-
assert.match(healthController, /@Get\('queue'\)/);
|
|
182
|
-
assert.match(healthController, /@Get\('scheduler'\)/);
|
|
183
|
-
assert.match(healthController, /@Get\('rate-limit'\)/);
|
|
184
|
-
|
|
185
|
-
assert.match(output, /Found 1 integration group/);
|
|
186
|
-
assert.match(output, /Integration skipped\./);
|
|
187
|
-
assert.match(output, /Run later with: pnpm forgeon:sync-integrations/);
|
|
188
|
-
assert.match(output, /Next: run pnpm install/);
|
|
189
|
-
assert.doesNotMatch(output, /Recommended companion modules are available:/);
|
|
190
|
-
} finally {
|
|
191
|
-
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('installs scheduler with required queue on proxy=none scaffold', async () => {
|
|
196
|
-
const tempRoot = makeTempDir('forgeon-run-add-scheduler-');
|
|
197
|
-
const targetRoot = path.join(tempRoot, 'demo-run-add-scheduler');
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
scaffoldBaseProject({
|
|
201
|
-
packageRoot,
|
|
202
|
-
targetRoot,
|
|
203
|
-
projectName: 'demo-run-add-scheduler',
|
|
204
|
-
proxy: 'none',
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
const output = await captureLogs(async () => {
|
|
208
|
-
await runAddModule(['scheduler', '--project', targetRoot, '--with-required']);
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'queue', 'package.json')), true);
|
|
212
|
-
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'scheduler', 'package.json')), true);
|
|
213
|
-
|
|
214
|
-
const compose = readFile(path.join(targetRoot, 'infra', 'docker', 'compose.yml'));
|
|
215
|
-
assert.match(compose, /^\s{2}redis:\s*$/m);
|
|
216
|
-
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
217
|
-
assert.doesNotMatch(compose, /^\s{2}nginx:\s*$/m);
|
|
218
|
-
|
|
219
|
-
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
220
|
-
assert.match(healthController, /@Get\('queue'\)/);
|
|
221
|
-
assert.match(healthController, /@Get\('scheduler'\)/);
|
|
222
|
-
|
|
223
|
-
assert.match(output, /No integration groups found\./);
|
|
224
|
-
assert.match(output, /Next: run pnpm install/);
|
|
225
|
-
} finally {
|
|
226
|
-
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
227
|
-
}
|
|
228
|
-
});
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { scaffoldProject } from './core/scaffold.mjs';
|
|
8
|
+
import { runAddModule } from './run-add-module.mjs';
|
|
9
|
+
|
|
10
|
+
function makeTempDir(prefix) {
|
|
11
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readFile(filePath) {
|
|
15
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function writeJson(filePath, value) {
|
|
19
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function scaffoldBaseProject({ packageRoot, targetRoot, projectName, proxy }) {
|
|
23
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
24
|
+
scaffoldProject({
|
|
25
|
+
templateRoot,
|
|
26
|
+
packageRoot,
|
|
27
|
+
targetRoot,
|
|
28
|
+
projectName,
|
|
29
|
+
frontend: 'react',
|
|
30
|
+
db: 'prisma',
|
|
31
|
+
dbPrismaEnabled: false,
|
|
32
|
+
i18nEnabled: false,
|
|
33
|
+
proxy,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function stripSyncTooling(targetRoot) {
|
|
38
|
+
const packagePath = path.join(targetRoot, 'package.json');
|
|
39
|
+
const packageJson = JSON.parse(readFile(packagePath));
|
|
40
|
+
if (packageJson.scripts) {
|
|
41
|
+
delete packageJson.scripts['forgeon:sync-integrations'];
|
|
42
|
+
}
|
|
43
|
+
writeJson(packagePath, packageJson);
|
|
44
|
+
|
|
45
|
+
fs.rmSync(path.join(targetRoot, 'scripts', 'forgeon-sync-integrations.mjs'), { force: true });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function captureLogs(work) {
|
|
49
|
+
const lines = [];
|
|
50
|
+
const originalLog = console.log;
|
|
51
|
+
console.log = (...args) => {
|
|
52
|
+
lines.push(args.join(' '));
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await work(lines);
|
|
57
|
+
} finally {
|
|
58
|
+
console.log = originalLog;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return lines.join('\n');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe('runAddModule', () => {
|
|
65
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
66
|
+
const packageRoot = path.resolve(thisDir, '..');
|
|
67
|
+
|
|
68
|
+
it('lists implemented modules without status suffixes', async () => {
|
|
69
|
+
const output = await captureLogs(async () => {
|
|
70
|
+
await runAddModule(['--list']);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
assert.match(output, /Available modules:/);
|
|
74
|
+
assert.doesNotMatch(output, /\(implemented\)/);
|
|
75
|
+
assert.match(output, /- files - /);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('installs files stack non-interactively with provider selection and restores sync tooling', async () => {
|
|
79
|
+
const tempRoot = makeTempDir('forgeon-run-add-files-');
|
|
80
|
+
const targetRoot = path.join(tempRoot, 'demo-run-add-files');
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
scaffoldBaseProject({
|
|
84
|
+
packageRoot,
|
|
85
|
+
targetRoot,
|
|
86
|
+
projectName: 'demo-run-add-files',
|
|
87
|
+
proxy: 'nginx',
|
|
88
|
+
});
|
|
89
|
+
stripSyncTooling(targetRoot);
|
|
90
|
+
|
|
91
|
+
const output = await captureLogs(async () => {
|
|
92
|
+
await runAddModule([
|
|
93
|
+
'files',
|
|
94
|
+
'--project',
|
|
95
|
+
targetRoot,
|
|
96
|
+
'--with-required',
|
|
97
|
+
'--provider',
|
|
98
|
+
'files-storage-adapter=files-local',
|
|
99
|
+
]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'db-prisma', 'package.json')), true);
|
|
103
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files-local', 'package.json')), true);
|
|
104
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files', 'package.json')), true);
|
|
105
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'scripts', 'forgeon-sync-integrations.mjs')), true);
|
|
106
|
+
|
|
107
|
+
const packageJson = JSON.parse(readFile(path.join(targetRoot, 'package.json')));
|
|
108
|
+
assert.equal(packageJson.scripts['forgeon:sync-integrations'], 'node scripts/forgeon-sync-integrations.mjs');
|
|
109
|
+
assert.equal(packageJson.scripts['add-all'], 'npx create-forgeon@latest add all --project .');
|
|
110
|
+
|
|
111
|
+
const compose = readFile(path.join(targetRoot, 'infra', 'docker', 'compose.yml'));
|
|
112
|
+
assert.match(compose, /^\s{2}nginx:\s*$/m);
|
|
113
|
+
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
114
|
+
|
|
115
|
+
const apiEnv = readFile(path.join(targetRoot, 'apps', 'api', '.env.example'));
|
|
116
|
+
assert.match(apiEnv, /DATABASE_URL=postgresql:\/\/postgres:postgres@localhost:5432\/app\?schema=public/);
|
|
117
|
+
assert.match(apiEnv, /FILES_STORAGE_DRIVER=local/);
|
|
118
|
+
|
|
119
|
+
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
120
|
+
assert.match(healthController, /@Post\('files'\)/);
|
|
121
|
+
|
|
122
|
+
assert.match(output, /Recommended companion modules are available:/);
|
|
123
|
+
assert.match(output, /No integration groups found\./);
|
|
124
|
+
assert.match(output, /Next: run pnpm install/);
|
|
125
|
+
} finally {
|
|
126
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('installs all implemented modules non-interactively with the recommended provider', async () => {
|
|
131
|
+
const tempRoot = makeTempDir('forgeon-run-add-all-');
|
|
132
|
+
const targetRoot = path.join(tempRoot, 'demo-run-add-all');
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
scaffoldBaseProject({
|
|
136
|
+
packageRoot,
|
|
137
|
+
targetRoot,
|
|
138
|
+
projectName: 'demo-run-add-all',
|
|
139
|
+
proxy: 'caddy',
|
|
140
|
+
});
|
|
141
|
+
stripSyncTooling(targetRoot);
|
|
142
|
+
|
|
143
|
+
const output = await captureLogs(async () => {
|
|
144
|
+
await runAddModule(['all', '--project', targetRoot]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const expectedInstalledModules = [
|
|
148
|
+
'db-prisma',
|
|
149
|
+
'files-local',
|
|
150
|
+
'files',
|
|
151
|
+
'files-access',
|
|
152
|
+
'files-quotas',
|
|
153
|
+
'files-image',
|
|
154
|
+
'i18n',
|
|
155
|
+
'logger',
|
|
156
|
+
'swagger',
|
|
157
|
+
'accounts',
|
|
158
|
+
'rate-limit',
|
|
159
|
+
'rbac',
|
|
160
|
+
'queue',
|
|
161
|
+
'scheduler',
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
for (const moduleId of expectedInstalledModules) {
|
|
165
|
+
const packageDir =
|
|
166
|
+
moduleId === 'accounts'
|
|
167
|
+
? path.join(targetRoot, 'packages', 'accounts-api')
|
|
168
|
+
: path.join(targetRoot, 'packages', moduleId);
|
|
169
|
+
assert.equal(fs.existsSync(path.join(packageDir, 'package.json')), true, `expected ${moduleId}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'files-s3', 'package.json')), false);
|
|
173
|
+
|
|
174
|
+
const packageJson = JSON.parse(readFile(path.join(targetRoot, 'package.json')));
|
|
175
|
+
assert.equal(packageJson.scripts['forgeon:sync-integrations'], 'node scripts/forgeon-sync-integrations.mjs');
|
|
176
|
+
assert.equal(packageJson.scripts['add-all'], 'npx create-forgeon@latest add all --project .');
|
|
177
|
+
|
|
178
|
+
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
179
|
+
assert.match(healthController, /@Post\('files'\)/);
|
|
180
|
+
assert.match(healthController, /@Get\('files-image'\)/);
|
|
181
|
+
assert.match(healthController, /@Get\('queue'\)/);
|
|
182
|
+
assert.match(healthController, /@Get\('scheduler'\)/);
|
|
183
|
+
assert.match(healthController, /@Get\('rate-limit'\)/);
|
|
184
|
+
|
|
185
|
+
assert.match(output, /Found 1 integration group/);
|
|
186
|
+
assert.match(output, /Integration skipped\./);
|
|
187
|
+
assert.match(output, /Run later with: pnpm forgeon:sync-integrations/);
|
|
188
|
+
assert.match(output, /Next: run pnpm install/);
|
|
189
|
+
assert.doesNotMatch(output, /Recommended companion modules are available:/);
|
|
190
|
+
} finally {
|
|
191
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('installs scheduler with required queue on proxy=none scaffold', async () => {
|
|
196
|
+
const tempRoot = makeTempDir('forgeon-run-add-scheduler-');
|
|
197
|
+
const targetRoot = path.join(tempRoot, 'demo-run-add-scheduler');
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
scaffoldBaseProject({
|
|
201
|
+
packageRoot,
|
|
202
|
+
targetRoot,
|
|
203
|
+
projectName: 'demo-run-add-scheduler',
|
|
204
|
+
proxy: 'none',
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const output = await captureLogs(async () => {
|
|
208
|
+
await runAddModule(['scheduler', '--project', targetRoot, '--with-required']);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'queue', 'package.json')), true);
|
|
212
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'packages', 'scheduler', 'package.json')), true);
|
|
213
|
+
|
|
214
|
+
const compose = readFile(path.join(targetRoot, 'infra', 'docker', 'compose.yml'));
|
|
215
|
+
assert.match(compose, /^\s{2}redis:\s*$/m);
|
|
216
|
+
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
217
|
+
assert.doesNotMatch(compose, /^\s{2}nginx:\s*$/m);
|
|
218
|
+
|
|
219
|
+
const healthController = readFile(path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts'));
|
|
220
|
+
assert.match(healthController, /@Get\('queue'\)/);
|
|
221
|
+
assert.match(healthController, /@Get\('scheduler'\)/);
|
|
222
|
+
|
|
223
|
+
assert.match(output, /No integration groups found\./);
|
|
224
|
+
assert.match(output, /Next: run pnpm install/);
|
|
225
|
+
} finally {
|
|
226
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
229
|
});
|
|
230
230
|
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@forgeon/files-quotas",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc -p tsconfig.json"
|
|
9
|
-
},
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"@forgeon/files": "workspace:*",
|
|
12
|
-
"@nestjs/common": "^11.0.1",
|
|
13
|
-
"@nestjs/config": "^4.0.0",
|
|
14
|
-
"zod": "^3.24.2"
|
|
15
|
-
},
|
|
16
|
-
"devDependencies": {
|
|
17
|
-
"@types/node": "^22.10.7",
|
|
18
|
-
"typescript": "^5.7.3"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeon/files-quotas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@forgeon/files": "workspace:*",
|
|
12
|
+
"@nestjs/common": "^11.0.1",
|
|
13
|
+
"@nestjs/config": "^4.0.0",
|
|
14
|
+
"zod": "^3.24.2"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^22.10.7",
|
|
18
|
+
"typescript": "^5.7.3"
|
|
19
|
+
}
|
|
20
|
+
}
|