underpost 2.90.4 → 2.95.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.
Files changed (41) hide show
  1. package/.github/workflows/pwa-microservices-template-page.cd.yml +5 -4
  2. package/.github/workflows/release.cd.yml +7 -7
  3. package/README.md +7 -8
  4. package/bin/build.js +6 -1
  5. package/bin/deploy.js +2 -196
  6. package/cli.md +154 -80
  7. package/manifests/deployment/dd-default-development/deployment.yaml +4 -4
  8. package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
  9. package/package.json +1 -1
  10. package/scripts/disk-clean.sh +216 -0
  11. package/scripts/rocky-setup.sh +1 -0
  12. package/scripts/ssh-cluster-info.sh +4 -3
  13. package/src/cli/cluster.js +1 -1
  14. package/src/cli/db.js +1143 -201
  15. package/src/cli/deploy.js +93 -24
  16. package/src/cli/env.js +2 -2
  17. package/src/cli/image.js +198 -133
  18. package/src/cli/index.js +111 -44
  19. package/src/cli/lxd.js +73 -74
  20. package/src/cli/monitor.js +20 -9
  21. package/src/cli/repository.js +212 -5
  22. package/src/cli/run.js +207 -74
  23. package/src/cli/ssh.js +642 -14
  24. package/src/client/components/core/CommonJs.js +0 -1
  25. package/src/db/mongo/MongooseDB.js +5 -1
  26. package/src/index.js +1 -1
  27. package/src/monitor.js +11 -1
  28. package/src/server/backup.js +1 -1
  29. package/src/server/conf.js +1 -1
  30. package/src/server/dns.js +242 -1
  31. package/src/server/process.js +6 -1
  32. package/src/server/start.js +2 -0
  33. package/scripts/snap-clean.sh +0 -26
  34. package/src/client/public/default/plantuml/client-conf.svg +0 -1
  35. package/src/client/public/default/plantuml/client-schema.svg +0 -1
  36. package/src/client/public/default/plantuml/cron-conf.svg +0 -1
  37. package/src/client/public/default/plantuml/cron-schema.svg +0 -1
  38. package/src/client/public/default/plantuml/server-conf.svg +0 -1
  39. package/src/client/public/default/plantuml/server-schema.svg +0 -1
  40. package/src/client/public/default/plantuml/ssr-conf.svg +0 -1
  41. package/src/client/public/default/plantuml/ssr-schema.svg +0 -1
@@ -10,8 +10,8 @@ import { pbcopy, shellCd, shellExec } from '../server/process.js';
10
10
  import { actionInitLog, loggerFactory } from '../server/logger.js';
11
11
  import fs from 'fs-extra';
12
12
  import { getNpmRootPath } from '../server/conf.js';
13
- import UnderpostStartUp from '../server/start.js';
14
13
  import { Config } from '../server/conf.js';
14
+ import { DefaultConf } from '../../conf.js';
15
15
 
16
16
  dotenv.config();
17
17
 
@@ -234,21 +234,154 @@ class UnderpostRepository {
234
234
  /**
235
235
  * Initializes a new Underpost repository, optionally setting up a deploy ID or sub-configuration.
236
236
  * @param {string} [projectName=''] - The name of the project to create.
237
- * @param {object} [options={ deployId: '', subConf: '', cluster: false, dev: false }] - Initialization options.
237
+ * @param {object} [options] - Initialization options.
238
238
  * @param {string} [options.deployId=''] - The deployment ID to set up.
239
239
  * @param {string} [options.subConf=''] - The sub-configuration to create.
240
240
  * @param {boolean} [options.cluster=false] - If true, sets up a clustered configuration.
241
241
  * @param {boolean} [options.dev=false] - If true, uses development settings.
242
+ * @param {boolean} [options.buildRepos=false] - If true, creates the deployment repositories (engine-*, engine-*-private, engine-*-cron-backups).
243
+ * @param {boolean} [options.purge=false] - If true, removes the deploy ID conf and all related repositories (requires deployId).
244
+ * @param {boolean} [options.cleanTemplate=false] - If true, cleans the pwa-microservices-template build directory.
245
+ * @param {boolean} [options.build=false] - If true, builds the deployment to pwa-microservices-template (requires deployId).
246
+ * @param {boolean} [options.syncConf=false] - If true, syncs configuration to private repositories (requires deployId).
247
+ * @param {boolean} [options.defaultConf=false] - If true, updates the default configuration file (requires deployId).
248
+ * @param {string} [options.confWorkflowId=''] - If provided, uses this configuration workflow ID.
242
249
  * @returns {Promise<boolean>} A promise that resolves when the initialization is complete.
243
250
  * @memberof UnderpostRepository
244
251
  */
245
- new(projectName, options = { deployId: '', subConf: '', cluster: false, dev: false }) {
252
+ new(
253
+ projectName,
254
+ options = {
255
+ deployId: '',
256
+ subConf: '',
257
+ cluster: false,
258
+ dev: false,
259
+ buildRepos: false,
260
+ purge: false,
261
+ cleanTemplate: false,
262
+ build: false,
263
+ syncConf: false,
264
+ defaultConf: false,
265
+ confWorkflowId: '',
266
+ },
267
+ ) {
246
268
  return new Promise(async (resolve, reject) => {
247
269
  try {
248
270
  await logger.setUpInfo();
249
271
  actionInitLog();
272
+
273
+ // Handle cleanTemplate operation
274
+ if (options.cleanTemplate) {
275
+ logger.info('Cleaning build directory');
276
+ const basePath = '../pwa-microservices-template';
277
+ shellExec(`cd ${basePath} && git reset`);
278
+ shellExec(`cd ${basePath} && git checkout .`);
279
+ shellExec(`cd ${basePath} && git clean -f -d`);
280
+ logger.info('Build directory cleaned successfully');
281
+ return resolve(true);
282
+ }
283
+
284
+ // Handle defaultConf operation
285
+ if (options.defaultConf) {
286
+ UnderpostRepository.API.updateDefaultConf(options);
287
+ return resolve(true);
288
+ }
289
+
250
290
  if (options.deployId) {
251
- Config.deployIdFactory(options.deployId, options);
291
+ let deployId = options.deployId;
292
+ if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
293
+ // Handle purge operation
294
+ if (options.purge) {
295
+ logger.info(`Purging deploy ID: ${deployId}`);
296
+
297
+ const suffix = deployId.split('dd-')[1];
298
+ const repoName = `engine-${suffix}`;
299
+ const privateRepoName = `engine-${suffix}-private`;
300
+ const cronRepoName = `engine-${suffix}-cron-backups`;
301
+ const confFolder = `./engine-private/conf/${deployId}`;
302
+
303
+ // Remove conf folder
304
+ if (fs.existsSync(confFolder)) {
305
+ fs.removeSync(confFolder);
306
+ logger.info(`Removed conf folder: ${confFolder}`);
307
+ } else {
308
+ logger.warn(`Conf folder not found: ${confFolder}`);
309
+ }
310
+
311
+ // Remove repositories
312
+ const repos = [
313
+ { path: `../${repoName}`, name: repoName },
314
+ { path: `../${privateRepoName}`, name: privateRepoName },
315
+ { path: `../${cronRepoName}`, name: cronRepoName },
316
+ ];
317
+
318
+ for (const repo of repos) {
319
+ if (fs.existsSync(repo.path)) {
320
+ fs.removeSync(repo.path);
321
+ logger.info(`Removed repository: ${repo.path}`);
322
+ } else {
323
+ logger.warn(`Repository not found: ${repo.path}`);
324
+ }
325
+ }
326
+
327
+ logger.info(`Successfully purged deploy ID: ${deployId}`);
328
+ return resolve(true);
329
+ }
330
+
331
+ // Handle sync-conf operation
332
+ if (options.syncConf) {
333
+ logger.info(`Syncing configuration for deploy ID: ${deployId}`);
334
+ shellExec(`node bin/build ${deployId} conf`);
335
+ logger.info('Configuration synced successfully');
336
+ return resolve(true);
337
+ }
338
+
339
+ // Handle build operation
340
+ if (options.build) {
341
+ logger.info(`Building deployment for deploy ID: ${deployId}`);
342
+ shellExec(`node bin/build ${deployId}`);
343
+ logger.info('Build completed successfully');
344
+ return resolve(true);
345
+ }
346
+
347
+ // Normal deploy ID factory operation
348
+ const { deployId: normalizedDeployId } = Config.deployIdFactory(deployId, options);
349
+
350
+ if (options.buildRepos) {
351
+ const suffix = normalizedDeployId.split('dd-')[1];
352
+ const repoName = `engine-${suffix}`;
353
+ const privateRepoName = `engine-${suffix}-private`;
354
+ const cronRepoName = `engine-${suffix}-cron-backups`;
355
+ const repos = [
356
+ { path: `../${repoName}`, name: repoName },
357
+ { path: `../${privateRepoName}`, name: privateRepoName },
358
+ { path: `../${cronRepoName}`, name: cronRepoName },
359
+ ];
360
+
361
+ const username = process.env.GITHUB_USERNAME;
362
+ const token = process.env.GITHUB_TOKEN;
363
+
364
+ if (!username) {
365
+ logger.error('GITHUB_USERNAME environment variable not set');
366
+ return reject(false);
367
+ }
368
+
369
+ for (const repo of repos) {
370
+ if (!fs.existsSync(repo.path)) {
371
+ fs.mkdirSync(repo.path, { recursive: true });
372
+ logger.info(`Created repository directory: ${repo.path}`);
373
+ }
374
+
375
+ // Initialize git repository
376
+ shellExec(`cd ${repo.path} && git init`, { disableLog: false });
377
+ logger.info(`Initialized git repository in: ${repo.path}`);
378
+
379
+ // Add remote origin
380
+ const remoteUrl = `https://${token ? `${token}@` : ''}github.com/${username}/${repo.name}.git`;
381
+ shellExec(`cd ${repo.path} && git remote add origin ${remoteUrl}`, { disableLog: false });
382
+ logger.info(`Added remote origin for: ${repo.name}`);
383
+ }
384
+ }
252
385
  return resolve(true);
253
386
  }
254
387
  if (projectName) {
@@ -326,7 +459,9 @@ class UnderpostRepository {
326
459
  const privateRepoPath = `../${privateRepoName}`;
327
460
  if (fs.existsSync(privateRepoPath)) fs.removeSync(privateRepoPath);
328
461
  shellExec(`cd .. && underpost clone ${process.env.GITHUB_USERNAME}/${privateRepoName}`);
329
- shellExec(`cd ${privateRepoPath} && underpost pull . ${process.env.GITHUB_USERNAME}/${privateRepoName}`);
462
+ shellExec(`cd ${privateRepoPath} && underpost pull . ${process.env.GITHUB_USERNAME}/${privateRepoName}`, {
463
+ silent: true,
464
+ });
330
465
  shellExec(`underpost run secret`);
331
466
  shellExec(`underpost run underpost-config`);
332
467
  const packageJsonDeploy = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
@@ -380,6 +515,78 @@ Prevent build private config repo.`,
380
515
  return line;
381
516
  });
382
517
  },
518
+ /**
519
+ * Updates the default configuration file based on the provided options.
520
+ * @param {object} [options={ deployId: '' }] - The options for updating the configuration.
521
+ * @param {string} [options.deployId=''] - The deployment ID to use for configuration.
522
+ * @param {string} [options.confWorkflowId=''] - The configuration workflow ID to use.
523
+ * @memberof UnderpostRepository
524
+ */
525
+ updateDefaultConf(options = { deployId: '', confWorkflowId: '' }) {
526
+ const defaultServer = DefaultConf.server['default.net']['/'];
527
+ let { deployId, confWorkflowId } = options;
528
+ let defaultConf = false;
529
+
530
+ // Custom workflow configurations
531
+ if (confWorkflowId)
532
+ switch (confWorkflowId) {
533
+ case 'dd-github-pages': {
534
+ const host = `${process.env.GITHUB_USERNAME ? process.env.GITHUB_USERNAME : 'underpostnet'}.github.io`;
535
+ const path = '/pwa-microservices-template-ghpkg';
536
+ DefaultConf.server = {
537
+ [host]: { [path]: defaultServer },
538
+ };
539
+ DefaultConf.server[host][path].apiBaseProxyPath = '/';
540
+ DefaultConf.server[host][path].apiBaseHost = 'www.nexodev.org';
541
+ defaultConf = true;
542
+ break;
543
+ }
544
+ case 'template': {
545
+ const host = 'default.net';
546
+ const path = '/';
547
+ DefaultConf.server[host][path].valkey = {
548
+ port: 6379,
549
+ host: 'valkey-service.default.svc.cluster.local',
550
+ };
551
+ // mongodb-0.mongodb-service
552
+ DefaultConf.server[host][path].db.host = 'mongodb://mongodb-service:27017';
553
+ defaultConf = true;
554
+ break;
555
+ }
556
+ default:
557
+ logger.error(`Unknown confWorkflowId: ${confWorkflowId}.`);
558
+ return;
559
+ }
560
+ else if (deployId && fs.existsSync(`./engine-private/conf/${deployId}`)) {
561
+ DefaultConf.client = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
562
+ DefaultConf.server = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
563
+ DefaultConf.ssr = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
564
+ // DefaultConf.cron = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.cron.json`, 'utf8'));
565
+
566
+ for (const host of Object.keys(DefaultConf.server)) {
567
+ for (const path of Object.keys(DefaultConf.server[host])) {
568
+ DefaultConf.server[host][path].db = defaultServer.db;
569
+ DefaultConf.server[host][path].mailer = defaultServer.mailer;
570
+
571
+ delete DefaultConf.server[host][path]._wp_client;
572
+ delete DefaultConf.server[host][path]._wp_git;
573
+ delete DefaultConf.server[host][path]._wp_directory;
574
+ delete DefaultConf.server[host][path].wp;
575
+ delete DefaultConf.server[host][path].git;
576
+ delete DefaultConf.server[host][path].directory;
577
+ }
578
+ }
579
+ } else
580
+ logger.warn(
581
+ `Deploy ID configuration not found: ./engine-private/conf/${deployId}, using default configuration.`,
582
+ );
583
+ const sepRender = '/**/';
584
+ const confRawPaths = fs.readFileSync('./conf.js', 'utf8').split(sepRender);
585
+ confRawPaths[1] = `${JSON.stringify(DefaultConf)};`;
586
+ const targetConfPath = `./conf${defaultConf ? '' : `.${deployId}`}.js`;
587
+ fs.writeFileSync(targetConfPath, confRawPaths.join(sepRender), 'utf8');
588
+ shellExec(`prettier --write ${targetConfPath}`);
589
+ },
383
590
  };
384
591
  }
385
592