@git.zone/cli 1.21.5 → 2.1.0
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/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/mod_commit/index.js +5 -2
- package/dist_ts/mod_commit/mod.helpers.js +24 -9
- package/dist_ts/mod_format/classes.baseformatter.js +4 -4
- package/dist_ts/mod_format/classes.changecache.js +29 -17
- package/dist_ts/mod_format/classes.diffreporter.js +10 -4
- package/dist_ts/mod_format/classes.formatstats.js +5 -2
- package/dist_ts/mod_format/classes.rollbackmanager.js +41 -17
- package/dist_ts/mod_format/format.cleanup.js +5 -3
- package/dist_ts/mod_format/format.copy.js +12 -4
- package/dist_ts/mod_format/format.gitignore.js +14 -5
- package/dist_ts/mod_format/format.license.js +4 -2
- package/dist_ts/mod_format/format.packagejson.js +6 -2
- package/dist_ts/mod_format/format.readme.js +9 -5
- package/dist_ts/mod_format/format.tsconfig.js +7 -4
- package/dist_ts/mod_format/formatters/cleanup.formatter.js +2 -2
- package/dist_ts/mod_format/formatters/prettier.formatter.js +19 -6
- package/dist_ts/mod_format/index.js +9 -3
- package/dist_ts/mod_meta/meta.classes.meta.js +82 -17
- package/dist_ts/mod_services/classes.globalregistry.d.ts +77 -0
- package/dist_ts/mod_services/classes.globalregistry.js +133 -0
- package/dist_ts/mod_services/classes.serviceconfiguration.d.ts +7 -0
- package/dist_ts/mod_services/classes.serviceconfiguration.js +86 -10
- package/dist_ts/mod_services/classes.servicemanager.d.ts +38 -0
- package/dist_ts/mod_services/classes.servicemanager.js +353 -10
- package/dist_ts/mod_services/helpers.d.ts +1 -1
- package/dist_ts/mod_services/helpers.js +8 -4
- package/dist_ts/mod_services/index.js +194 -28
- package/dist_ts/mod_standard/index.js +22 -9
- package/dist_ts/mod_template/index.js +2 -2
- package/dist_ts/plugins.d.ts +2 -0
- package/dist_ts/plugins.js +4 -1
- package/package.json +7 -6
- package/readme.hints.md +55 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/mod_commit/index.ts +4 -4
- package/ts/mod_commit/mod.helpers.ts +23 -11
- package/ts/mod_format/classes.baseformatter.ts +3 -3
- package/ts/mod_format/classes.changecache.ts +28 -16
- package/ts/mod_format/classes.diffreporter.ts +9 -8
- package/ts/mod_format/classes.formatstats.ts +4 -4
- package/ts/mod_format/classes.rollbackmanager.ts +40 -18
- package/ts/mod_format/format.cleanup.ts +4 -4
- package/ts/mod_format/format.copy.ts +11 -3
- package/ts/mod_format/format.gitignore.ts +13 -6
- package/ts/mod_format/format.license.ts +3 -3
- package/ts/mod_format/format.packagejson.ts +5 -3
- package/ts/mod_format/format.readme.ts +8 -11
- package/ts/mod_format/format.tsconfig.ts +6 -5
- package/ts/mod_format/formatters/cleanup.formatter.ts +1 -1
- package/ts/mod_format/formatters/prettier.formatter.ts +18 -8
- package/ts/mod_format/index.ts +10 -5
- package/ts/mod_meta/meta.classes.meta.ts +84 -41
- package/ts/mod_services/classes.globalregistry.ts +190 -0
- package/ts/mod_services/classes.serviceconfiguration.ts +121 -35
- package/ts/mod_services/classes.servicemanager.ts +405 -32
- package/ts/mod_services/helpers.ts +8 -4
- package/ts/mod_services/index.ts +257 -48
- package/ts/mod_standard/index.ts +23 -10
- package/ts/mod_template/index.ts +1 -1
- package/ts/plugins.ts +4 -0
|
@@ -2,17 +2,21 @@ import * as plugins from './mod.plugins.js';
|
|
|
2
2
|
import * as helpers from './helpers.js';
|
|
3
3
|
import { ServiceConfiguration } from './classes.serviceconfiguration.js';
|
|
4
4
|
import { DockerContainer } from './classes.dockercontainer.js';
|
|
5
|
+
import { GlobalRegistry } from './classes.globalregistry.js';
|
|
5
6
|
import { logger } from '../gitzone.logging.js';
|
|
6
7
|
|
|
7
8
|
export class ServiceManager {
|
|
8
9
|
private config: ServiceConfiguration;
|
|
9
10
|
private docker: DockerContainer;
|
|
10
|
-
|
|
11
|
+
private enabledServices: string[] | null = null;
|
|
12
|
+
private globalRegistry: GlobalRegistry;
|
|
13
|
+
|
|
11
14
|
constructor() {
|
|
12
15
|
this.config = new ServiceConfiguration();
|
|
13
16
|
this.docker = new DockerContainer();
|
|
17
|
+
this.globalRegistry = GlobalRegistry.getInstance();
|
|
14
18
|
}
|
|
15
|
-
|
|
19
|
+
|
|
16
20
|
/**
|
|
17
21
|
* Initialize the service manager
|
|
18
22
|
*/
|
|
@@ -22,15 +26,162 @@ export class ServiceManager {
|
|
|
22
26
|
logger.log('error', 'Error: Docker is not installed. Please install Docker first.');
|
|
23
27
|
process.exit(1);
|
|
24
28
|
}
|
|
25
|
-
|
|
29
|
+
|
|
26
30
|
// Load or create configuration
|
|
27
31
|
await this.config.loadOrCreate();
|
|
28
32
|
logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`);
|
|
29
|
-
|
|
33
|
+
|
|
34
|
+
// Load service selection from npmextra.json
|
|
35
|
+
await this.loadServiceConfiguration();
|
|
36
|
+
|
|
30
37
|
// Validate and update ports if needed
|
|
31
38
|
await this.config.validateAndUpdatePorts();
|
|
32
39
|
}
|
|
33
|
-
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Load service configuration from npmextra.json
|
|
43
|
+
*/
|
|
44
|
+
private async loadServiceConfiguration(): Promise<void> {
|
|
45
|
+
const npmextraConfig = new plugins.npmextra.Npmextra(process.cwd());
|
|
46
|
+
const gitzoneConfig = npmextraConfig.dataFor<any>('gitzone', {});
|
|
47
|
+
|
|
48
|
+
// Check if services array exists
|
|
49
|
+
if (!gitzoneConfig.services || !Array.isArray(gitzoneConfig.services) || gitzoneConfig.services.length === 0) {
|
|
50
|
+
// Prompt user to select services
|
|
51
|
+
const smartinteract = new plugins.smartinteract.SmartInteract();
|
|
52
|
+
const response = await smartinteract.askQuestion({
|
|
53
|
+
name: 'services',
|
|
54
|
+
type: 'checkbox',
|
|
55
|
+
message: 'Which services do you want to enable for this project?',
|
|
56
|
+
choices: [
|
|
57
|
+
{ name: 'MongoDB', value: 'mongodb' },
|
|
58
|
+
{ name: 'MinIO (S3)', value: 'minio' },
|
|
59
|
+
{ name: 'Elasticsearch', value: 'elasticsearch' }
|
|
60
|
+
],
|
|
61
|
+
default: ['mongodb', 'minio', 'elasticsearch']
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.enabledServices = response.value || ['mongodb', 'minio', 'elasticsearch'];
|
|
65
|
+
|
|
66
|
+
// Save to npmextra.json
|
|
67
|
+
await this.saveServiceConfiguration(this.enabledServices);
|
|
68
|
+
} else {
|
|
69
|
+
this.enabledServices = gitzoneConfig.services;
|
|
70
|
+
logger.log('info', `🔧 Enabled services: ${this.enabledServices.join(', ')}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Save service configuration to npmextra.json
|
|
76
|
+
*/
|
|
77
|
+
private async saveServiceConfiguration(services: string[]): Promise<void> {
|
|
78
|
+
const npmextraPath = plugins.path.join(process.cwd(), 'npmextra.json');
|
|
79
|
+
let npmextraData: any = {};
|
|
80
|
+
|
|
81
|
+
// Read existing npmextra.json if it exists
|
|
82
|
+
if (await plugins.smartfs.file(npmextraPath).exists()) {
|
|
83
|
+
const content = await plugins.smartfs.file(npmextraPath).encoding('utf8').read();
|
|
84
|
+
npmextraData = JSON.parse(content as string);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Update gitzone.services
|
|
88
|
+
if (!npmextraData.gitzone) {
|
|
89
|
+
npmextraData.gitzone = {};
|
|
90
|
+
}
|
|
91
|
+
npmextraData.gitzone.services = services;
|
|
92
|
+
|
|
93
|
+
// Write back to npmextra.json
|
|
94
|
+
await plugins.smartfs
|
|
95
|
+
.file(npmextraPath)
|
|
96
|
+
.encoding('utf8')
|
|
97
|
+
.write(JSON.stringify(npmextraData, null, 2));
|
|
98
|
+
|
|
99
|
+
logger.log('ok', `✅ Saved service configuration to npmextra.json`);
|
|
100
|
+
logger.log('info', `🔧 Enabled services: ${services.join(', ')}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if a service is enabled
|
|
105
|
+
*/
|
|
106
|
+
private isServiceEnabled(service: string): boolean {
|
|
107
|
+
if (!this.enabledServices) {
|
|
108
|
+
return true; // If no configuration, enable all
|
|
109
|
+
}
|
|
110
|
+
return this.enabledServices.includes(service);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Register this project with the global registry
|
|
115
|
+
*/
|
|
116
|
+
private async registerWithGlobalRegistry(): Promise<void> {
|
|
117
|
+
const config = this.config.getConfig();
|
|
118
|
+
const containers = this.config.getContainerNames();
|
|
119
|
+
|
|
120
|
+
await this.globalRegistry.registerProject({
|
|
121
|
+
projectPath: process.cwd(),
|
|
122
|
+
projectName: config.PROJECT_NAME,
|
|
123
|
+
containers: {
|
|
124
|
+
mongo: containers.mongo,
|
|
125
|
+
minio: containers.minio,
|
|
126
|
+
elasticsearch: containers.elasticsearch,
|
|
127
|
+
},
|
|
128
|
+
ports: {
|
|
129
|
+
mongo: parseInt(config.MONGODB_PORT),
|
|
130
|
+
s3: parseInt(config.S3_PORT),
|
|
131
|
+
s3Console: parseInt(config.S3_CONSOLE_PORT),
|
|
132
|
+
elasticsearch: parseInt(config.ELASTICSEARCH_PORT),
|
|
133
|
+
},
|
|
134
|
+
enabledServices: this.enabledServices || ['mongodb', 'minio', 'elasticsearch'],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Start all enabled services
|
|
140
|
+
*/
|
|
141
|
+
public async startAll(): Promise<void> {
|
|
142
|
+
let first = true;
|
|
143
|
+
if (this.isServiceEnabled('mongodb')) {
|
|
144
|
+
if (!first) console.log();
|
|
145
|
+
await this.startMongoDB();
|
|
146
|
+
first = false;
|
|
147
|
+
}
|
|
148
|
+
if (this.isServiceEnabled('minio')) {
|
|
149
|
+
if (!first) console.log();
|
|
150
|
+
await this.startMinIO();
|
|
151
|
+
first = false;
|
|
152
|
+
}
|
|
153
|
+
if (this.isServiceEnabled('elasticsearch')) {
|
|
154
|
+
if (!first) console.log();
|
|
155
|
+
await this.startElasticsearch();
|
|
156
|
+
first = false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Register with global registry
|
|
160
|
+
await this.registerWithGlobalRegistry();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Stop all enabled services
|
|
165
|
+
*/
|
|
166
|
+
public async stopAll(): Promise<void> {
|
|
167
|
+
let first = true;
|
|
168
|
+
if (this.isServiceEnabled('mongodb')) {
|
|
169
|
+
if (!first) console.log();
|
|
170
|
+
await this.stopMongoDB();
|
|
171
|
+
first = false;
|
|
172
|
+
}
|
|
173
|
+
if (this.isServiceEnabled('minio')) {
|
|
174
|
+
if (!first) console.log();
|
|
175
|
+
await this.stopMinIO();
|
|
176
|
+
first = false;
|
|
177
|
+
}
|
|
178
|
+
if (this.isServiceEnabled('elasticsearch')) {
|
|
179
|
+
if (!first) console.log();
|
|
180
|
+
await this.stopElasticsearch();
|
|
181
|
+
first = false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
34
185
|
/**
|
|
35
186
|
* Start MongoDB service
|
|
36
187
|
*/
|
|
@@ -42,7 +193,7 @@ export class ServiceManager {
|
|
|
42
193
|
const directories = this.config.getDataDirectories();
|
|
43
194
|
|
|
44
195
|
// Ensure data directory exists
|
|
45
|
-
await plugins.
|
|
196
|
+
await plugins.smartfs.directory(directories.mongo).recursive().create();
|
|
46
197
|
|
|
47
198
|
const status = await this.docker.getStatus(containers.mongo);
|
|
48
199
|
|
|
@@ -141,7 +292,7 @@ export class ServiceManager {
|
|
|
141
292
|
const directories = this.config.getDataDirectories();
|
|
142
293
|
|
|
143
294
|
// Ensure data directory exists
|
|
144
|
-
await plugins.
|
|
295
|
+
await plugins.smartfs.directory(directories.minio).recursive().create();
|
|
145
296
|
|
|
146
297
|
const status = await this.docker.getStatus(containers.minio);
|
|
147
298
|
|
|
@@ -259,7 +410,103 @@ export class ServiceManager {
|
|
|
259
410
|
logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`);
|
|
260
411
|
logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_ACCESSKEY}/***)`);
|
|
261
412
|
}
|
|
262
|
-
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Start Elasticsearch service
|
|
416
|
+
*/
|
|
417
|
+
public async startElasticsearch(): Promise<void> {
|
|
418
|
+
logger.log('note', '📦 Elasticsearch:');
|
|
419
|
+
|
|
420
|
+
const config = this.config.getConfig();
|
|
421
|
+
const containers = this.config.getContainerNames();
|
|
422
|
+
const directories = this.config.getDataDirectories();
|
|
423
|
+
|
|
424
|
+
// Ensure data directory exists
|
|
425
|
+
await plugins.smartfs.directory(directories.elasticsearch).recursive().create();
|
|
426
|
+
|
|
427
|
+
const status = await this.docker.getStatus(containers.elasticsearch);
|
|
428
|
+
|
|
429
|
+
switch (status) {
|
|
430
|
+
case 'running':
|
|
431
|
+
logger.log('ok', ' Already running ✓');
|
|
432
|
+
break;
|
|
433
|
+
|
|
434
|
+
case 'stopped':
|
|
435
|
+
// Check if port mapping matches config
|
|
436
|
+
const esPortMappings = await this.docker.getPortMappings(containers.elasticsearch);
|
|
437
|
+
if (esPortMappings && esPortMappings['9200'] !== config.ELASTICSEARCH_PORT) {
|
|
438
|
+
logger.log('note', ' Port configuration changed, recreating container...');
|
|
439
|
+
await this.docker.remove(containers.elasticsearch, true);
|
|
440
|
+
// Fall through to create new container
|
|
441
|
+
const success = await this.docker.run({
|
|
442
|
+
name: containers.elasticsearch,
|
|
443
|
+
image: 'elasticsearch:8.11.0',
|
|
444
|
+
ports: {
|
|
445
|
+
[`0.0.0.0:${config.ELASTICSEARCH_PORT}`]: '9200'
|
|
446
|
+
},
|
|
447
|
+
volumes: {
|
|
448
|
+
[directories.elasticsearch]: '/usr/share/elasticsearch/data'
|
|
449
|
+
},
|
|
450
|
+
environment: {
|
|
451
|
+
'discovery.type': 'single-node',
|
|
452
|
+
'xpack.security.enabled': 'true',
|
|
453
|
+
'ELASTIC_PASSWORD': config.ELASTICSEARCH_PASS,
|
|
454
|
+
'ES_JAVA_OPTS': '-Xms512m -Xmx512m'
|
|
455
|
+
},
|
|
456
|
+
restart: 'unless-stopped'
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
if (success) {
|
|
460
|
+
logger.log('ok', ' Recreated with new port ✓');
|
|
461
|
+
} else {
|
|
462
|
+
logger.log('error', ' Failed to recreate container');
|
|
463
|
+
}
|
|
464
|
+
} else {
|
|
465
|
+
// Ports match, just start the container
|
|
466
|
+
if (await this.docker.start(containers.elasticsearch)) {
|
|
467
|
+
logger.log('ok', ' Started ✓');
|
|
468
|
+
} else {
|
|
469
|
+
logger.log('error', ' Failed to start');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
|
|
474
|
+
case 'not_exists':
|
|
475
|
+
logger.log('note', ' Creating container...');
|
|
476
|
+
|
|
477
|
+
const success = await this.docker.run({
|
|
478
|
+
name: containers.elasticsearch,
|
|
479
|
+
image: 'elasticsearch:8.11.0',
|
|
480
|
+
ports: {
|
|
481
|
+
[`0.0.0.0:${config.ELASTICSEARCH_PORT}`]: '9200'
|
|
482
|
+
},
|
|
483
|
+
volumes: {
|
|
484
|
+
[directories.elasticsearch]: '/usr/share/elasticsearch/data'
|
|
485
|
+
},
|
|
486
|
+
environment: {
|
|
487
|
+
'discovery.type': 'single-node',
|
|
488
|
+
'xpack.security.enabled': 'true',
|
|
489
|
+
'ELASTIC_PASSWORD': config.ELASTICSEARCH_PASS,
|
|
490
|
+
'ES_JAVA_OPTS': '-Xms512m -Xmx512m'
|
|
491
|
+
},
|
|
492
|
+
restart: 'unless-stopped'
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
if (success) {
|
|
496
|
+
logger.log('ok', ' Created and started ✓');
|
|
497
|
+
} else {
|
|
498
|
+
logger.log('error', ' Failed to create container');
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
logger.log('info', ` Container: ${containers.elasticsearch}`);
|
|
504
|
+
logger.log('info', ` Port: ${config.ELASTICSEARCH_PORT}`);
|
|
505
|
+
logger.log('info', ` Connection: ${config.ELASTICSEARCH_URL}`);
|
|
506
|
+
logger.log('info', ` Username: ${config.ELASTICSEARCH_USER}`);
|
|
507
|
+
logger.log('info', ` Password: ${config.ELASTICSEARCH_PASS}`);
|
|
508
|
+
}
|
|
509
|
+
|
|
263
510
|
/**
|
|
264
511
|
* Stop MongoDB service
|
|
265
512
|
*/
|
|
@@ -285,10 +532,10 @@ export class ServiceManager {
|
|
|
285
532
|
*/
|
|
286
533
|
public async stopMinIO(): Promise<void> {
|
|
287
534
|
logger.log('note', '📦 S3/MinIO:');
|
|
288
|
-
|
|
535
|
+
|
|
289
536
|
const containers = this.config.getContainerNames();
|
|
290
537
|
const status = await this.docker.getStatus(containers.minio);
|
|
291
|
-
|
|
538
|
+
|
|
292
539
|
if (status === 'running') {
|
|
293
540
|
if (await this.docker.stop(containers.minio)) {
|
|
294
541
|
logger.log('ok', ' Stopped ✓');
|
|
@@ -299,7 +546,27 @@ export class ServiceManager {
|
|
|
299
546
|
logger.log('note', ' Not running');
|
|
300
547
|
}
|
|
301
548
|
}
|
|
302
|
-
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Stop Elasticsearch service
|
|
552
|
+
*/
|
|
553
|
+
public async stopElasticsearch(): Promise<void> {
|
|
554
|
+
logger.log('note', '📦 Elasticsearch:');
|
|
555
|
+
|
|
556
|
+
const containers = this.config.getContainerNames();
|
|
557
|
+
const status = await this.docker.getStatus(containers.elasticsearch);
|
|
558
|
+
|
|
559
|
+
if (status === 'running') {
|
|
560
|
+
if (await this.docker.stop(containers.elasticsearch)) {
|
|
561
|
+
logger.log('ok', ' Stopped ✓');
|
|
562
|
+
} else {
|
|
563
|
+
logger.log('error', ' Failed to stop');
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
logger.log('note', ' Not running');
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
303
570
|
/**
|
|
304
571
|
* Show service status
|
|
305
572
|
*/
|
|
@@ -385,8 +652,36 @@ export class ServiceManager {
|
|
|
385
652
|
}
|
|
386
653
|
break;
|
|
387
654
|
}
|
|
655
|
+
|
|
656
|
+
// Elasticsearch status
|
|
657
|
+
const esStatus = await this.docker.getStatus(containers.elasticsearch);
|
|
658
|
+
switch (esStatus) {
|
|
659
|
+
case 'running':
|
|
660
|
+
logger.log('ok', '📦 Elasticsearch: 🟢 Running');
|
|
661
|
+
logger.log('info', ` ├─ Container: ${containers.elasticsearch}`);
|
|
662
|
+
logger.log('info', ` ├─ Port: ${config.ELASTICSEARCH_PORT}`);
|
|
663
|
+
logger.log('info', ` ├─ Connection: ${config.ELASTICSEARCH_URL}`);
|
|
664
|
+
logger.log('info', ` └─ Credentials: ${config.ELASTICSEARCH_USER}/${config.ELASTICSEARCH_PASS}`);
|
|
665
|
+
break;
|
|
666
|
+
case 'stopped':
|
|
667
|
+
logger.log('note', '📦 Elasticsearch: 🟡 Stopped');
|
|
668
|
+
logger.log('info', ` ├─ Container: ${containers.elasticsearch}`);
|
|
669
|
+
logger.log('info', ` └─ Port: ${config.ELASTICSEARCH_PORT}`);
|
|
670
|
+
break;
|
|
671
|
+
case 'not_exists':
|
|
672
|
+
logger.log('info', '📦 Elasticsearch: ⚪ Not installed');
|
|
673
|
+
// Check port availability
|
|
674
|
+
const esPort = parseInt(config.ELASTICSEARCH_PORT);
|
|
675
|
+
const esAvailable = await helpers.isPortAvailable(esPort);
|
|
676
|
+
if (!esAvailable) {
|
|
677
|
+
logger.log('error', ` └─ ⚠️ Port ${esPort} is in use by another process`);
|
|
678
|
+
} else {
|
|
679
|
+
logger.log('info', ` └─ Port ${esPort} is available`);
|
|
680
|
+
}
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
388
683
|
}
|
|
389
|
-
|
|
684
|
+
|
|
390
685
|
/**
|
|
391
686
|
* Show configuration
|
|
392
687
|
*/
|
|
@@ -420,6 +715,15 @@ export class ServiceManager {
|
|
|
420
715
|
logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`);
|
|
421
716
|
logger.log('info', ` Endpoint: ${config.S3_ENDPOINT}`);
|
|
422
717
|
logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`);
|
|
718
|
+
|
|
719
|
+
console.log();
|
|
720
|
+
logger.log('note', 'Elasticsearch:');
|
|
721
|
+
logger.log('info', ` Host: ${config.ELASTICSEARCH_HOST}:${config.ELASTICSEARCH_PORT}`);
|
|
722
|
+
logger.log('info', ` User: ${config.ELASTICSEARCH_USER}`);
|
|
723
|
+
logger.log('info', ' Password: ***');
|
|
724
|
+
logger.log('info', ` Container: ${this.config.getContainerNames().elasticsearch}`);
|
|
725
|
+
logger.log('info', ` Data: ${this.config.getDataDirectories().elasticsearch}`);
|
|
726
|
+
logger.log('info', ` Connection: ${config.ELASTICSEARCH_URL}`);
|
|
423
727
|
}
|
|
424
728
|
|
|
425
729
|
/**
|
|
@@ -477,16 +781,29 @@ export class ServiceManager {
|
|
|
477
781
|
logger.log('note', 'S3/MinIO container is not running');
|
|
478
782
|
}
|
|
479
783
|
break;
|
|
480
|
-
|
|
784
|
+
|
|
785
|
+
case 'elasticsearch':
|
|
786
|
+
case 'es':
|
|
787
|
+
if (await this.docker.isRunning(containers.elasticsearch)) {
|
|
788
|
+
helpers.printHeader(`Elasticsearch Logs (last ${lines} lines)`);
|
|
789
|
+
const logs = await this.docker.logs(containers.elasticsearch, lines);
|
|
790
|
+
console.log(logs);
|
|
791
|
+
} else {
|
|
792
|
+
logger.log('note', 'Elasticsearch container is not running');
|
|
793
|
+
}
|
|
794
|
+
break;
|
|
795
|
+
|
|
481
796
|
case 'all':
|
|
482
797
|
case '':
|
|
483
798
|
await this.showLogs('mongo', lines);
|
|
484
799
|
console.log();
|
|
485
800
|
await this.showLogs('minio', lines);
|
|
801
|
+
console.log();
|
|
802
|
+
await this.showLogs('elasticsearch', lines);
|
|
486
803
|
break;
|
|
487
|
-
|
|
804
|
+
|
|
488
805
|
default:
|
|
489
|
-
logger.log('note', 'Usage: gitzone services logs [mongo|s3|all] [lines]');
|
|
806
|
+
logger.log('note', 'Usage: gitzone services logs [mongo|s3|elasticsearch|all] [lines]');
|
|
490
807
|
break;
|
|
491
808
|
}
|
|
492
809
|
}
|
|
@@ -497,24 +814,40 @@ export class ServiceManager {
|
|
|
497
814
|
public async removeContainers(): Promise<void> {
|
|
498
815
|
const containers = this.config.getContainerNames();
|
|
499
816
|
let removed = false;
|
|
500
|
-
|
|
817
|
+
|
|
501
818
|
if (await this.docker.exists(containers.mongo)) {
|
|
502
819
|
if (await this.docker.remove(containers.mongo, true)) {
|
|
503
820
|
logger.log('ok', ' MongoDB container removed ✓');
|
|
504
821
|
removed = true;
|
|
505
822
|
}
|
|
506
823
|
}
|
|
507
|
-
|
|
824
|
+
|
|
508
825
|
if (await this.docker.exists(containers.minio)) {
|
|
509
826
|
if (await this.docker.remove(containers.minio, true)) {
|
|
510
827
|
logger.log('ok', ' S3/MinIO container removed ✓');
|
|
511
828
|
removed = true;
|
|
512
829
|
}
|
|
513
830
|
}
|
|
514
|
-
|
|
831
|
+
|
|
832
|
+
if (await this.docker.exists(containers.elasticsearch)) {
|
|
833
|
+
if (await this.docker.remove(containers.elasticsearch, true)) {
|
|
834
|
+
logger.log('ok', ' Elasticsearch container removed ✓');
|
|
835
|
+
removed = true;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
515
839
|
if (!removed) {
|
|
516
840
|
logger.log('note', ' No containers to remove');
|
|
517
841
|
}
|
|
842
|
+
|
|
843
|
+
// Check if all containers are gone, then unregister from global registry
|
|
844
|
+
const mongoExists = await this.docker.exists(containers.mongo);
|
|
845
|
+
const minioExists = await this.docker.exists(containers.minio);
|
|
846
|
+
const esExists = await this.docker.exists(containers.elasticsearch);
|
|
847
|
+
|
|
848
|
+
if (!mongoExists && !minioExists && !esExists) {
|
|
849
|
+
await this.globalRegistry.unregisterProject(process.cwd());
|
|
850
|
+
}
|
|
518
851
|
}
|
|
519
852
|
|
|
520
853
|
/**
|
|
@@ -523,24 +856,60 @@ export class ServiceManager {
|
|
|
523
856
|
public async cleanData(): Promise<void> {
|
|
524
857
|
const directories = this.config.getDataDirectories();
|
|
525
858
|
let cleaned = false;
|
|
526
|
-
|
|
527
|
-
if (await plugins.
|
|
528
|
-
await plugins.
|
|
859
|
+
|
|
860
|
+
if (await plugins.smartfs.directory(directories.mongo).exists()) {
|
|
861
|
+
await plugins.smartfs.directory(directories.mongo).recursive().delete();
|
|
529
862
|
logger.log('ok', ' MongoDB data removed ✓');
|
|
530
863
|
cleaned = true;
|
|
531
864
|
}
|
|
532
|
-
|
|
533
|
-
if (await plugins.
|
|
534
|
-
await plugins.
|
|
865
|
+
|
|
866
|
+
if (await plugins.smartfs.directory(directories.minio).exists()) {
|
|
867
|
+
await plugins.smartfs.directory(directories.minio).recursive().delete();
|
|
535
868
|
logger.log('ok', ' S3/MinIO data removed ✓');
|
|
536
869
|
cleaned = true;
|
|
537
870
|
}
|
|
538
|
-
|
|
871
|
+
|
|
872
|
+
if (await plugins.smartfs.directory(directories.elasticsearch).exists()) {
|
|
873
|
+
await plugins.smartfs.directory(directories.elasticsearch).recursive().delete();
|
|
874
|
+
logger.log('ok', ' Elasticsearch data removed ✓');
|
|
875
|
+
cleaned = true;
|
|
876
|
+
}
|
|
877
|
+
|
|
539
878
|
if (!cleaned) {
|
|
540
879
|
logger.log('note', ' No data to clean');
|
|
541
880
|
}
|
|
542
881
|
}
|
|
543
882
|
|
|
883
|
+
/**
|
|
884
|
+
* Configure which services are enabled
|
|
885
|
+
*/
|
|
886
|
+
public async configureServices(): Promise<void> {
|
|
887
|
+
logger.log('note', 'Select which services to enable for this project:');
|
|
888
|
+
console.log();
|
|
889
|
+
|
|
890
|
+
const currentServices = this.enabledServices || ['mongodb', 'minio', 'elasticsearch'];
|
|
891
|
+
|
|
892
|
+
const smartinteract = new plugins.smartinteract.SmartInteract();
|
|
893
|
+
const response = await smartinteract.askQuestion({
|
|
894
|
+
name: 'services',
|
|
895
|
+
type: 'checkbox',
|
|
896
|
+
message: 'Which services do you want to enable?',
|
|
897
|
+
choices: [
|
|
898
|
+
{ name: 'MongoDB', value: 'mongodb' },
|
|
899
|
+
{ name: 'MinIO (S3)', value: 'minio' },
|
|
900
|
+
{ name: 'Elasticsearch', value: 'elasticsearch' }
|
|
901
|
+
],
|
|
902
|
+
default: currentServices
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
this.enabledServices = response.value || ['mongodb', 'minio', 'elasticsearch'];
|
|
906
|
+
|
|
907
|
+
// Save to npmextra.json
|
|
908
|
+
await this.saveServiceConfiguration(this.enabledServices);
|
|
909
|
+
|
|
910
|
+
logger.log('ok', '✅ Service configuration updated');
|
|
911
|
+
}
|
|
912
|
+
|
|
544
913
|
/**
|
|
545
914
|
* Reconfigure services with new ports
|
|
546
915
|
*/
|
|
@@ -551,20 +920,25 @@ export class ServiceManager {
|
|
|
551
920
|
|
|
552
921
|
// Stop existing containers
|
|
553
922
|
logger.log('note', '🛑 Stopping existing containers...');
|
|
554
|
-
|
|
923
|
+
|
|
555
924
|
if (await this.docker.exists(containers.mongo)) {
|
|
556
925
|
await this.docker.stop(containers.mongo);
|
|
557
926
|
logger.log('ok', ' MongoDB stopped ✓');
|
|
558
927
|
}
|
|
559
|
-
|
|
928
|
+
|
|
560
929
|
if (await this.docker.exists(containers.minio)) {
|
|
561
930
|
await this.docker.stop(containers.minio);
|
|
562
931
|
logger.log('ok', ' S3/MinIO stopped ✓');
|
|
563
932
|
}
|
|
564
|
-
|
|
933
|
+
|
|
934
|
+
if (await this.docker.exists(containers.elasticsearch)) {
|
|
935
|
+
await this.docker.stop(containers.elasticsearch);
|
|
936
|
+
logger.log('ok', ' Elasticsearch stopped ✓');
|
|
937
|
+
}
|
|
938
|
+
|
|
565
939
|
// Reconfigure ports
|
|
566
940
|
await this.config.reconfigurePorts();
|
|
567
|
-
|
|
941
|
+
|
|
568
942
|
// Ask if user wants to restart services
|
|
569
943
|
const smartinteract = new plugins.smartinteract.SmartInteract();
|
|
570
944
|
const response = await smartinteract.askQuestion({
|
|
@@ -573,11 +947,10 @@ export class ServiceManager {
|
|
|
573
947
|
message: 'Do you want to start services with new ports?',
|
|
574
948
|
default: true
|
|
575
949
|
});
|
|
576
|
-
|
|
950
|
+
|
|
577
951
|
if (response.value) {
|
|
578
952
|
console.log();
|
|
579
|
-
await this.
|
|
580
|
-
await this.startMinIO();
|
|
953
|
+
await this.startAll();
|
|
581
954
|
}
|
|
582
955
|
}
|
|
583
956
|
}
|
|
@@ -42,11 +42,15 @@ export const getRandomAvailablePort = async (): Promise<number> => {
|
|
|
42
42
|
/**
|
|
43
43
|
* Get the project name from package.json or directory
|
|
44
44
|
*/
|
|
45
|
-
export const getProjectName = (): string => {
|
|
45
|
+
export const getProjectName = async (): Promise<string> => {
|
|
46
46
|
try {
|
|
47
47
|
const packageJsonPath = plugins.path.join(process.cwd(), 'package.json');
|
|
48
|
-
if (plugins.
|
|
49
|
-
const
|
|
48
|
+
if (await plugins.smartfs.file(packageJsonPath).exists()) {
|
|
49
|
+
const content = (await plugins.smartfs
|
|
50
|
+
.file(packageJsonPath)
|
|
51
|
+
.encoding('utf8')
|
|
52
|
+
.read()) as string;
|
|
53
|
+
const packageJson = JSON.parse(content);
|
|
50
54
|
if (packageJson.name) {
|
|
51
55
|
// Sanitize: @fin.cx/skr → fin-cx-skr
|
|
52
56
|
return packageJson.name.replace(/@/g, '').replace(/[\/\.]/g, '-');
|
|
@@ -55,7 +59,7 @@ export const getProjectName = (): string => {
|
|
|
55
59
|
} catch (error) {
|
|
56
60
|
// Ignore errors and fall back to directory name
|
|
57
61
|
}
|
|
58
|
-
|
|
62
|
+
|
|
59
63
|
return plugins.path.basename(process.cwd());
|
|
60
64
|
};
|
|
61
65
|
|