@underpostnet/underpost 3.0.3 → 3.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/{.env.production → .env.example} +20 -2
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +22 -7
- package/.github/workflows/publish.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +3 -2
- package/.vscode/extensions.json +9 -8
- package/.vscode/settings.json +3 -2
- package/CHANGELOG.md +146 -1
- package/CLI-HELP.md +71 -52
- package/README.md +2 -2
- package/bin/build.js +4 -1
- package/bin/deploy.js +150 -208
- package/bin/file.js +2 -1
- package/bin/vs.js +3 -3
- package/conf.js +30 -13
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/pv-pvc-dd.yaml +1 -1
- package/package.json +48 -43
- package/scripts/k3s-node-setup.sh +1 -1
- package/src/api/document/document.service.js +1 -1
- package/src/api/file/file.controller.js +3 -1
- package/src/api/file/file.service.js +28 -5
- package/src/api/user/user.router.js +10 -5
- package/src/api/user/user.service.js +7 -7
- package/src/cli/baremetal.js +6 -10
- package/src/cli/cloud-init.js +0 -3
- package/src/cli/db.js +54 -71
- package/src/cli/deploy.js +64 -12
- package/src/cli/env.js +4 -4
- package/src/cli/fs.js +0 -2
- package/src/cli/image.js +0 -3
- package/src/cli/index.js +27 -13
- package/src/cli/monitor.js +5 -6
- package/src/cli/repository.js +322 -35
- package/src/cli/run.js +118 -69
- package/src/cli/secrets.js +0 -3
- package/src/cli/ssh.js +1 -1
- package/src/client/components/core/AgGrid.js +20 -5
- package/src/client/components/core/Content.js +22 -3
- package/src/client/components/core/Docs.js +21 -4
- package/src/client/components/core/FileExplorer.js +71 -4
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Modal.js +20 -6
- package/src/client/public/default/sitemap +3 -3
- package/src/client/public/test/sitemap +3 -3
- package/src/client.build.js +0 -3
- package/src/client.dev.js +0 -3
- package/src/db/DataBaseProvider.js +17 -2
- package/src/db/mariadb/MariaDB.js +14 -9
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/index.js +1 -1
- package/src/proxy.js +0 -3
- package/src/runtime/express/Express.js +7 -1
- package/src/runtime/lampp/Lampp.js +6 -13
- package/src/server/auth.js +6 -9
- package/src/server/backup.js +2 -3
- package/src/server/client-build-docs.js +178 -3
- package/src/server/client-build-live.js +9 -18
- package/src/server/client-build.js +175 -38
- package/src/server/client-dev-server.js +14 -13
- package/src/server/conf.js +357 -149
- package/src/server/cron.js +2 -1
- package/src/server/dns.js +28 -12
- package/src/server/downloader.js +0 -2
- package/src/server/logger.js +27 -9
- package/src/server/peer.js +0 -2
- package/src/server/process.js +1 -50
- package/src/server/proxy.js +4 -8
- package/src/server/runtime.js +5 -8
- package/src/server/ssr.js +0 -3
- package/src/server/start.js +5 -5
- package/src/server/tls.js +0 -2
- package/src/server.js +0 -4
- package/.env.development +0 -43
- package/.env.test +0 -43
package/src/cli/run.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* @namespace UnderpostRun
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { daemonProcess, getTerminalPid,
|
|
7
|
+
import { daemonProcess, getTerminalPid, shellCd, shellExec } from '../server/process.js';
|
|
8
8
|
import {
|
|
9
9
|
awaitDeployMonitor,
|
|
10
10
|
buildKindPorts,
|
|
11
11
|
Config,
|
|
12
12
|
getNpmRootPath,
|
|
13
13
|
isDeployRunnerContext,
|
|
14
|
+
loadConfServerJson,
|
|
14
15
|
writeEnv,
|
|
15
16
|
} from '../server/conf.js';
|
|
16
17
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
@@ -55,7 +56,6 @@ const logger = loggerFactory(import.meta);
|
|
|
55
56
|
* @property {string} apiVersion - The API version for the container.
|
|
56
57
|
* @property {string} claimName - The claim name for the volume.
|
|
57
58
|
* @property {string} kindType - The kind of resource to create.
|
|
58
|
-
* @property {boolean} terminal - Whether to open a terminal.
|
|
59
59
|
* @property {number} devProxyPortOffset - The port offset for the development proxy.
|
|
60
60
|
* @property {boolean} hostNetwork - Whether to use host networking.
|
|
61
61
|
* @property {string} requestsMemory - The memory request for the container.
|
|
@@ -120,7 +120,6 @@ const DEFAULT_OPTION = {
|
|
|
120
120
|
apiVersion: '',
|
|
121
121
|
claimName: '',
|
|
122
122
|
kindType: '',
|
|
123
|
-
terminal: false,
|
|
124
123
|
devProxyPortOffset: 0,
|
|
125
124
|
hostNetwork: false,
|
|
126
125
|
requestsMemory: '',
|
|
@@ -195,7 +194,7 @@ class UnderpostRun {
|
|
|
195
194
|
}
|
|
196
195
|
|
|
197
196
|
{
|
|
198
|
-
// Detect MongoDB primary pod using
|
|
197
|
+
// Detect MongoDB primary pod using method
|
|
199
198
|
let primaryMongoHost = 'mongodb-0.mongodb-service';
|
|
200
199
|
try {
|
|
201
200
|
const primaryPodName = Underpost.db.getMongoPrimaryPodName({
|
|
@@ -355,22 +354,35 @@ class UnderpostRun {
|
|
|
355
354
|
},
|
|
356
355
|
/**
|
|
357
356
|
* @method template-deploy
|
|
358
|
-
* @description
|
|
357
|
+
* @description Pushes `engine-private`, dispatches CI workflow to build `pwa-microservices-template`, and optionally dispatches CD sync workflow.
|
|
359
358
|
* @param {string} path - The input value, identifier, or path for the operation.
|
|
360
359
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
361
360
|
* @memberof UnderpostRun
|
|
362
361
|
*/
|
|
363
362
|
'template-deploy': (path = '', options = DEFAULT_OPTION) => {
|
|
364
363
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
364
|
+
shellExec(`npm run security:secrets`);
|
|
365
|
+
const reportPath = './gitleaks-report.json';
|
|
366
|
+
if (fs.existsSync(reportPath) && JSON.parse(fs.readFileSync(reportPath, 'utf8')).length > 0) {
|
|
367
|
+
logger.error('Secrets detected in gitleaks-report.json, aborting template-deploy');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
shellExec(`${baseCommand} run pull`);
|
|
365
371
|
const message = shellExec(`node bin cmt --changelog --changelog-no-hash`, { silent: true, stdout: true }).trim();
|
|
366
|
-
shellExec(`${baseCommand} run clean`);
|
|
367
372
|
shellExec(
|
|
368
373
|
`${baseCommand} push ./engine-private ${options.force ? '-f ' : ''}${
|
|
369
374
|
process.env.GITHUB_USERNAME
|
|
370
375
|
}/engine-private`,
|
|
371
376
|
);
|
|
372
377
|
shellCd('/home/dd/engine');
|
|
373
|
-
|
|
378
|
+
|
|
379
|
+
// Store deploy boundary hash for changelog before dispatch
|
|
380
|
+
const deployBoundaryHash = shellExec('git rev-parse HEAD', {
|
|
381
|
+
stdout: true,
|
|
382
|
+
silent: true,
|
|
383
|
+
disableLog: true,
|
|
384
|
+
}).trim();
|
|
385
|
+
|
|
374
386
|
function replaceNthNewline(str, n, replacement = ' ') {
|
|
375
387
|
let count = 0;
|
|
376
388
|
return str.replace(/\r\n?|\n/g, (match) => {
|
|
@@ -378,35 +390,54 @@ class UnderpostRun {
|
|
|
378
390
|
return count === n ? replacement : match;
|
|
379
391
|
});
|
|
380
392
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
)}"`
|
|
390
|
-
: ''
|
|
391
|
-
}`,
|
|
392
|
-
);
|
|
393
|
+
const sanitizedMessage = message
|
|
394
|
+
? replaceNthNewline(message.replaceAll('"', '').replaceAll('`', '').replaceAll('#', '').replaceAll('- ', ''), 2)
|
|
395
|
+
.replace(/\r\n?|\n/g, ' ')
|
|
396
|
+
.trim()
|
|
397
|
+
: '';
|
|
398
|
+
|
|
399
|
+
// Push engine repo so workflow YAML changes reach GitHub
|
|
400
|
+
shellExec(`git reset`);
|
|
393
401
|
shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
|
|
402
|
+
|
|
403
|
+
// Dispatch CI workflow instead of empty commit + push
|
|
404
|
+
const repo = `${process.env.GITHUB_USERNAME}/engine`;
|
|
405
|
+
Underpost.repo.dispatchWorkflow({
|
|
406
|
+
repo,
|
|
407
|
+
workflowFile: 'npmpkg.ci.yml',
|
|
408
|
+
ref: 'master',
|
|
409
|
+
inputs: sanitizedMessage ? { message: sanitizedMessage } : {},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Dispatch CD sync-and-deploy if path starts with 'sync'
|
|
413
|
+
if (path.startsWith('sync')) {
|
|
414
|
+
const confId = path.replace(/^sync-/, '');
|
|
415
|
+
Underpost.repo.dispatchWorkflow({
|
|
416
|
+
repo,
|
|
417
|
+
workflowFile: `${confId}.cd.yml`,
|
|
418
|
+
ref: 'master',
|
|
419
|
+
inputs: { job: 'sync-and-deploy' },
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Store deploy boundary for changelog
|
|
424
|
+
shellExec(`${baseCommand} config set LAST_CI_DEPLOY_HASH ${deployBoundaryHash}`);
|
|
394
425
|
},
|
|
395
426
|
|
|
396
427
|
/**
|
|
397
428
|
* @method template-deploy-image
|
|
398
|
-
* @description
|
|
429
|
+
* @description Dispatches the Docker image CI workflow for the `engine` repository.
|
|
399
430
|
* @param {string} path - The input value, identifier, or path for the operation.
|
|
400
431
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
401
432
|
* @memberof UnderpostRun
|
|
402
433
|
*/
|
|
403
434
|
'template-deploy-image': (path, options = DEFAULT_OPTION) => {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
);
|
|
435
|
+
Underpost.repo.dispatchWorkflow({
|
|
436
|
+
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
437
|
+
workflowFile: 'docker-image.ci.yml',
|
|
438
|
+
ref: 'master',
|
|
439
|
+
inputs: {},
|
|
440
|
+
});
|
|
410
441
|
},
|
|
411
442
|
/**
|
|
412
443
|
* @method clean
|
|
@@ -467,18 +498,30 @@ class UnderpostRun {
|
|
|
467
498
|
},
|
|
468
499
|
/**
|
|
469
500
|
* @method ssh-deploy
|
|
470
|
-
* @description
|
|
471
|
-
* @param {string} path - The
|
|
501
|
+
* @description Dispatches the corresponding CD workflow for SSH-based deployment, replacing empty commits with workflow_dispatch.
|
|
502
|
+
* @param {string} path - The deployment identifier (e.g., 'engine-core', 'sync-engine-core', 'init-engine-core').
|
|
472
503
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
473
504
|
* @memberof UnderpostRun
|
|
474
505
|
*/
|
|
475
506
|
'ssh-deploy': (path, options = DEFAULT_OPTION) => {
|
|
476
507
|
actionInitLog();
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
508
|
+
|
|
509
|
+
let job = 'deploy';
|
|
510
|
+
let confId = path;
|
|
511
|
+
if (path.startsWith('sync-')) {
|
|
512
|
+
job = 'sync-and-deploy';
|
|
513
|
+
confId = path.replace(/^sync-/, '');
|
|
514
|
+
} else if (path.startsWith('init-')) {
|
|
515
|
+
job = 'init';
|
|
516
|
+
confId = path.replace(/^init-/, '');
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
Underpost.repo.dispatchWorkflow({
|
|
520
|
+
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
521
|
+
workflowFile: `${confId}.cd.yml`,
|
|
522
|
+
ref: 'master',
|
|
523
|
+
inputs: { job },
|
|
524
|
+
});
|
|
482
525
|
},
|
|
483
526
|
/**
|
|
484
527
|
* @method ide
|
|
@@ -488,15 +531,25 @@ class UnderpostRun {
|
|
|
488
531
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
489
532
|
* @memberof UnderpostRun
|
|
490
533
|
*/
|
|
491
|
-
ide: (path, options = DEFAULT_OPTION) => {
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
shellExec(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
534
|
+
ide: (path = '', options = DEFAULT_OPTION) => {
|
|
535
|
+
const underpostRoot = options.dev ? '.' : options.underpostRoot;
|
|
536
|
+
const [projectPath, customIde] = path.split(',');
|
|
537
|
+
if (projectPath === 'install') {
|
|
538
|
+
if (customIde === 'zed') shellExec(`sudo curl -f https://zed.dev/install.sh | sh`);
|
|
539
|
+
else if (customIde === 'subl') {
|
|
540
|
+
shellExec(
|
|
541
|
+
`sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo`,
|
|
542
|
+
);
|
|
543
|
+
shellExec(`sudo dnf install -y sublime-text`);
|
|
544
|
+
} else {
|
|
545
|
+
shellExec(`sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc &&
|
|
546
|
+
echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/vscode.repo > /dev/null`);
|
|
547
|
+
shellExec(`sudo dnf install -y code`);
|
|
548
|
+
}
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (customIde === 'zed') shellExec(`node ${underpostRoot}/bin/zed ${projectPath}`);
|
|
552
|
+
else shellExec(`node ${underpostRoot}/bin/vs ${projectPath}`);
|
|
500
553
|
},
|
|
501
554
|
/**
|
|
502
555
|
* @method crypto-policy
|
|
@@ -525,7 +578,7 @@ class UnderpostRun {
|
|
|
525
578
|
options.replicas,
|
|
526
579
|
``,
|
|
527
580
|
``,
|
|
528
|
-
options.
|
|
581
|
+
!options.kubeadm && !options.k3s ? 'kind-control-plane' : os.hostname(),
|
|
529
582
|
];
|
|
530
583
|
let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
|
|
531
584
|
deployId = deployId ? deployId : defaultPath[0];
|
|
@@ -1008,9 +1061,7 @@ EOF
|
|
|
1008
1061
|
volumeMountPath: volumeHostPath,
|
|
1009
1062
|
...(options.dev ? { volumeHostPath } : { claimName }),
|
|
1010
1063
|
on: {
|
|
1011
|
-
init: async () => {
|
|
1012
|
-
// openTerminal(`kubectl logs -f ${podName}`);
|
|
1013
|
-
},
|
|
1064
|
+
init: async () => {},
|
|
1014
1065
|
},
|
|
1015
1066
|
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
|
|
1016
1067
|
};
|
|
@@ -1145,7 +1196,7 @@ EOF
|
|
|
1145
1196
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
1146
1197
|
let hosts = [];
|
|
1147
1198
|
for (const deployId of deployList) {
|
|
1148
|
-
const confServer =
|
|
1199
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1149
1200
|
hosts = hosts.concat(Object.keys(confServer));
|
|
1150
1201
|
}
|
|
1151
1202
|
shellExec(`node bin cluster --prom ${hosts.join(',')}`);
|
|
@@ -1318,34 +1369,31 @@ EOF
|
|
|
1318
1369
|
if (!subConf) subConf = 'local';
|
|
1319
1370
|
if (options.reset && fs.existsSync(`./engine-private/conf/${deployId}`))
|
|
1320
1371
|
fs.removeSync(`./engine-private/conf/${deployId}`);
|
|
1321
|
-
if (!fs.existsSync(`./engine-private/conf/${deployId}`)) Config.deployIdFactory(deployId, { subConf });
|
|
1322
1372
|
if (options.devProxyPortOffset) {
|
|
1323
1373
|
const envPath = `./engine-private/conf/${deployId}/.env.development`;
|
|
1324
1374
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
1325
1375
|
envObj.DEV_PROXY_PORT_OFFSET = options.devProxyPortOffset;
|
|
1326
1376
|
writeEnv(envPath, envObj);
|
|
1327
1377
|
}
|
|
1378
|
+
dotenv.config({ path: `./engine-private/conf/${deployId}/.env.development`, override: true });
|
|
1328
1379
|
shellExec(`node bin run dev-cluster --expose --namespace ${options.namespace}`, { async: true });
|
|
1329
1380
|
{
|
|
1330
|
-
const cmd = `npm run dev
|
|
1381
|
+
const cmd = `npm run dev:api ${deployId} ${subConf} ${host} ${_path} ${clientHostPort} proxy${
|
|
1331
1382
|
options.tls ? ' tls' : ''
|
|
1332
1383
|
}`;
|
|
1333
|
-
|
|
1384
|
+
shellExec(cmd, { async: true });
|
|
1334
1385
|
}
|
|
1335
1386
|
await awaitDeployMonitor(true);
|
|
1336
1387
|
{
|
|
1337
|
-
const cmd = `npm run dev
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
:
|
|
1341
|
-
|
|
1342
|
-
});
|
|
1388
|
+
const cmd = `npm run dev:client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
|
|
1389
|
+
|
|
1390
|
+
shellExec(cmd, {
|
|
1391
|
+
async: true,
|
|
1392
|
+
});
|
|
1343
1393
|
}
|
|
1344
1394
|
await awaitDeployMonitor(true);
|
|
1345
1395
|
shellExec(
|
|
1346
|
-
|
|
1347
|
-
options.tls ? ' tls' : ''
|
|
1348
|
-
}`,
|
|
1396
|
+
`NODE_ENV=development node src/proxy proxy ${deployId} ${subConf} ${host} ${_path}${options.tls ? ' tls' : ''}`,
|
|
1349
1397
|
);
|
|
1350
1398
|
},
|
|
1351
1399
|
|
|
@@ -1364,7 +1412,7 @@ EOF
|
|
|
1364
1412
|
let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
|
|
1365
1413
|
if (!replicas) replicas = options.replicas;
|
|
1366
1414
|
// const confClient = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
|
|
1367
|
-
const confServer =
|
|
1415
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1368
1416
|
// const confSSR = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
|
|
1369
1417
|
// const packageData = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
|
|
1370
1418
|
const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
|
|
@@ -1455,9 +1503,7 @@ EOF
|
|
|
1455
1503
|
'etc-hosts': async (path = '', options = DEFAULT_OPTION) => {
|
|
1456
1504
|
const hosts = path ? path.split(',') : [];
|
|
1457
1505
|
if (options.deployId) {
|
|
1458
|
-
const confServer =
|
|
1459
|
-
fs.readFileSync(`./engine-private/conf/${options.deployId}/conf.server.json`, 'utf8'),
|
|
1460
|
-
);
|
|
1506
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${options.deployId}/conf.server.json`);
|
|
1461
1507
|
hosts.push(...Object.keys(confServer));
|
|
1462
1508
|
}
|
|
1463
1509
|
const hostListenResult = Underpost.deploy.etcHostFactory(hosts);
|
|
@@ -1572,7 +1618,7 @@ EOF
|
|
|
1572
1618
|
`npm install -g npm@11.2.0`,
|
|
1573
1619
|
`npm install -g underpost`,
|
|
1574
1620
|
`${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
|
|
1575
|
-
`${baseCommand} start --build --run ${deployId} ${env}
|
|
1621
|
+
`${baseCommand} start --build --run ${deployId} ${env}`,
|
|
1576
1622
|
];
|
|
1577
1623
|
shellExec(`node bin run sync${baseClusterCommand} --deploy-id-cron-jobs none dd-test --cmd "${cmd}"`);
|
|
1578
1624
|
},
|
|
@@ -1591,19 +1637,22 @@ EOF
|
|
|
1591
1637
|
for (let deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
1592
1638
|
deployId = deployId.trim();
|
|
1593
1639
|
const _path = '/single-replica';
|
|
1594
|
-
const confServer =
|
|
1640
|
+
const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
|
|
1595
1641
|
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
1596
1642
|
for (const host of Object.keys(confServer))
|
|
1597
|
-
if (_path in confServer[host])
|
|
1643
|
+
if (_path in confServer[host])
|
|
1644
|
+
await Underpost.repo.client(deployId, '', host, _path, {
|
|
1645
|
+
singleReplica: true,
|
|
1646
|
+
});
|
|
1598
1647
|
const node = options.nodeName
|
|
1599
1648
|
? options.nodeName
|
|
1600
|
-
: options.
|
|
1649
|
+
: !options.kubeadm && !options.k3s
|
|
1601
1650
|
? 'kind-control-plane'
|
|
1602
1651
|
: os.hostname();
|
|
1603
1652
|
// deployId, replicas, versions, image, node
|
|
1604
1653
|
let defaultPath = [deployId, 1, ``, ``, node];
|
|
1605
1654
|
shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
|
|
1606
|
-
|
|
1655
|
+
await Underpost.repo.client(deployId);
|
|
1607
1656
|
}
|
|
1608
1657
|
if (isDeployRunnerContext(path, options)) shellExec(`${baseCommand} run promote ${path} production`);
|
|
1609
1658
|
},
|
|
@@ -1680,7 +1729,7 @@ EOF
|
|
|
1680
1729
|
shellExec(`sudo kubectl cp ${nameSpace}/${podName}:${basePath}/docs${fromPath} ${toPath}`);
|
|
1681
1730
|
}
|
|
1682
1731
|
|
|
1683
|
-
|
|
1732
|
+
shellExec(`firefox ${outsPaths.join(' ')}`);
|
|
1684
1733
|
process.exit(0);
|
|
1685
1734
|
}
|
|
1686
1735
|
})();
|
package/src/cli/secrets.js
CHANGED
|
@@ -4,13 +4,10 @@
|
|
|
4
4
|
* @namespace UnderpostSecret
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import dotenv from 'dotenv';
|
|
8
7
|
import { shellExec } from '../server/process.js';
|
|
9
8
|
import fs from 'fs-extra';
|
|
10
9
|
import Underpost from '../index.js';
|
|
11
10
|
|
|
12
|
-
dotenv.config();
|
|
13
|
-
|
|
14
11
|
/**
|
|
15
12
|
* @class UnderpostSecret
|
|
16
13
|
* @description Manages the secrets of the application.
|
package/src/cli/ssh.js
CHANGED
|
@@ -497,7 +497,7 @@ EOF`);
|
|
|
497
497
|
},
|
|
498
498
|
|
|
499
499
|
/**
|
|
500
|
-
* Generic SSH remote command runner that
|
|
500
|
+
* Generic SSH remote command runner that SSH execution logic.
|
|
501
501
|
* Executes arbitrary shell commands on a remote server via SSH with proper credential handling.
|
|
502
502
|
* @async
|
|
503
503
|
* @function sshRemoteRunner
|
|
@@ -13,20 +13,32 @@ const AgGrid = {
|
|
|
13
13
|
Render: async function (options) {
|
|
14
14
|
let { id, paginationOptions } = options;
|
|
15
15
|
setTimeout(() => {
|
|
16
|
+
// Normalize rowSelection from deprecated string form to object form (AG Grid v32.2.1+)
|
|
17
|
+
let gridOptionsOverrides = { ...(options.gridOptions || {}) };
|
|
18
|
+
if (typeof gridOptionsOverrides.rowSelection === 'string') {
|
|
19
|
+
const mode = gridOptionsOverrides.rowSelection; // 'single' or 'multiple'
|
|
20
|
+
gridOptionsOverrides.rowSelection = {
|
|
21
|
+
mode: mode === 'multiple' ? 'multiRow' : 'singleRow',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
// Grid Options: Contains all of the grid configurations
|
|
17
26
|
const gridOptions = {
|
|
27
|
+
// Use legacy CSS theme mode to avoid conflict with Theming API (AG Grid v33+)
|
|
28
|
+
theme: 'legacy',
|
|
18
29
|
// Row Data: The data to be displayed.
|
|
19
30
|
pagination: false, // Disabled by default, will be handled by the management view
|
|
20
31
|
// paginationPageSize: 100,
|
|
21
32
|
// suppressPaginationPanel: true, // We are using our own custom pagination component
|
|
22
33
|
// rowHeight: 60,
|
|
23
|
-
enableCellChangeFlash
|
|
34
|
+
// enableCellChangeFlash was removed in v35; use enableCellChangeFlash on defaultColDef instead
|
|
24
35
|
defaultColDef: {
|
|
25
36
|
editable: false,
|
|
26
37
|
flex: 1,
|
|
27
38
|
minWidth: 50,
|
|
28
39
|
filter: true,
|
|
29
40
|
autoHeight: true,
|
|
41
|
+
enableCellChangeFlash: true,
|
|
30
42
|
},
|
|
31
43
|
rowClassRules: {
|
|
32
44
|
'row-new-highlight': (params) => {
|
|
@@ -76,7 +88,7 @@ const AgGrid = {
|
|
|
76
88
|
return { field };
|
|
77
89
|
})
|
|
78
90
|
: [],
|
|
79
|
-
...
|
|
91
|
+
...gridOptionsOverrides,
|
|
80
92
|
};
|
|
81
93
|
|
|
82
94
|
// Your Javascript code to create the grid
|
|
@@ -86,8 +98,11 @@ const AgGrid = {
|
|
|
86
98
|
// myGridElement.style.setProperty('width', '100%');
|
|
87
99
|
ThemeEvents[id] = () => {
|
|
88
100
|
if (s(`.${id}`)) {
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
// darkTheme has already been updated by Css.js when this event fires
|
|
102
|
+
// If darkTheme is true: remove light class, add dark class
|
|
103
|
+
// If darkTheme is false: remove dark class, add light class
|
|
104
|
+
s(`.${id}`).classList.remove(this.theme, this.theme + '-dark');
|
|
105
|
+
s(`.${id}`).classList.add(darkTheme ? this.theme + '-dark' : this.theme);
|
|
91
106
|
} else {
|
|
92
107
|
// console.warn('change theme: grid not found');
|
|
93
108
|
delete ThemeEvents[id];
|
|
@@ -112,7 +127,7 @@ const AgGrid = {
|
|
|
112
127
|
: '';
|
|
113
128
|
return html`
|
|
114
129
|
<div
|
|
115
|
-
class="${id} ${this.theme
|
|
130
|
+
class="${id} ${darkTheme ? this.theme + '-dark' : this.theme}"
|
|
116
131
|
style="${options?.style
|
|
117
132
|
? Object.keys(options.style).map((styleKey) => `${styleKey}: ${options.style[styleKey]}; `)
|
|
118
133
|
: ''}"
|
|
@@ -56,7 +56,7 @@ const attachMarkdownLinkHandlers = (containerSelector) => {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
const Content = {
|
|
59
|
-
Render: async function (options = { idModal: '' }) {
|
|
59
|
+
Render: async function (options = { idModal: '', titleIcon: '' }) {
|
|
60
60
|
const { idModal } = options;
|
|
61
61
|
setTimeout(async () => {
|
|
62
62
|
try {
|
|
@@ -111,11 +111,30 @@ const Content = {
|
|
|
111
111
|
throw new Error(`no-preview-available`);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// Use custom titleIcon from options, or extract from the modal's original title HTML, or fall back to default
|
|
115
|
+
const titleIcon = options.titleIcon
|
|
116
|
+
? options.titleIcon
|
|
117
|
+
: Modal.Data[idModal] &&
|
|
118
|
+
Modal.Data[idModal].options &&
|
|
119
|
+
Modal.Data[idModal].options.title &&
|
|
120
|
+
Modal.Data[idModal].options.title.includes &&
|
|
121
|
+
Modal.Data[idModal].options.title.includes('<img')
|
|
122
|
+
? Modal.Data[idModal].options.title.match(/<img[^>]*>/)?.[0] || html`<i class="inl far fa-file"></i>`
|
|
123
|
+
: html`<i class="inl far fa-file"></i>`;
|
|
124
|
+
|
|
125
|
+
// Preserve the original text wrapper class if present in the modal's stored title
|
|
126
|
+
const originalTitle = Modal.Data[idModal]?.options?.title || '';
|
|
127
|
+
const hasCustomTextClass = originalTitle.includes && originalTitle.includes('underpost-text-title-modal');
|
|
128
|
+
const docTitle = documentObj.title ? documentObj.title : documentObj.location;
|
|
129
|
+
const titleText = hasCustomTextClass
|
|
130
|
+
? `<span class='inl underpost-text-title-modal'>${docTitle}</span>`
|
|
131
|
+
: docTitle;
|
|
132
|
+
|
|
114
133
|
htmls(
|
|
115
134
|
`.title-modal-${idModal}`,
|
|
116
135
|
html`${renderViewTitle({
|
|
117
|
-
icon:
|
|
118
|
-
text:
|
|
136
|
+
icon: titleIcon,
|
|
137
|
+
text: titleText,
|
|
119
138
|
})} `,
|
|
120
139
|
);
|
|
121
140
|
htmls(`.content-render-${idModal}`, ``);
|
|
@@ -12,6 +12,10 @@ const Docs = {
|
|
|
12
12
|
const docData = this.Data.find((d) => d.type === type);
|
|
13
13
|
const ModalId = `modal-docs-${docData.type}`;
|
|
14
14
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
15
|
+
const parentBarMode =
|
|
16
|
+
Modal.Data['modal-docs'] && Modal.Data['modal-docs'].options.barMode
|
|
17
|
+
? Modal.Data['modal-docs'].options.barMode
|
|
18
|
+
: undefined;
|
|
15
19
|
|
|
16
20
|
await Modal.Render({
|
|
17
21
|
barConfig,
|
|
@@ -34,7 +38,7 @@ const Docs = {
|
|
|
34
38
|
route: 'docs',
|
|
35
39
|
slideMenu: 'modal-menu',
|
|
36
40
|
observer: true,
|
|
37
|
-
barMode:
|
|
41
|
+
barMode: parentBarMode,
|
|
38
42
|
query: true,
|
|
39
43
|
RouterInstance: Modal.Data['modal-docs'].options.RouterInstance,
|
|
40
44
|
});
|
|
@@ -166,6 +170,8 @@ const Docs = {
|
|
|
166
170
|
icon: html`<i class="fab fa-github"></i>`,
|
|
167
171
|
text: `Last Release`,
|
|
168
172
|
url: function () {
|
|
173
|
+
const tokenOpts = Docs.Tokens['modal-docs'];
|
|
174
|
+
if (tokenOpts && tokenOpts.lastReleaseUrl) return tokenOpts.lastReleaseUrl();
|
|
169
175
|
return `https://github.com/underpostnet/pwa-microservices-template-ghpkg/`;
|
|
170
176
|
},
|
|
171
177
|
},
|
|
@@ -180,6 +186,8 @@ const Docs = {
|
|
|
180
186
|
</svg>`,
|
|
181
187
|
text: html`Demo`,
|
|
182
188
|
url: function () {
|
|
189
|
+
const tokenOpts = Docs.Tokens['modal-docs'];
|
|
190
|
+
if (tokenOpts && tokenOpts.demoUrl) return tokenOpts.demoUrl();
|
|
183
191
|
return `https://underpostnet.github.io/pwa-microservices-template-ghpkg/`;
|
|
184
192
|
},
|
|
185
193
|
},
|
|
@@ -204,6 +212,8 @@ const Docs = {
|
|
|
204
212
|
icon: html`<img height="20" width="20" class="doc-icon-coverage" />`,
|
|
205
213
|
text: `Coverage report`,
|
|
206
214
|
url: function () {
|
|
215
|
+
const tokenOpts = Docs.Tokens['modal-docs'];
|
|
216
|
+
if (tokenOpts && tokenOpts.coverageUrl) return tokenOpts.coverageUrl();
|
|
207
217
|
return `${getProxyPath()}docs/coverage`;
|
|
208
218
|
},
|
|
209
219
|
themeEvent: () => {
|
|
@@ -223,7 +233,7 @@ const Docs = {
|
|
|
223
233
|
},
|
|
224
234
|
],
|
|
225
235
|
Tokens: {},
|
|
226
|
-
Init: async function (options) {
|
|
236
|
+
Init: async function (options = {}) {
|
|
227
237
|
const { idModal } = options;
|
|
228
238
|
this.Tokens[idModal] = options;
|
|
229
239
|
setTimeout(() => {
|
|
@@ -284,10 +294,14 @@ const Docs = {
|
|
|
284
294
|
break;
|
|
285
295
|
}
|
|
286
296
|
tabHref = docData.url();
|
|
297
|
+
const subMenuIcon =
|
|
298
|
+
options.subMenuIcon && typeof options.subMenuIcon === 'function'
|
|
299
|
+
? options.subMenuIcon(docData.type)
|
|
300
|
+
: docData.icon;
|
|
287
301
|
docMenuRender += html`
|
|
288
302
|
${await BtnIcon.Render({
|
|
289
303
|
class: `in wfa main-btn-menu submenu-btn btn-docs btn-docs-${docData.type}`,
|
|
290
|
-
label: html`<span class="inl menu-btn-icon">${
|
|
304
|
+
label: html`<span class="inl menu-btn-icon">${subMenuIcon}</span
|
|
291
305
|
><span class="menu-label-text menu-label-text-docs"> ${docData.text} </span>`,
|
|
292
306
|
tabHref,
|
|
293
307
|
tooltipHtml: await Badge.Render(buildBadgeToolTipMenuOption(docData.text, 'right')),
|
|
@@ -447,7 +461,10 @@ const Docs = {
|
|
|
447
461
|
if (s(`.docs-card-container-${item.id}`)) {
|
|
448
462
|
s(`.docs-card-container-${item.id}`).onclick = () => {
|
|
449
463
|
if (item.id.match('demo')) {
|
|
450
|
-
|
|
464
|
+
const demoData = Docs.Data.find((d) => d.type === 'demo');
|
|
465
|
+
location.href = demoData
|
|
466
|
+
? demoData.url()
|
|
467
|
+
: 'https://underpostnet.github.io/pwa-microservices-template-ghpkg/';
|
|
451
468
|
} else if (item.id.match('api')) {
|
|
452
469
|
if (s(`.btn-docs-api`)) s(`.btn-docs-api`).click();
|
|
453
470
|
} else {
|