@cerema/cadriciel 1.7.7 → 1.8.1
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/cli/global/create.js +245 -37
- package/cli.js +1 -0
- package/package.json +1 -1
- package/.gitlab-ci.yml +0 -16
- package/cli/assets/docker/.env +0 -27
package/cli/global/create.js
CHANGED
|
@@ -11,6 +11,157 @@ module.exports = (args) => {
|
|
|
11
11
|
const CACHE_DIR = path.join(os.homedir(), '.cadriciel', 'starters-cache');
|
|
12
12
|
const PACKAGE_NAME = '@cadriciel/starters';
|
|
13
13
|
|
|
14
|
+
// Helper: Parse CLI arguments
|
|
15
|
+
const parseArgs = (cmdArgs) => {
|
|
16
|
+
const options = {
|
|
17
|
+
name: null,
|
|
18
|
+
template: null,
|
|
19
|
+
features: null,
|
|
20
|
+
allFeatures: false,
|
|
21
|
+
defaults: false,
|
|
22
|
+
list: false,
|
|
23
|
+
listFeatures: null,
|
|
24
|
+
yes: false,
|
|
25
|
+
test: false,
|
|
26
|
+
help: false
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < cmdArgs.length; i++) {
|
|
30
|
+
const arg = cmdArgs[i];
|
|
31
|
+
const nextArg = cmdArgs[i + 1];
|
|
32
|
+
|
|
33
|
+
switch (arg) {
|
|
34
|
+
case '-n':
|
|
35
|
+
case '--name':
|
|
36
|
+
options.name = nextArg;
|
|
37
|
+
i++;
|
|
38
|
+
break;
|
|
39
|
+
case '-t':
|
|
40
|
+
case '--template':
|
|
41
|
+
options.template = nextArg;
|
|
42
|
+
i++;
|
|
43
|
+
break;
|
|
44
|
+
case '-f':
|
|
45
|
+
case '--features':
|
|
46
|
+
options.features = nextArg ? nextArg.split(',').map(f => f.trim()) : [];
|
|
47
|
+
i++;
|
|
48
|
+
break;
|
|
49
|
+
case '-a':
|
|
50
|
+
case '--all-features':
|
|
51
|
+
options.allFeatures = true;
|
|
52
|
+
break;
|
|
53
|
+
case '-d':
|
|
54
|
+
case '--defaults':
|
|
55
|
+
options.defaults = true;
|
|
56
|
+
break;
|
|
57
|
+
case '-l':
|
|
58
|
+
case '--list':
|
|
59
|
+
options.list = true;
|
|
60
|
+
break;
|
|
61
|
+
case '--list-features':
|
|
62
|
+
options.listFeatures = nextArg;
|
|
63
|
+
i++;
|
|
64
|
+
break;
|
|
65
|
+
case '-y':
|
|
66
|
+
case '--yes':
|
|
67
|
+
options.yes = true;
|
|
68
|
+
break;
|
|
69
|
+
case '--test':
|
|
70
|
+
options.test = true;
|
|
71
|
+
break;
|
|
72
|
+
case '-h':
|
|
73
|
+
case '--help':
|
|
74
|
+
options.help = true;
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
// Positional argument (project name if not already set)
|
|
78
|
+
if (!arg.startsWith('-') && !options.name && arg !== 'create') {
|
|
79
|
+
options.name = arg;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return options;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Helper: Display help
|
|
89
|
+
const showHelp = () => {
|
|
90
|
+
console.log(chalk.bold.cyan('\nUsage: cad create [options] [project-name]\n'));
|
|
91
|
+
console.log(chalk.bold('Options:'));
|
|
92
|
+
console.log(' -n, --name <name> Project name');
|
|
93
|
+
console.log(' -t, --template <id> Template ID (skip template selection)');
|
|
94
|
+
console.log(' -f, --features <list> Comma-separated list of features to enable');
|
|
95
|
+
console.log(' -a, --all-features Enable all available features');
|
|
96
|
+
console.log(' -d, --defaults Use default feature selection');
|
|
97
|
+
console.log(' -l, --list List available templates');
|
|
98
|
+
console.log(' --list-features <id> List features for a specific template');
|
|
99
|
+
console.log(' -y, --yes Auto-confirm prompts (e.g., overwrite)');
|
|
100
|
+
console.log(' --test Use current directory for starters (dev mode)');
|
|
101
|
+
console.log(' -h, --help Show this help message');
|
|
102
|
+
console.log(chalk.bold('\nExamples:'));
|
|
103
|
+
console.log(chalk.gray(' # Interactive mode (default)'));
|
|
104
|
+
console.log(' cad create');
|
|
105
|
+
console.log(' cad create my-project');
|
|
106
|
+
console.log(chalk.gray('\n # Automated mode'));
|
|
107
|
+
console.log(' cad create -n my-project -t basic -d');
|
|
108
|
+
console.log(' cad create -n my-project -t basic -f auth,api');
|
|
109
|
+
console.log(' cad create -n my-project -t basic -a -y');
|
|
110
|
+
console.log(chalk.gray('\n # List templates and features'));
|
|
111
|
+
console.log(' cad create --list');
|
|
112
|
+
console.log(' cad create --list-features basic');
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Helper: List templates
|
|
116
|
+
const listTemplates = (starters) => {
|
|
117
|
+
console.log(chalk.bold.cyan('\nAvailable templates:\n'));
|
|
118
|
+
starters.forEach(s => {
|
|
119
|
+
console.log(` ${chalk.bold.green(s.id)}`);
|
|
120
|
+
console.log(` Name: ${s.name}`);
|
|
121
|
+
console.log(` Description: ${s.description}`);
|
|
122
|
+
console.log('');
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Helper: List features for a template
|
|
127
|
+
const listFeatures = (starter) => {
|
|
128
|
+
const optionsConfig = starter.config.options || {};
|
|
129
|
+
const coreFeatures = [];
|
|
130
|
+
const optionalFeatures = [];
|
|
131
|
+
|
|
132
|
+
Object.keys(optionsConfig).forEach(key => {
|
|
133
|
+
const opt = optionsConfig[key];
|
|
134
|
+
if (opt.type === 'core') {
|
|
135
|
+
coreFeatures.push({ id: key, ...opt });
|
|
136
|
+
} else {
|
|
137
|
+
optionalFeatures.push({ id: key, ...opt });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.log(chalk.bold.cyan(`\nFeatures for template: ${starter.name}\n`));
|
|
142
|
+
|
|
143
|
+
if (coreFeatures.length > 0) {
|
|
144
|
+
console.log(chalk.bold('Core (always included):'));
|
|
145
|
+
coreFeatures.forEach(f => {
|
|
146
|
+
console.log(` ${chalk.gray('•')} ${f.id}${f.description ? ` - ${f.description}` : ''}`);
|
|
147
|
+
});
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (optionalFeatures.length > 0) {
|
|
152
|
+
console.log(chalk.bold('Optional:'));
|
|
153
|
+
optionalFeatures.forEach(f => {
|
|
154
|
+
const defaultTag = f.default ? chalk.green(' [default]') : '';
|
|
155
|
+
console.log(` ${chalk.gray('•')} ${chalk.bold(f.id)}${f.description ? ` - ${f.description}` : ''}${defaultTag}`);
|
|
156
|
+
});
|
|
157
|
+
console.log('');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (optionalFeatures.length === 0 && coreFeatures.length === 0) {
|
|
161
|
+
console.log(chalk.yellow(' No features defined for this template.'));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
14
165
|
// Helper: Fetch/Update the starters package
|
|
15
166
|
const fetchStarters = async () => {
|
|
16
167
|
const spinner = ora('Fetching latest starters...').start();
|
|
@@ -71,19 +222,23 @@ module.exports = (args) => {
|
|
|
71
222
|
};
|
|
72
223
|
|
|
73
224
|
// Helper: Generate Project
|
|
74
|
-
const generateProject = async (starter, options, targetName) => {
|
|
225
|
+
const generateProject = async (starter, options, targetName, autoConfirm = false) => {
|
|
75
226
|
const targetPath = path.resolve(process.cwd(), targetName);
|
|
76
227
|
|
|
77
228
|
if (fs.existsSync(targetPath)) {
|
|
78
|
-
|
|
79
|
-
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
229
|
+
if (autoConfirm) {
|
|
230
|
+
console.log(chalk.yellow(`Directory ${targetName} already exists. Overwriting...`));
|
|
231
|
+
} else {
|
|
232
|
+
const { replace } = await inquirer.prompt([
|
|
233
|
+
{
|
|
234
|
+
type: 'confirm',
|
|
235
|
+
name: 'replace',
|
|
236
|
+
message: `Directory ${targetName} already exists. Overwrite?`,
|
|
237
|
+
default: false
|
|
238
|
+
}
|
|
239
|
+
]);
|
|
240
|
+
if (!replace) return;
|
|
241
|
+
}
|
|
87
242
|
}
|
|
88
243
|
|
|
89
244
|
const spinner = ora(`Generating project ${targetName}...`).start();
|
|
@@ -182,16 +337,23 @@ module.exports = (args) => {
|
|
|
182
337
|
description: 'Create a new project from Cadriciel templates',
|
|
183
338
|
},
|
|
184
339
|
start: async (cmdArgs) => {
|
|
340
|
+
// Parse CLI arguments
|
|
341
|
+
const opts = parseArgs(cmdArgs);
|
|
342
|
+
|
|
343
|
+
// Show help if requested
|
|
344
|
+
if (opts.help) {
|
|
345
|
+
showHelp();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
185
349
|
console.log(chalk.bold.cyan('Cadriciel Project Generator'));
|
|
186
350
|
|
|
187
|
-
//
|
|
188
|
-
const
|
|
189
|
-
// Remove --test from args so it doesn't interfere with project name
|
|
190
|
-
const filteredArgs = cmdArgs.filter(arg => arg !== '--test');
|
|
351
|
+
// Determine if running in automated mode
|
|
352
|
+
const isAutomated = opts.template && opts.name && (opts.features || opts.allFeatures || opts.defaults);
|
|
191
353
|
|
|
192
354
|
// 1. Fetch Starters
|
|
193
355
|
let startersPath;
|
|
194
|
-
if (
|
|
356
|
+
if (opts.test) {
|
|
195
357
|
console.log(chalk.yellow('Running in TEST mode: Using current directory for starters.'));
|
|
196
358
|
startersPath = process.cwd();
|
|
197
359
|
} else {
|
|
@@ -206,12 +368,26 @@ module.exports = (args) => {
|
|
|
206
368
|
return;
|
|
207
369
|
}
|
|
208
370
|
|
|
209
|
-
//
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
371
|
+
// Handle --list: show available templates and exit
|
|
372
|
+
if (opts.list) {
|
|
373
|
+
listTemplates(starters);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Handle --list-features: show features for a template and exit
|
|
378
|
+
if (opts.listFeatures) {
|
|
379
|
+
const starter = starters.find(s => s.id === opts.listFeatures);
|
|
380
|
+
if (!starter) {
|
|
381
|
+
console.log(chalk.red(`Template '${opts.listFeatures}' not found.`));
|
|
382
|
+
console.log(chalk.gray('Use --list to see available templates.'));
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
listFeatures(starter);
|
|
386
|
+
return;
|
|
213
387
|
}
|
|
214
|
-
|
|
388
|
+
|
|
389
|
+
// 2. Get Project Name
|
|
390
|
+
let targetName = opts.name;
|
|
215
391
|
if (!targetName) {
|
|
216
392
|
const answers = await inquirer.prompt([
|
|
217
393
|
{
|
|
@@ -225,25 +401,38 @@ module.exports = (args) => {
|
|
|
225
401
|
}
|
|
226
402
|
|
|
227
403
|
// 3. Select Starter
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
value: s.id
|
|
236
|
-
}))
|
|
404
|
+
let starter;
|
|
405
|
+
if (opts.template) {
|
|
406
|
+
starter = starters.find(s => s.id === opts.template);
|
|
407
|
+
if (!starter) {
|
|
408
|
+
console.log(chalk.red(`Template '${opts.template}' not found.`));
|
|
409
|
+
console.log(chalk.gray('Use --list to see available templates.'));
|
|
410
|
+
return;
|
|
237
411
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
412
|
+
console.log(chalk.gray(`Using template: ${starter.name}`));
|
|
413
|
+
} else if (opts.defaults || opts.allFeatures || opts.features) {
|
|
414
|
+
// In automated mode without explicit template, use first available
|
|
415
|
+
starter = starters[0];
|
|
416
|
+
console.log(chalk.gray(`Using default template: ${starter.name}`));
|
|
417
|
+
} else {
|
|
418
|
+
const { selectedStarterId } = await inquirer.prompt([
|
|
419
|
+
{
|
|
420
|
+
type: 'list',
|
|
421
|
+
name: 'selectedStarterId',
|
|
422
|
+
message: 'Select a template:',
|
|
423
|
+
choices: starters.map(s => ({
|
|
424
|
+
name: `${chalk.bold(s.name)} - ${s.description}${opts.test ? ` (${s.path})` : ''}`,
|
|
425
|
+
value: s.id
|
|
426
|
+
}))
|
|
427
|
+
}
|
|
428
|
+
]);
|
|
429
|
+
starter = starters.find(s => s.id === selectedStarterId);
|
|
430
|
+
}
|
|
241
431
|
|
|
242
432
|
// 4. Select Features
|
|
243
|
-
// Determine selectable features from config
|
|
244
433
|
const optionsConfig = starter.config.options || {};
|
|
245
434
|
const selectableFeatures = Object.keys(optionsConfig)
|
|
246
|
-
.filter(key => optionsConfig[key].type !== 'core')
|
|
435
|
+
.filter(key => optionsConfig[key].type !== 'core')
|
|
247
436
|
.map(key => ({
|
|
248
437
|
name: optionsConfig[key].description || key,
|
|
249
438
|
value: key,
|
|
@@ -251,7 +440,26 @@ module.exports = (args) => {
|
|
|
251
440
|
}));
|
|
252
441
|
|
|
253
442
|
let selectedFeatures = [];
|
|
254
|
-
|
|
443
|
+
|
|
444
|
+
if (opts.allFeatures) {
|
|
445
|
+
// Enable all features
|
|
446
|
+
selectedFeatures = selectableFeatures.map(f => f.value);
|
|
447
|
+
console.log(chalk.gray(`Enabling all features: ${selectedFeatures.join(', ') || 'none'}`));
|
|
448
|
+
} else if (opts.features) {
|
|
449
|
+
// Use specified features
|
|
450
|
+
const validFeatures = selectableFeatures.map(f => f.value);
|
|
451
|
+
const invalidFeatures = opts.features.filter(f => !validFeatures.includes(f));
|
|
452
|
+
if (invalidFeatures.length > 0) {
|
|
453
|
+
console.log(chalk.yellow(`Warning: Unknown features ignored: ${invalidFeatures.join(', ')}`));
|
|
454
|
+
}
|
|
455
|
+
selectedFeatures = opts.features.filter(f => validFeatures.includes(f));
|
|
456
|
+
console.log(chalk.gray(`Selected features: ${selectedFeatures.join(', ') || 'none'}`));
|
|
457
|
+
} else if (opts.defaults) {
|
|
458
|
+
// Use default features
|
|
459
|
+
selectedFeatures = selectableFeatures.filter(f => f.checked).map(f => f.value);
|
|
460
|
+
console.log(chalk.gray(`Using default features: ${selectedFeatures.join(', ') || 'none'}`));
|
|
461
|
+
} else if (selectableFeatures.length > 0) {
|
|
462
|
+
// Interactive mode
|
|
255
463
|
const featureAnswers = await inquirer.prompt([
|
|
256
464
|
{
|
|
257
465
|
type: 'checkbox',
|
|
@@ -264,9 +472,9 @@ module.exports = (args) => {
|
|
|
264
472
|
}
|
|
265
473
|
|
|
266
474
|
// 5. Generate
|
|
267
|
-
await generateProject(starter, { selectedFeatures }, targetName);
|
|
475
|
+
await generateProject(starter, { selectedFeatures }, targetName, opts.yes);
|
|
268
476
|
|
|
269
|
-
if (
|
|
477
|
+
if (opts.test) process.exit(0);
|
|
270
478
|
},
|
|
271
479
|
};
|
|
272
480
|
};
|
package/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const userHomeDir = os.homedir(); // Fetching the user's home directory.
|
|
|
10
10
|
const boxen = require('boxen'); // For creating boxes in the console.
|
|
11
11
|
const axios = require('axios'); // For making HTTP requests.
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
// Locating the '.cadriciel' directory starting from the current working directory.
|
|
14
15
|
const CADRICIEL_PATH = findCadricielDir(process.cwd());
|
|
15
16
|
const CADRICIEL_COMMAND = 'cad';
|
package/package.json
CHANGED
package/.gitlab-ci.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
image: node:20
|
|
2
|
-
|
|
3
|
-
stages:
|
|
4
|
-
- publish
|
|
5
|
-
|
|
6
|
-
publish:
|
|
7
|
-
stage: publish
|
|
8
|
-
tags:
|
|
9
|
-
- k8-runner
|
|
10
|
-
script:
|
|
11
|
-
- npm install
|
|
12
|
-
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
|
13
|
-
- npm publish
|
|
14
|
-
rules:
|
|
15
|
-
- if: '$CI_COMMIT_TAG'
|
|
16
|
-
- if: '$CI_COMMIT_BRANCH == "main"'
|
package/cli/assets/docker/.env
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
MINIO_URL=localhost
|
|
3
|
-
MINIO_ROOT_USER=minioadmin
|
|
4
|
-
MINIO_ROOT_PASSWORD=minioadmin
|
|
5
|
-
|
|
6
|
-
POSTGRES_DB=sysadyp
|
|
7
|
-
POSTGRES_PASSWORD=password
|
|
8
|
-
PG_USER=postgres
|
|
9
|
-
|
|
10
|
-
REDIS_PASSWORD=password
|
|
11
|
-
KEYCLOAK_ADMIN_USER=admin
|
|
12
|
-
KEYCLOAK_ADMIN_PASSWORD=dreammotion
|
|
13
|
-
|
|
14
|
-
DOCKER_REGISTRY=cerema
|
|
15
|
-
PROJECT_NAME=sysadyp
|
|
16
|
-
VERSION=latest
|
|
17
|
-
|
|
18
|
-
# CADRICIEL
|
|
19
|
-
CADRICIEL_PG_DB="postgres://postgres:password@postgres:5432/sysadyp"
|
|
20
|
-
CADRICIEL_PG_DBAPI="postgres://postgres:password@postgres:5432/sysadyp"
|
|
21
|
-
CADRICIEL_PG_DB_SCHEMA="sysadyp"
|
|
22
|
-
CADRICIEL_API_PORT=3000
|
|
23
|
-
CADRICIEL_APP_PORT=4200
|
|
24
|
-
CADRICIEL_AUTH_STRATEGY="guest"
|
|
25
|
-
CADRICIEL_ORION_URI="http://localhost:9090"
|
|
26
|
-
CADRICIEL_ORION_REALM="62540d37-7443-44e2-be54-2b402e899660"
|
|
27
|
-
|