@underpostnet/underpost 2.98.3 → 2.99.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/src/cli/deploy.js CHANGED
@@ -18,12 +18,9 @@ import { loggerFactory } from '../server/logger.js';
18
18
  import { shellExec } from '../server/process.js';
19
19
  import fs from 'fs-extra';
20
20
  import dotenv from 'dotenv';
21
- import UnderpostRootEnv from './env.js';
22
- import UnderpostCluster from './cluster.js';
23
21
  import { timer } from '../client/components/core/CommonJs.js';
24
22
  import os from 'node:os';
25
- import Dns, { getLocalIPv4Address } from '../server/dns.js';
26
- import UnderpostBaremetal from './baremetal.js';
23
+ import Underpost from '../index.js';
27
24
 
28
25
  const logger = loggerFactory(import.meta);
29
26
 
@@ -35,7 +32,6 @@ const logger = loggerFactory(import.meta);
35
32
  * @memberof UnderpostDeploy
36
33
  */
37
34
  class UnderpostDeploy {
38
- static NETWORK = {};
39
35
  static API = {
40
36
  /**
41
37
  * Creates a router configuration for a list of deployments.
@@ -59,12 +55,24 @@ class UnderpostDeploy {
59
55
  * @param {string} env - Environment for which the service is being created.
60
56
  * @param {number} port - Port number for the service.
61
57
  * @param {Array<string>} deploymentVersions - List of deployment versions.
58
+ * @param {string} serviceId - Custom service name (optional).
59
+ * @param {Array} pathRewritePolicy - Path rewrite policy (optional).
60
+ * @param {object} timeoutPolicy - Timeout policy (optional).
61
+ * @param {object} retryPolicy - Retry policy (optional).
62
62
  * @returns {string} - YAML service configuration for the specified deployment.
63
- * @param {string} [serviceId] - Custom service name (optional).
64
- * @param {Array} [pathRewritePolicy] - Path rewrite policy (optional).
65
63
  * @memberof UnderpostDeploy
66
64
  */
67
- deploymentYamlServiceFactory({ deployId, path, env, port, deploymentVersions, serviceId, pathRewritePolicy }) {
65
+ deploymentYamlServiceFactory({
66
+ deployId,
67
+ path,
68
+ env,
69
+ port,
70
+ deploymentVersions,
71
+ serviceId,
72
+ pathRewritePolicy,
73
+ timeoutPolicy,
74
+ retryPolicy,
75
+ }) {
68
76
  return `
69
77
  - conditions:
70
78
  - prefix: ${path}
@@ -79,12 +87,25 @@ class UnderpostDeploy {
79
87
  ).join(`
80
88
  `)}`
81
89
  : ''
90
+ }${
91
+ timeoutPolicy
92
+ ? `\n timeoutPolicy:\n${timeoutPolicy.response ? ` response: ${timeoutPolicy.response}\n` : ''}${
93
+ timeoutPolicy.idle ? ` idle: ${timeoutPolicy.idle}\n` : ''
94
+ }`
95
+ : ''
96
+ }${
97
+ retryPolicy
98
+ ? `\n retryPolicy:\n${retryPolicy.count !== undefined ? ` count: ${retryPolicy.count}\n` : ''}${
99
+ retryPolicy.perTryTimeout ? ` perTryTimeout: ${retryPolicy.perTryTimeout}\n` : ''
100
+ }`
101
+ : ''
82
102
  }
83
103
  enableWebsockets: true
84
104
  services:
85
105
  ${deploymentVersions
86
106
  .map(
87
- (version, i) => ` - name: ${serviceId ? serviceId : `${deployId}-${env}-${version}-service`}
107
+ (version, i) =>
108
+ ` - name: ${serviceId ? serviceId : `${deployId}-${env}-${version}-service`}
88
109
  port: ${port}
89
110
  weight: ${i === 0 ? 100 : 0}
90
111
  `,
@@ -106,13 +127,12 @@ class UnderpostDeploy {
106
127
  * @memberof UnderpostDeploy
107
128
  */
108
129
  deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image, namespace, volumes, cmd }) {
109
- const baseCommand = env === 'development' ? 'node bin' : 'underpost';
110
130
  if (!cmd)
111
131
  cmd = [
112
132
  `npm install -g npm@11.2.0`,
113
133
  `npm install -g underpost`,
114
- `${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
115
- `${baseCommand} start --build --run ${deployId} ${env}`,
134
+ `underpost secret underpost --create-from-file /etc/config/.env.${env}`,
135
+ `underpost start --build --run --underpost-quickly-install ${deployId} ${env}`,
116
136
  ];
117
137
  const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
118
138
  if (!volumes)
@@ -164,7 +184,8 @@ ${
164
184
  - >
165
185
  ${cmd.join(` && `)}
166
186
 
167
- ${UnderpostDeploy.API.volumeFactory(volumes.map((v) => ((v.version = `${deployId}-${env}-${suffix}`), v)))
187
+ ${Underpost.deploy
188
+ .volumeFactory(volumes.map((v) => ((v.version = `${deployId}-${env}-${suffix}`), v)))
168
189
  .render.split(`\n`)
169
190
  .map((l) => ' ' + l)
170
191
  .join(`\n`)}
@@ -188,6 +209,14 @@ spec:
188
209
  * @param {string} options.replicas - Number of replicas for each deployment.
189
210
  * @param {string} options.image - Docker image for the deployment.
190
211
  * @param {string} options.namespace - Kubernetes namespace for the deployment.
212
+ * @param {string} [options.versions] - Comma-separated list of versions to deploy.
213
+ * @param {string} [options.cmd] - Custom initialization command for deploymentYamlPartsFactory (comma-separated commands).
214
+ * @param {string} [options.timeoutResponse] - Timeout response setting for the deployment.
215
+ * @param {string} [options.timeoutIdle] - Timeout idle setting for the deployment.
216
+ * @param {string} [options.retryCount] - Retry count setting for the deployment.
217
+ * @param {string} [options.retryPerTryTimeout] - Retry per-try timeout setting for the deployment.
218
+ * @param {boolean} [options.disableDeploymentProxy] - Whether to disable deployment proxy.
219
+ * @param {string} [options.traffic] - Traffic status for the deployment.
191
220
  * @returns {Promise<void>} - Promise that resolves when the manifest is built.
192
221
  * @memberof UnderpostDeploy
193
222
  */
@@ -203,7 +232,7 @@ spec:
203
232
  deployId,
204
233
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
205
234
  );
206
- const router = await UnderpostDeploy.API.routerFactory(deployId, env);
235
+ const router = await Underpost.deploy.routerFactory(deployId, env);
207
236
  const pathPortAssignmentData = await pathPortAssignmentFactory(deployId, router, confServer);
208
237
  const { fromPort, toPort } = deployRangePortFactory(router);
209
238
  const deploymentVersions = options.versions.split(',');
@@ -215,15 +244,17 @@ spec:
215
244
  let deploymentYamlParts = '';
216
245
  for (const deploymentVersion of deploymentVersions) {
217
246
  deploymentYamlParts += `---
218
- ${UnderpostDeploy.API.deploymentYamlPartsFactory({
219
- deployId,
220
- env,
221
- suffix: deploymentVersion,
222
- replicas,
223
- image,
224
- namespace: options.namespace,
225
- cmd: options.cmd ? options.cmd.split(',').map((c) => c.trim()) : undefined,
226
- }).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
247
+ ${Underpost.deploy
248
+ .deploymentYamlPartsFactory({
249
+ deployId,
250
+ env,
251
+ suffix: deploymentVersion,
252
+ replicas,
253
+ image,
254
+ namespace: options.namespace,
255
+ cmd: options.cmd ? options.cmd.split(',').map((c) => c.trim()) : undefined,
256
+ })
257
+ .replace('{{ports}}', buildKindPorts(fromPort, toPort))}
227
258
  `;
228
259
  }
229
260
  fs.writeFileSync(`./engine-private/conf/${deployId}/build/${env}/deployment.yaml`, deploymentYamlParts, 'utf8');
@@ -236,34 +267,63 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
236
267
 
237
268
  for (const host of Object.keys(confServer)) {
238
269
  if (env === 'production')
239
- secretYaml += UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace: options.namespace });
270
+ secretYaml += Underpost.deploy.buildCertManagerCertificate({ host, namespace: options.namespace });
240
271
 
241
272
  const pathPortAssignment = pathPortAssignmentData[host];
242
273
  // logger.info('', { host, pathPortAssignment });
243
- let _proxyYaml = UnderpostDeploy.API.baseProxyYamlFactory({ host, env, options });
274
+ let _proxyYaml = Underpost.deploy.baseProxyYamlFactory({ host, env, options });
244
275
  const deploymentVersions =
245
276
  options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'];
246
277
  let proxyRoutes = '';
278
+ const globalTimeoutPolicy =
279
+ (options.timeoutResponse && options.timeoutResponse !== '') ||
280
+ (options.timeoutIdle && options.timeoutIdle !== '')
281
+ ? {
282
+ response: options.timeoutResponse,
283
+ idle: options.timeoutIdle,
284
+ }
285
+ : undefined;
286
+ const globalRetryPolicy =
287
+ options.retryCount ||
288
+ options.retryCount === 0 ||
289
+ (options.retryPerTryTimeout && options.retryPerTryTimeout !== '')
290
+ ? {
291
+ count: options.retryCount,
292
+ perTryTimeout: options.retryPerTryTimeout,
293
+ }
294
+ : undefined;
247
295
  if (!options.disableDeploymentProxy)
248
296
  for (const conditionObj of pathPortAssignment) {
249
297
  const { path, port } = conditionObj;
250
- proxyRoutes += UnderpostDeploy.API.deploymentYamlServiceFactory({
298
+ proxyRoutes += Underpost.deploy.deploymentYamlServiceFactory({
251
299
  path,
252
300
  deployId,
253
301
  env,
254
302
  port,
255
303
  deploymentVersions,
304
+ timeoutPolicy: globalTimeoutPolicy,
305
+ retryPolicy: globalRetryPolicy,
256
306
  });
257
307
  }
258
308
  for (const customService of customServices) {
259
- const { path: _path, port, serviceId, host: _host, pathRewritePolicy } = customService;
309
+ const {
310
+ path: _path,
311
+ port,
312
+ serviceId,
313
+ host: _host,
314
+ pathRewritePolicy,
315
+ timeoutPolicy: _timeoutPolicy,
316
+ retryPolicy: _retryPolicy,
317
+ } = customService;
260
318
  if (host === _host) {
261
- proxyRoutes += UnderpostDeploy.API.deploymentYamlServiceFactory({
319
+ proxyRoutes += Underpost.deploy.deploymentYamlServiceFactory({
262
320
  path: _path,
263
321
  port,
264
322
  serviceId,
265
323
  deploymentVersions,
266
324
  pathRewritePolicy,
325
+ timeoutPolicy: _timeoutPolicy ? _timeoutPolicy : globalTimeoutPolicy,
326
+ retryPolicy: _retryPolicy ? _retryPolicy : globalRetryPolicy,
267
327
  });
268
328
  }
269
329
  }
@@ -389,6 +449,10 @@ spec:
389
449
  * @param {boolean} options.etcHosts - Whether to display the /etc/hosts file.
390
450
  * @param {boolean} options.disableUpdateUnderpostConfig - Whether to disable Underpost config updates.
391
451
  * @param {string} [options.namespace] - Kubernetes namespace for the deployment.
452
+ * @param {string} [options.timeoutResponse] - Timeout response setting for the deployment.
453
+ * @param {string} [options.timeoutIdle] - Timeout idle setting for the deployment.
454
+ * @param {string} [options.retryCount] - Retry count setting for the deployment.
455
+ * @param {string} [options.retryPerTryTimeout] - Retry per-try timeout setting for the deployment.
392
456
  * @param {string} [options.kindType] - Type of Kubernetes resource to retrieve information for.
393
457
  * @param {number} [options.port] - Port number for exposing the deployment.
394
458
  * @param {string} [options.cmd] - Custom initialization command for deploymentYamlPartsFactory (comma-separated commands).
@@ -421,6 +485,10 @@ spec:
421
485
  etcHosts: false,
422
486
  disableUpdateUnderpostConfig: false,
423
487
  namespace: '',
488
+ timeoutResponse: '',
489
+ timeoutIdle: '',
490
+ retryCount: '',
491
+ retryPerTryTimeout: '',
424
492
  kindType: '',
425
493
  port: 0,
426
494
  cmd: '',
@@ -430,7 +498,7 @@ spec:
430
498
  if (!deployList && options.certHosts) {
431
499
  for (const host of options.certHosts.split(',')) {
432
500
  shellExec(`sudo kubectl apply -f - -n ${namespace} <<EOF
433
- ${UnderpostDeploy.API.buildCertManagerCertificate({ host, namespace })}
501
+ ${Underpost.deploy.buildCertManagerCertificate({ host, namespace })}
434
502
  EOF`);
435
503
  }
436
504
  return;
@@ -453,26 +521,26 @@ EOF`);
453
521
  path: instance.path,
454
522
  fromPort: instance.fromPort,
455
523
  toPort: instance.toPort,
456
- traffic: UnderpostDeploy.API.getCurrentTraffic(_deployId, { namespace, hostTest: instance.host }),
524
+ traffic: Underpost.deploy.getCurrentTraffic(_deployId, { namespace, hostTest: instance.host }),
457
525
  });
458
526
  }
459
527
  }
460
528
  logger.info('', {
461
529
  deployId,
462
530
  env,
463
- traffic: UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace }),
464
- router: await UnderpostDeploy.API.routerFactory(deployId, env),
465
- pods: await UnderpostDeploy.API.get(deployId),
531
+ traffic: Underpost.deploy.getCurrentTraffic(deployId, { namespace }),
532
+ router: await Underpost.deploy.routerFactory(deployId, env),
533
+ pods: await Underpost.deploy.get(deployId),
466
534
  instances,
467
535
  });
468
536
  }
469
- const interfaceName = Dns.getDefaultNetworkInterface();
537
+ const interfaceName = Underpost.dns.getDefaultNetworkInterface();
470
538
  logger.info('Machine', {
471
539
  hostname: os.hostname(),
472
- arch: UnderpostBaremetal.API.getHostArch(),
473
- ipv4Public: await Dns.getPublicIp(),
474
- ipv4Local: getLocalIPv4Address(),
475
- resources: UnderpostCluster.API.getResourcesCapacity(options.node),
540
+ arch: Underpost.baremetal.getHostArch(),
541
+ ipv4Public: await Underpost.dns.getPublicIp(),
542
+ ipv4Local: Underpost.dns.getLocalIPv4Address(),
543
+ resources: Underpost.cluster.getResourcesCapacity(options.node),
476
544
  defaultInterfaceName: interfaceName,
477
545
  defaultInterfaceInfo: os.networkInterfaces()[interfaceName],
478
546
  });
@@ -484,16 +552,16 @@ EOF`);
484
552
  getDataDeploy({
485
553
  buildSingleReplica: true,
486
554
  });
487
- if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
555
+ if (options.buildManifest === true) await Underpost.deploy.buildManifest(deployList, env, options);
488
556
  if (options.infoRouter === true || options.buildManifest === true) {
489
- logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
557
+ logger.info('router', await Underpost.deploy.routerFactory(deployList, env));
490
558
  return;
491
559
  }
492
- if (!options.disableUpdateUnderpostConfig) UnderpostDeploy.API.configMap(env);
560
+ if (!options.disableUpdateUnderpostConfig) Underpost.deploy.configMap(env);
493
561
  let renderHosts = '';
494
562
  let etcHosts = [];
495
563
  if (options.restoreHosts === true) {
496
- const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
564
+ const factoryResult = Underpost.deploy.etcHostFactory(etcHosts);
497
565
  renderHosts = factoryResult.renderHosts;
498
566
  logger.info(renderHosts);
499
567
  return;
@@ -504,7 +572,7 @@ EOF`);
504
572
  if (!deployId) continue;
505
573
  if (options.expose === true) {
506
574
  const kindType = options.kindType ? options.kindType : 'svc';
507
- const svc = UnderpostDeploy.API.get(deployId, kindType)[0];
575
+ const svc = Underpost.deploy.get(deployId, kindType)[0];
508
576
  const port = options.port
509
577
  ? options.port
510
578
  : kindType !== 'svc'
@@ -535,7 +603,7 @@ EOF`);
535
603
  );
536
604
  if (!options.disableUpdateVolume)
537
605
  for (const volume of confVolume)
538
- UnderpostDeploy.API.deployVolume(volume, {
606
+ Underpost.deploy.deployVolume(volume, {
539
607
  deployId,
540
608
  env,
541
609
  version,
@@ -547,7 +615,7 @@ EOF`);
547
615
  for (const host of Object.keys(confServer)) {
548
616
  if (!options.disableUpdateProxy) {
549
617
  shellExec(`sudo kubectl delete HTTPProxy ${host} -n ${namespace} --ignore-not-found`);
550
- if (UnderpostDeploy.API.isValidTLSContext({ host, env, options }))
618
+ if (Underpost.deploy.isValidTLSContext({ host, env, options }))
551
619
  shellExec(`sudo kubectl delete Certificate ${host} -n ${namespace} --ignore-not-found`);
552
620
  }
553
621
  if (!options.remove) etcHosts.push(host);
@@ -564,12 +632,12 @@ EOF`);
564
632
  if (!options.disableUpdateProxy)
565
633
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml -n ${namespace}`);
566
634
 
567
- if (UnderpostDeploy.API.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
635
+ if (Underpost.deploy.isValidTLSContext({ host: Object.keys(confServer)[0], env, options }))
568
636
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml -n ${namespace}`);
569
637
  }
570
638
  }
571
639
  if (options.etcHosts === true) {
572
- const factoryResult = UnderpostDeploy.API.etcHostFactory(etcHosts);
640
+ const factoryResult = Underpost.deploy.etcHostFactory(etcHosts);
573
641
  renderHosts = factoryResult.renderHosts;
574
642
  }
575
643
  if (renderHosts)
@@ -667,7 +735,7 @@ EOF`);
667
735
  */
668
736
  async checkDeploymentReadyStatus(deployId, env, traffic, ignoresNames = [], namespace = 'default') {
669
737
  const cmd = `underpost config get container-status`;
670
- const pods = UnderpostDeploy.API.get(`${deployId}-${env}-${traffic}`, 'pods', namespace);
738
+ const pods = Underpost.deploy.get(`${deployId}-${env}-${traffic}`, 'pods', namespace);
671
739
  const readyPods = [];
672
740
  const notReadyPods = [];
673
741
  for (const pod of pods) {
@@ -711,14 +779,35 @@ EOF`);
711
779
  * @param {string} targetTraffic - Target traffic status for the deployment.
712
780
  * @param {number} replicas - Number of replicas for the deployment.
713
781
  * @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
782
+ * @param {object} options - Options for the traffic switch.
783
+ * @param {string} options.timeoutResponse - Timeout response setting for the deployment.
784
+ * @param {string} options.timeoutIdle - Timeout idle setting for the deployment.
785
+ * @param {string} options.retryCount - Retry count setting for the deployment.
786
+ * @param {string} options.retryPerTryTimeout - Retry per-try timeout setting for the deployment.
714
787
  * @memberof UnderpostDeploy
715
788
  */
716
- switchTraffic(deployId, env, targetTraffic, replicas = 1, namespace = 'default') {
717
- UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
789
+ switchTraffic(
790
+ deployId,
791
+ env,
792
+ targetTraffic,
793
+ replicas = 1,
794
+ namespace = 'default',
795
+ options = {
796
+ timeoutResponse: '',
797
+ timeoutIdle: '',
798
+ retryCount: '',
799
+ retryPerTryTimeout: '',
800
+ },
801
+ ) {
802
+ const timeoutFlags = Underpost.deploy.timeoutFlagsFactory(options);
803
+
718
804
  shellExec(
719
- `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} --namespace ${namespace} ${deployId} ${env}`,
805
+ `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} --namespace ${namespace}${timeoutFlags} ${deployId} ${env}`,
720
806
  );
807
+
721
808
  shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml -n ${namespace}`);
809
+
810
+ Underpost.env.set(`${deployId}-${env}-traffic`, targetTraffic);
722
811
  },
723
812
 
724
813
  /**
@@ -767,7 +856,7 @@ EOF`);
767
856
  shellExec(`kubectl delete pvc ${pvcId} -n ${namespace} --ignore-not-found`);
768
857
  shellExec(`kubectl delete pv ${pvId} --ignore-not-found`);
769
858
  shellExec(`kubectl apply -f - -n ${namespace} <<EOF
770
- ${UnderpostDeploy.API.persistentVolumeFactory({
859
+ ${Underpost.deploy.persistentVolumeFactory({
771
860
  hostPath: rootVolumeHostPath,
772
861
  pvcId,
773
862
  })}
@@ -934,13 +1023,7 @@ ${renderHosts}`,
934
1023
  );
935
1024
  break;
936
1025
  }
937
- result = await UnderpostDeploy.API.checkDeploymentReadyStatus(
938
- deployId,
939
- env,
940
- targetTraffic,
941
- ignorePods,
942
- namespace,
943
- );
1026
+ result = await Underpost.deploy.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods, namespace);
944
1027
  if (result.ready === true) {
945
1028
  readyOk++;
946
1029
  logger.info(`${iteratorTag} | Deployment ready. Verification number: ${readyOk}`);
@@ -1137,7 +1220,7 @@ ${renderHosts}`,
1137
1220
  ) => {
1138
1221
  if (resources) {
1139
1222
  if (resources.resourceTemplateId)
1140
- return UnderpostDeploy.API.resourcesTemplate[resources.resourceTemplateId].resources;
1223
+ return Underpost.deploy.resourcesTemplate[resources.resourceTemplateId].resources;
1141
1224
  if (resources.requestsMemory && resources.requestsCpu && resources.limitsMemory && resources.limitsCpu)
1142
1225
  return {
1143
1226
  requests: {
@@ -1152,6 +1235,25 @@ ${renderHosts}`,
1152
1235
  }
1153
1236
  return undefined;
1154
1237
  },
1238
+
1239
+ /**
1240
+ * Generates timeout flags string for deployment commands.
1241
+ * @param {object} options - Options containing timeout settings.
1242
+ * @param {string|number} [options.timeoutResponse] - Timeout response value.
1243
+ * @param {string|number} [options.timeoutIdle] - Timeout idle value.
1244
+ * @param {string|number} [options.retryCount] - Retry count value.
1245
+ * @param {string|number} [options.retryPerTryTimeout] - Retry per try timeout value.
1246
+ * @returns {string} The timeout flags string.
1247
+ * @memberof UnderpostDeploy
1248
+ */
1249
+ timeoutFlagsFactory: (options = {}) => {
1250
+ return (
1251
+ `${options.timeoutResponse ? ` --timeout-response ${options.timeoutResponse}` : ''}` +
1252
+ `${options.timeoutIdle ? ` --timeout-idle ${options.timeoutIdle}` : ''}` +
1253
+ `${options.retryCount || options.retryCount === 0 ? ` --retry-count ${options.retryCount}` : ''}` +
1254
+ `${options.retryPerTryTimeout ? ` --retry-per-try-timeout ${options.retryPerTryTimeout}` : ''}`
1255
+ );
1256
+ },
1155
1257
  };
1156
1258
  }
1157
1259
 
package/src/cli/env.js CHANGED
@@ -25,15 +25,30 @@ class UnderpostRootEnv {
25
25
  * @description Sets an environment variable in the underpost root environment.
26
26
  * @param {string} key - The key of the environment variable to set.
27
27
  * @param {string} value - The value of the environment variable to set.
28
+ * @param {object} options - Options for setting the environment variable.
29
+ * @param {string} [options.deployId=''] - Deployment ID associated with the environment variable.
30
+ * @param {boolean} [options.build=false] - If true, triggers a build after setting the environment variable.
28
31
  * @memberof UnderpostEnv
29
32
  */
30
- set(key, value) {
33
+ set(key, value, options = { deployId: '', build: false }) {
34
+ const _set = (envPath, key, value) => {
35
+ let env = {};
36
+ if (fs.existsSync(envPath)) env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
37
+ env[key] = value;
38
+ writeEnv(envPath, env);
39
+ };
40
+ if (options.build) {
41
+ const deployIdList = options.deployId
42
+ ? [options.deployId]
43
+ : fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
44
+ for (const deployId of deployIdList)
45
+ for (const envFile of ['test', 'development', 'production'])
46
+ _set(`./engine-private/conf/${deployId}/.env.${envFile}`, key, value);
47
+ return;
48
+ }
31
49
  const exeRootPath = `${getNpmRootPath()}/underpost`;
32
50
  const envPath = `${exeRootPath}/.env`;
33
- let env = {};
34
- if (fs.existsSync(envPath)) env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
35
- env[key] = value;
36
- writeEnv(envPath, env);
51
+ _set(envPath, key, value);
37
52
  },
38
53
  /**
39
54
  * @method delete
package/src/cli/fs.js CHANGED
@@ -11,8 +11,8 @@ import AdmZip from 'adm-zip';
11
11
  import * as dir from 'path';
12
12
  import fs from 'fs-extra';
13
13
  import Downloader from '../server/downloader.js';
14
- import UnderpostRepository from './repository.js';
15
14
  import { shellExec } from '../server/process.js';
15
+ import Underpost from '../index.js';
16
16
  dotenv.config();
17
17
 
18
18
  const logger = loggerFactory(import.meta);
@@ -93,12 +93,12 @@ class UnderpostFileStorage {
93
93
  storageFilePath: '',
94
94
  },
95
95
  ) {
96
- const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
97
- const deleteFiles = options.pull === true ? [] : UnderpostRepository.API.getDeleteFiles(path);
96
+ const { storage, storageConf } = Underpost.fs.getStorageConf(options);
97
+ const deleteFiles = options.pull === true ? [] : Underpost.repo.getDeleteFiles(path);
98
98
  for (const relativePath of deleteFiles) {
99
99
  const _path = path + '/' + relativePath;
100
100
  if (_path in storage) {
101
- await UnderpostFileStorage.API.delete(_path);
101
+ await Underpost.fs.delete(_path);
102
102
  delete storage[_path];
103
103
  }
104
104
  }
@@ -106,27 +106,25 @@ class UnderpostFileStorage {
106
106
  for (const _path of Object.keys(storage)) {
107
107
  if (!fs.existsSync(_path) || options.force === true) {
108
108
  if (options.force === true && fs.existsSync(_path)) fs.removeSync(_path);
109
- await UnderpostFileStorage.API.pull(_path, options);
109
+ await Underpost.fs.pull(_path, options);
110
110
  } else logger.warn(`Pull path already exists`, _path);
111
111
  }
112
112
  shellExec(`cd ${path} && git init && git add . && git commit -m "Base pull state"`);
113
113
  } else {
114
114
  const files =
115
- options.git === true
116
- ? UnderpostRepository.API.getChangedFiles(path)
117
- : await fs.readdir(path, { recursive: true });
115
+ options.git === true ? Underpost.repo.getChangedFiles(path) : await fs.readdir(path, { recursive: true });
118
116
  for (const relativePath of files) {
119
117
  const _path = path + '/' + relativePath;
120
118
  if (fs.statSync(_path).isDirectory()) {
121
119
  if (options.pull === true && !fs.existsSync(_path)) fs.mkdirSync(_path, { recursive: true });
122
120
  continue;
123
121
  } else if (!(_path in storage) || options.force === true) {
124
- await UnderpostFileStorage.API.upload(_path, options);
122
+ await Underpost.fs.upload(_path, options);
125
123
  if (storage) storage[_path] = {};
126
124
  } else logger.warn('File already exists', _path);
127
125
  }
128
126
  }
129
- UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
127
+ Underpost.fs.writeStorageConf(storage, storageConf);
130
128
  if (options.git === true) {
131
129
  shellExec(`cd ${path} && git add .`);
132
130
  shellExec(`underpost cmt ${path} feat`);
@@ -152,10 +150,10 @@ class UnderpostFileStorage {
152
150
  options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
153
151
  ) {
154
152
  if (options.recursive === true || options.git === true)
155
- return await UnderpostFileStorage.API.recursiveCallback(path, options);
156
- if (options.pull === true) return await UnderpostFileStorage.API.pull(path, options);
157
- if (options.rm === true) return await UnderpostFileStorage.API.delete(path, options);
158
- return await UnderpostFileStorage.API.upload(path, options);
153
+ return await Underpost.fs.recursiveCallback(path, options);
154
+ if (options.pull === true) return await Underpost.fs.pull(path, options);
155
+ if (options.rm === true) return await Underpost.fs.delete(path, options);
156
+ return await Underpost.fs.upload(path, options);
159
157
  },
160
158
  /**
161
159
  * @method upload
@@ -171,9 +169,9 @@ class UnderpostFileStorage {
171
169
  path,
172
170
  options = { rm: false, recursive: false, deployId: '', force: false, pull: false, storageFilePath: '' },
173
171
  ) {
174
- UnderpostFileStorage.API.cloudinaryConfig();
175
- const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
176
- // path = UnderpostFileStorage.API.file2Zip(path);
172
+ Underpost.fs.cloudinaryConfig();
173
+ const { storage, storageConf } = Underpost.fs.getStorageConf(options);
174
+ // path = Underpost.fs.file2Zip(path);
177
175
  const uploadResult = await cloudinary.uploader
178
176
  .upload(path, {
179
177
  public_id: path,
@@ -185,7 +183,7 @@ class UnderpostFileStorage {
185
183
  });
186
184
  logger.info('upload result', uploadResult);
187
185
  if (storage) storage[path] = {};
188
- UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
186
+ Underpost.fs.writeStorageConf(storage, storageConf);
189
187
  return uploadResult;
190
188
  },
191
189
  /**
@@ -196,7 +194,7 @@ class UnderpostFileStorage {
196
194
  * @memberof UnderpostFileStorage
197
195
  */
198
196
  async pull(path) {
199
- UnderpostFileStorage.API.cloudinaryConfig();
197
+ Underpost.fs.cloudinaryConfig();
200
198
  const folder = dir.dirname(path);
201
199
  if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
202
200
  const downloadResult = await cloudinary.utils.download_archive_url({
@@ -205,11 +203,11 @@ class UnderpostFileStorage {
205
203
  });
206
204
  logger.info('download result', downloadResult);
207
205
  await Downloader.downloadFile(downloadResult, path + '.zip');
208
- path = UnderpostFileStorage.API.zip2File(path + '.zip');
206
+ path = Underpost.fs.zip2File(path + '.zip');
209
207
  fs.removeSync(path + '.zip');
210
208
  },
211
209
  async delete(path) {
212
- UnderpostFileStorage.API.cloudinaryConfig();
210
+ Underpost.fs.cloudinaryConfig();
213
211
  const deleteResult = await cloudinary.api
214
212
  .delete_resources([path], { type: 'upload', resource_type: 'raw' })
215
213
  .catch((error) => {