@underpostnet/underpost 2.8.5 → 2.8.6
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/.github/workflows/ghpkg.yml +1 -1
- package/.github/workflows/npmpkg.yml +1 -1
- package/.github/workflows/pwa-microservices-template.page.yml +1 -1
- package/.vscode/settings.json +4 -0
- package/CHANGELOG.md +24 -0
- package/bin/build.js +29 -4
- package/bin/deploy.js +70 -74
- package/bin/hwt.js +0 -10
- package/bin/index.js +54 -23
- package/bin/util.js +0 -7
- package/bin/vs.js +1 -0
- package/conf.js +0 -2
- package/docker-compose.yml +1 -1
- package/manifests/kind-config-dev.yaml +12 -0
- package/manifests/mongodb/kustomization.yaml +2 -2
- package/manifests/mongodb-4.4/kustomization.yaml +7 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +63 -0
- package/package.json +9 -7
- package/src/cli/cluster.js +99 -51
- package/src/cli/cron.js +1 -1
- package/src/cli/db.js +102 -38
- package/src/cli/deploy.js +76 -35
- package/src/cli/fs.js +149 -0
- package/src/cli/image.js +50 -27
- package/src/cli/repository.js +21 -0
- package/src/cli/script.js +25 -1
- package/src/cli/test.js +39 -4
- package/src/client/components/core/CalendarCore.js +12 -1
- package/src/client/components/core/CommonJs.js +52 -1
- package/src/client/components/core/CssCore.js +2 -4
- package/src/client/components/core/Docs.js +1 -2
- package/src/client/components/core/Input.js +4 -2
- package/src/client/components/core/LoadingAnimation.js +8 -1
- package/src/client/components/core/Modal.js +30 -6
- package/src/client/components/core/Panel.js +8 -6
- package/src/client/components/core/PanelForm.js +23 -7
- package/src/client/services/core/core.service.js +15 -10
- package/src/client/ssr/Render.js +4 -1
- package/src/client/ssr/body/CacheControl.js +2 -3
- package/src/client/sw/default.sw.js +3 -3
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/index.js +9 -1
- package/src/server/backup.js +3 -3
- package/src/server/client-build.js +32 -23
- package/src/server/client-formatted.js +2 -1
- package/src/server/conf.js +17 -15
- package/src/server/dns.js +39 -46
- package/src/server/downloader.js +0 -8
- package/src/server/runtime.js +16 -1
- package/test/api.test.js +0 -8
- package/manifests/core/kustomization.yaml +0 -11
- package/manifests/core/underpost-engine-backup-access.yaml +0 -16
- package/manifests/core/underpost-engine-backup-pv-pvc.yaml +0 -22
- package/manifests/core/underpost-engine-headless-service.yaml +0 -10
- package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +0 -40
- package/manifests/core/underpost-engine-mongodb-configmap.yaml +0 -26
- package/manifests/core/underpost-engine-statefulset.yaml +0 -91
- package/manifests/valkey/underpost-engine-valkey-service.yaml +0 -17
- package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +0 -39
- /package/manifests/{core/underpost-engine-pv-pvc.yaml → mongodb-4.4/pv-pvc.yaml} +0 -0
package/src/cli/deploy.js
CHANGED
|
@@ -32,7 +32,7 @@ class UnderpostDeploy {
|
|
|
32
32
|
await Config.build(undefined, 'proxy', deployList);
|
|
33
33
|
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
34
34
|
},
|
|
35
|
-
async buildManifest(deployList, env) {
|
|
35
|
+
async buildManifest(deployList, env, version) {
|
|
36
36
|
for (const _deployId of deployList.split(',')) {
|
|
37
37
|
const deployId = _deployId.trim();
|
|
38
38
|
if (!deployId) continue;
|
|
@@ -69,7 +69,18 @@ spec:
|
|
|
69
69
|
spec:
|
|
70
70
|
containers:
|
|
71
71
|
- name: ${deployId}-${env}
|
|
72
|
-
image: localhost
|
|
72
|
+
image: localhost/underpost-engine:${version && typeof version === 'string' ? version : Underpost.version}
|
|
73
|
+
lifecycle:
|
|
74
|
+
postStart:
|
|
75
|
+
exec:
|
|
76
|
+
command:
|
|
77
|
+
- /bin/sh
|
|
78
|
+
- -c
|
|
79
|
+
- >
|
|
80
|
+
sleep 60 &&
|
|
81
|
+
underpost config set deploy-id ${deployId} &&
|
|
82
|
+
underpost config set deploy-env ${env}
|
|
83
|
+
# image: localhost/${deployId}-${env}:${version && typeof version === 'string' ? version : Underpost.version}
|
|
73
84
|
---
|
|
74
85
|
apiVersion: v1
|
|
75
86
|
kind: Service
|
|
@@ -180,70 +191,100 @@ spec:
|
|
|
180
191
|
async callback(
|
|
181
192
|
deployList = 'default',
|
|
182
193
|
env = 'development',
|
|
183
|
-
options = {
|
|
194
|
+
options = {
|
|
195
|
+
remove: false,
|
|
196
|
+
infoRouter: false,
|
|
197
|
+
sync: false,
|
|
198
|
+
buildManifest: false,
|
|
199
|
+
infoUtil: false,
|
|
200
|
+
expose: false,
|
|
201
|
+
cert: false,
|
|
202
|
+
version: '',
|
|
203
|
+
},
|
|
184
204
|
) {
|
|
205
|
+
if (options.infoUtil === true)
|
|
206
|
+
return logger.info(`
|
|
207
|
+
kubectl rollout restart deployment/deployment-name
|
|
208
|
+
kubectl rollout undo deployment/deployment-name
|
|
209
|
+
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
210
|
+
`);
|
|
185
211
|
if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
186
212
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
187
213
|
if (options.sync) UnderpostDeploy.API.sync(deployList);
|
|
188
|
-
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env);
|
|
214
|
+
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options.version);
|
|
189
215
|
if (options.infoRouter === true)
|
|
190
216
|
return logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
217
|
+
const etcHost = (
|
|
218
|
+
concat,
|
|
219
|
+
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
220
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
221
|
+
let concatHots = '';
|
|
191
222
|
|
|
192
223
|
for (const _deployId of deployList.split(',')) {
|
|
193
224
|
const deployId = _deployId.trim();
|
|
194
225
|
if (!deployId) continue;
|
|
195
|
-
|
|
226
|
+
if (options.expose === true) {
|
|
227
|
+
const svc = UnderpostDeploy.API.get(deployId, 'svc')[0];
|
|
228
|
+
const port = parseInt(svc[`PORT(S)`].split('/TCP')[0]);
|
|
229
|
+
logger.info(deployId, {
|
|
230
|
+
svc,
|
|
231
|
+
port,
|
|
232
|
+
});
|
|
233
|
+
shellExec(`sudo kubectl port-forward -n default svc/${svc.NAME} ${port}:${port}`, { async: true });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
196
236
|
shellExec(`sudo kubectl delete svc ${deployId}-${env}-service`);
|
|
197
237
|
shellExec(`sudo kubectl delete deployment ${deployId}-${env}`);
|
|
198
238
|
|
|
199
|
-
const etcHost = (
|
|
200
|
-
concat,
|
|
201
|
-
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
202
|
-
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
203
|
-
let concatHots = '';
|
|
204
|
-
|
|
205
239
|
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
206
240
|
for (const host of Object.keys(confServer)) {
|
|
207
241
|
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
242
|
+
if (env === 'production' && options.cert === true) shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
208
243
|
if (!options.remove === true && env === 'development') concatHots += ` ${host}`;
|
|
209
244
|
}
|
|
210
245
|
|
|
246
|
+
const manifestsPath =
|
|
247
|
+
env === 'production'
|
|
248
|
+
? `engine-private/conf/${deployId}/build/production`
|
|
249
|
+
: `manifests/deployment/${deployId}-${env}`;
|
|
250
|
+
|
|
211
251
|
if (!options.remove === true) {
|
|
212
|
-
shellExec(`sudo kubectl apply -f
|
|
213
|
-
shellExec(`sudo kubectl apply -f
|
|
252
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
|
|
253
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
|
|
254
|
+
if (env === 'production' && options.cert === true)
|
|
255
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
214
256
|
}
|
|
257
|
+
}
|
|
258
|
+
let renderHosts;
|
|
259
|
+
switch (process.platform) {
|
|
260
|
+
case 'linux':
|
|
261
|
+
{
|
|
262
|
+
switch (env) {
|
|
263
|
+
case 'development':
|
|
264
|
+
renderHosts = etcHost(concatHots);
|
|
265
|
+
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
215
266
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
switch (process.platform) {
|
|
219
|
-
case 'linux':
|
|
220
|
-
{
|
|
221
|
-
switch (env) {
|
|
222
|
-
case 'development':
|
|
223
|
-
renderHosts = etcHost(concatHots);
|
|
224
|
-
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
225
|
-
|
|
226
|
-
break;
|
|
267
|
+
break;
|
|
227
268
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
269
|
+
default:
|
|
270
|
+
break;
|
|
231
271
|
}
|
|
232
|
-
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
233
274
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
275
|
+
default:
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
if (renderHosts)
|
|
237
279
|
logger.info(
|
|
238
280
|
`
|
|
239
281
|
` + renderHosts,
|
|
240
282
|
);
|
|
241
|
-
}
|
|
242
283
|
},
|
|
243
|
-
|
|
244
|
-
const raw = shellExec(`sudo kubectl get
|
|
284
|
+
get(deployId, kindType = 'pods') {
|
|
285
|
+
const raw = shellExec(`sudo kubectl get ${kindType} --all-namespaces -o wide`, {
|
|
245
286
|
stdout: true,
|
|
246
|
-
disableLog:
|
|
287
|
+
disableLog: true,
|
|
247
288
|
silent: true,
|
|
248
289
|
});
|
|
249
290
|
|
package/src/cli/fs.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { v2 as cloudinary } from 'cloudinary';
|
|
2
|
+
import { loggerFactory } from '../server/logger.js';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import AdmZip from 'adm-zip';
|
|
5
|
+
import * as dir from 'path';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import { Downloader } from '../server/downloader.js';
|
|
8
|
+
import UnderpostRepository from './repository.js';
|
|
9
|
+
import { shellExec } from '../server/process.js';
|
|
10
|
+
dotenv.config();
|
|
11
|
+
|
|
12
|
+
const logger = loggerFactory(import.meta);
|
|
13
|
+
|
|
14
|
+
class UnderpostFileStorage {
|
|
15
|
+
static API = {
|
|
16
|
+
cloudinaryConfig() {
|
|
17
|
+
// https://console.cloudinary.com/
|
|
18
|
+
cloudinary.config({
|
|
19
|
+
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
|
|
20
|
+
api_key: process.env.CLOUDINARY_API_KEY,
|
|
21
|
+
api_secret: process.env.CLOUDINARY_API_SECRET,
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
getStorageConf(options) {
|
|
25
|
+
let storage, storageConf;
|
|
26
|
+
if (options.deployId && typeof options.deployId === 'string') {
|
|
27
|
+
storageConf = `./engine-private/conf/${options.deployId}/storage.json`;
|
|
28
|
+
if (!fs.existsSync(storageConf)) fs.writeFileSync(storageConf, JSON.stringify({}), 'utf8');
|
|
29
|
+
storage = JSON.parse(fs.readFileSync(storageConf, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
return { storage, storageConf };
|
|
32
|
+
},
|
|
33
|
+
writeStorageConf(storage, storageConf) {
|
|
34
|
+
if (storage) fs.writeFileSync(storageConf, JSON.stringify(storage, null, 4), 'utf8');
|
|
35
|
+
},
|
|
36
|
+
async recursiveCallback(
|
|
37
|
+
path,
|
|
38
|
+
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
|
|
39
|
+
) {
|
|
40
|
+
const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
|
|
41
|
+
const deleteFiles = UnderpostRepository.API.getDeleteFiles(path);
|
|
42
|
+
for (const relativePath of deleteFiles) {
|
|
43
|
+
const _path = path + '/' + relativePath;
|
|
44
|
+
if (_path in storage) {
|
|
45
|
+
await UnderpostFileStorage.API.delete(_path);
|
|
46
|
+
delete storage[_path];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const files =
|
|
50
|
+
options.git === true
|
|
51
|
+
? UnderpostRepository.API.getChangedFiles(path)
|
|
52
|
+
: await fs.readdir(path, { recursive: true });
|
|
53
|
+
if (options.pull === true) {
|
|
54
|
+
for (const _path of Object.keys(storage)) {
|
|
55
|
+
if (!fs.existsSync(_path) || options.force === true) {
|
|
56
|
+
if (options.force === true && fs.existsSync(_path)) fs.removeSync(_path);
|
|
57
|
+
await UnderpostFileStorage.API.pull(_path, options);
|
|
58
|
+
} else logger.warn(`Pull path already exists`, _path);
|
|
59
|
+
}
|
|
60
|
+
} else
|
|
61
|
+
for (const relativePath of files) {
|
|
62
|
+
const _path = path + '/' + relativePath;
|
|
63
|
+
if (fs.statSync(_path).isDirectory()) {
|
|
64
|
+
if (options.pull === true && !fs.existsSync(_path)) fs.mkdirSync(_path, { recursive: true });
|
|
65
|
+
continue;
|
|
66
|
+
} else if (!(_path in storage) || options.force === true) {
|
|
67
|
+
await UnderpostFileStorage.API.upload(_path, options);
|
|
68
|
+
if (storage) storage[_path] = {};
|
|
69
|
+
} else logger.warn('File already exists', _path);
|
|
70
|
+
}
|
|
71
|
+
UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
|
|
72
|
+
if (options.git === true) {
|
|
73
|
+
shellExec(`cd ${path} && git add .`);
|
|
74
|
+
shellExec(`underpost cmt ${path} feat`);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
async callback(
|
|
78
|
+
path,
|
|
79
|
+
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
|
|
80
|
+
) {
|
|
81
|
+
if (options.recursive === true || options.git === true)
|
|
82
|
+
return await UnderpostFileStorage.API.recursiveCallback(path, options);
|
|
83
|
+
if (options.pull === true) return await UnderpostFileStorage.API.pull(path, options);
|
|
84
|
+
if (options.rm === true) return await UnderpostFileStorage.API.delete(path, options);
|
|
85
|
+
return await UnderpostFileStorage.API.upload(path, options);
|
|
86
|
+
},
|
|
87
|
+
async upload(path, options = { rm: false, recursive: false, deployId: '', force: false, pull: false }) {
|
|
88
|
+
UnderpostFileStorage.API.cloudinaryConfig();
|
|
89
|
+
const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
|
|
90
|
+
// path = UnderpostFileStorage.API.file2Zip(path);
|
|
91
|
+
const uploadResult = await cloudinary.uploader
|
|
92
|
+
.upload(path, {
|
|
93
|
+
public_id: path,
|
|
94
|
+
resource_type: 'raw',
|
|
95
|
+
overwrite: options.force === true ? true : false,
|
|
96
|
+
})
|
|
97
|
+
.catch((error) => {
|
|
98
|
+
logger.error(error, { path, stack: error.stack });
|
|
99
|
+
});
|
|
100
|
+
logger.info('upload result', uploadResult);
|
|
101
|
+
if (storage) storage[path] = {};
|
|
102
|
+
UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
|
|
103
|
+
return uploadResult;
|
|
104
|
+
},
|
|
105
|
+
async pull(path) {
|
|
106
|
+
UnderpostFileStorage.API.cloudinaryConfig();
|
|
107
|
+
const folder = dir.dirname(path);
|
|
108
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
109
|
+
const downloadResult = await cloudinary.utils.download_archive_url({
|
|
110
|
+
public_ids: [path],
|
|
111
|
+
resource_type: 'raw',
|
|
112
|
+
});
|
|
113
|
+
logger.info('download result', downloadResult);
|
|
114
|
+
await Downloader(downloadResult, path + '.zip');
|
|
115
|
+
path = UnderpostFileStorage.API.zip2File(path + '.zip');
|
|
116
|
+
fs.removeSync(path + '.zip');
|
|
117
|
+
},
|
|
118
|
+
async delete(path) {
|
|
119
|
+
UnderpostFileStorage.API.cloudinaryConfig();
|
|
120
|
+
const deleteResult = await cloudinary.api
|
|
121
|
+
.delete_resources([path], { type: 'upload', resource_type: 'raw' })
|
|
122
|
+
.catch((error) => {
|
|
123
|
+
logger.error(error, { path, stack: error.stack });
|
|
124
|
+
});
|
|
125
|
+
logger.info('delete result', deleteResult);
|
|
126
|
+
return deleteResult;
|
|
127
|
+
},
|
|
128
|
+
file2Zip(path) {
|
|
129
|
+
const zip = new AdmZip();
|
|
130
|
+
zip.addLocalFile(path, '/');
|
|
131
|
+
path = path + '.zip';
|
|
132
|
+
zip.writeZip(path);
|
|
133
|
+
return path;
|
|
134
|
+
},
|
|
135
|
+
zip2File(path) {
|
|
136
|
+
const zip = new AdmZip(path);
|
|
137
|
+
path = path.replaceAll('.zip', '');
|
|
138
|
+
zip.extractEntryTo(
|
|
139
|
+
/*entry name*/ path.split('/').pop(),
|
|
140
|
+
/*target path*/ dir.dirname(path),
|
|
141
|
+
/*maintainEntryPath*/ false,
|
|
142
|
+
/*overwrite*/ true,
|
|
143
|
+
);
|
|
144
|
+
return path;
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export default UnderpostFileStorage;
|
package/src/cli/image.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import Underpost from '../index.js';
|
|
3
|
-
import { shellExec } from '../server/process.js';
|
|
3
|
+
import { shellCd, shellExec } from '../server/process.js';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
5
|
import { getNpmRootPath } from '../server/conf.js';
|
|
6
6
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
7
|
+
import UnderpostRootEnv from './env.js';
|
|
7
8
|
|
|
8
9
|
dotenv.config();
|
|
9
10
|
|
|
@@ -13,11 +14,22 @@ class UnderpostImage {
|
|
|
13
14
|
pullBaseImages() {
|
|
14
15
|
shellExec(`sudo podman pull docker.io/library/debian:buster`);
|
|
15
16
|
},
|
|
16
|
-
build(
|
|
17
|
-
|
|
17
|
+
build(
|
|
18
|
+
deployId = 'default',
|
|
19
|
+
env = 'development',
|
|
20
|
+
path = '.',
|
|
21
|
+
options = { imageArchive: false, podmanSave: false, imageName: '', imageVersion: '' },
|
|
22
|
+
) {
|
|
23
|
+
const imgName = `${
|
|
24
|
+
options.imageName && typeof options.imageName === 'string' ? options.imageName : `${deployId}-${env}`
|
|
25
|
+
}:${
|
|
26
|
+
options.imageVersion && typeof options.imageVersions === 'string' ? options.imageVersion : Underpost.version
|
|
27
|
+
}`;
|
|
18
28
|
const podManImg = `localhost/${imgName}`;
|
|
19
|
-
const imagesStoragePath =
|
|
20
|
-
|
|
29
|
+
const imagesStoragePath = `/images`;
|
|
30
|
+
if (!fs.existsSync(`${path}${imagesStoragePath}`))
|
|
31
|
+
fs.mkdirSync(`${path}${imagesStoragePath}`, { recursive: true });
|
|
32
|
+
const tarFile = `.${imagesStoragePath}/${imgName.replace(':', '_')}.tar`;
|
|
21
33
|
|
|
22
34
|
let secrets = ' ';
|
|
23
35
|
let secretDockerInput = '';
|
|
@@ -36,33 +48,44 @@ class UnderpostImage {
|
|
|
36
48
|
`cd ${path}${secrets}&& sudo podman build -f ./Dockerfile -t ${imgName} --pull=never --cap-add=CAP_AUDIT_WRITE${secretDockerInput}`,
|
|
37
49
|
);
|
|
38
50
|
fs.removeSync(`${path}/.env.underpost`);
|
|
39
|
-
shellExec(`cd ${path} && podman save -o ${tarFile} ${podManImg}`);
|
|
40
51
|
}
|
|
52
|
+
if (options.imageArchive !== true || options.podmanSave === true)
|
|
53
|
+
shellExec(`cd ${path} && podman save -o ${tarFile} ${podManImg}`);
|
|
41
54
|
shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
|
|
42
55
|
},
|
|
43
|
-
async script(deployId = 'default', env = 'development', options = { run: false }) {
|
|
56
|
+
async script(deployId = 'default', env = 'development', options = { run: false, build: false }) {
|
|
57
|
+
if (deployId === 'deploy') {
|
|
58
|
+
const _deployId = UnderpostRootEnv.API.get('deploy-id');
|
|
59
|
+
const _env = UnderpostRootEnv.API.get('deploy-env');
|
|
60
|
+
const _path = UnderpostRootEnv.API.get('deploy-path');
|
|
61
|
+
if (_deployId) {
|
|
62
|
+
deployId = _deployId;
|
|
63
|
+
if (_env) env = _env;
|
|
64
|
+
if (_path) path = _path;
|
|
65
|
+
} else {
|
|
66
|
+
await timer(30 * 1000);
|
|
67
|
+
return await UnderpostImage.API.script(deployId, env, path, options);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (options.build === true) {
|
|
71
|
+
const buildBasePath = `/home/dd`;
|
|
72
|
+
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
73
|
+
fs.mkdirSync(buildBasePath, { recursive: true });
|
|
74
|
+
shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
|
|
75
|
+
shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
|
|
76
|
+
shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
|
|
77
|
+
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
78
|
+
shellCd(`${buildBasePath}/engine`);
|
|
79
|
+
shellExec(`npm install`);
|
|
80
|
+
const itcScripts = fs.readdir('./engine-private/itc-scripts');
|
|
81
|
+
for (const itcScript of itcScripts)
|
|
82
|
+
if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
|
|
83
|
+
}
|
|
44
84
|
switch (deployId) {
|
|
45
85
|
case 'dd-lampp':
|
|
46
86
|
{
|
|
47
87
|
const lamppPublicPath = '/xampp/htdocs/online';
|
|
48
88
|
shellExec(`sudo mkdir -p ${lamppPublicPath}`);
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
shellExec(
|
|
52
|
-
`cd ${lamppPublicPath} && git clone https://${process.env.GITHUB_TOKEN}@github.com/${process.env.DD_LAMPP_REPO_0}`,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
shellExec(`cd ${lamppPublicPath} && sudo ${process.env.DD_LAMPP_SCRIPT_0}`);
|
|
56
|
-
|
|
57
|
-
shellExec(
|
|
58
|
-
`sudo sed -i -e "s@define( 'DB_HOST', 'localhost' );@define( 'DB_HOST', '${process.env.MARIADB_HOST}' );@g" ${lamppPublicPath}/${process.env.DD_LAMPP_REPO_0_FOLDER}/wp-config.php`,
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
{
|
|
62
|
-
shellExec(
|
|
63
|
-
`cd ${lamppPublicPath} && git clone https://${process.env.GITHUB_TOKEN}@github.com/${process.env.DD_LAMPP_REPO_1}`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
89
|
}
|
|
67
90
|
break;
|
|
68
91
|
|
|
@@ -101,12 +124,12 @@ class UnderpostImage {
|
|
|
101
124
|
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
102
125
|
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
103
126
|
if (options.run === true) {
|
|
104
|
-
const runCmd = env === 'production' ? 'prod-img' : 'dev-img';
|
|
127
|
+
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
105
128
|
if (fs.existsSync(`./engine-private/replica`)) {
|
|
106
129
|
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
107
130
|
for (const replica of replicas) {
|
|
108
131
|
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
109
|
-
shellExec(`npm
|
|
132
|
+
shellExec(`npm ${runCmd} ${replica} deploy`, { async: true });
|
|
110
133
|
fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
111
134
|
const monitor = async () => {
|
|
112
135
|
await timer(1000);
|
|
@@ -116,7 +139,7 @@ class UnderpostImage {
|
|
|
116
139
|
}
|
|
117
140
|
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
118
141
|
}
|
|
119
|
-
shellExec(`npm
|
|
142
|
+
shellExec(`npm ${runCmd} ${deployId} deploy`);
|
|
120
143
|
}
|
|
121
144
|
},
|
|
122
145
|
},
|
package/src/cli/repository.js
CHANGED
|
@@ -98,6 +98,27 @@ class UnderpostRepository {
|
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
100
|
},
|
|
101
|
+
|
|
102
|
+
getDeleteFiles(path = '.') {
|
|
103
|
+
const commandUntrack = `cd ${path} && git ls-files --deleted`;
|
|
104
|
+
const diffUntrackOutput = shellExec(commandUntrack, { stdout: true, silent: true });
|
|
105
|
+
return diffUntrackOutput.toString().split('\n').filter(Boolean);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
getChangedFiles(path = '.', extension = '', head = false) {
|
|
109
|
+
const extensionFilter = extension ? `-- '***.${extension}'` : '';
|
|
110
|
+
const command = `cd ${path} && git diff ${head ? 'HEAD^ HEAD ' : ''}--name-only ${extensionFilter}`;
|
|
111
|
+
const commandUntrack = `cd ${path} && git ls-files --others --exclude-standard`;
|
|
112
|
+
const diffOutput = shellExec(command, { stdout: true, silent: true });
|
|
113
|
+
const diffUntrackOutput = shellExec(commandUntrack, { stdout: true, silent: true });
|
|
114
|
+
const deleteFiles = UnderpostRepository.API.getDeleteFiles(path);
|
|
115
|
+
return diffOutput
|
|
116
|
+
.toString()
|
|
117
|
+
.split('\n')
|
|
118
|
+
.filter(Boolean)
|
|
119
|
+
.concat(diffUntrackOutput.toString().split('\n').filter(Boolean))
|
|
120
|
+
.filter((f) => !deleteFiles.includes(f));
|
|
121
|
+
},
|
|
101
122
|
};
|
|
102
123
|
}
|
|
103
124
|
|
package/src/cli/script.js
CHANGED
|
@@ -2,6 +2,7 @@ import { getNpmRootPath } from '../server/conf.js';
|
|
|
2
2
|
import { loggerFactory } from '../server/logger.js';
|
|
3
3
|
import { shellExec } from '../server/process.js';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
+
import UnderpostDeploy from './deploy.js';
|
|
5
6
|
|
|
6
7
|
const logger = loggerFactory(import.meta);
|
|
7
8
|
|
|
@@ -13,8 +14,31 @@ class UnderpostScript {
|
|
|
13
14
|
packageJson.scripts[key] = value;
|
|
14
15
|
fs.writeFileSync(`${npmRoot}/package.json`, JSON.stringify(packageJson, null, 4));
|
|
15
16
|
},
|
|
16
|
-
run(key) {
|
|
17
|
+
run(key, value, options) {
|
|
17
18
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
19
|
+
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
20
|
+
if (options.itc === true) {
|
|
21
|
+
value = packageJson.scripts[key];
|
|
22
|
+
const podScriptPath = `${options.itcPath && typeof options.itcPath === 'string' ? options.itcPath : '/'}${value
|
|
23
|
+
.split('/')
|
|
24
|
+
.pop()}`;
|
|
25
|
+
const nameSpace = options.ns && typeof options.ns === 'string' ? options.ns : 'default';
|
|
26
|
+
const podMatch = options.podName && typeof options.podName === 'string' ? options.podName : key;
|
|
27
|
+
|
|
28
|
+
if (fs.existsSync(`${value}`)) {
|
|
29
|
+
for (const pod of UnderpostDeploy.API.get(podMatch)) {
|
|
30
|
+
shellExec(`sudo kubectl cp ${value} ${nameSpace}/${pod.NAME}:${podScriptPath}`);
|
|
31
|
+
const cmd = `node ${podScriptPath}`;
|
|
32
|
+
shellExec(`sudo kubectl exec -i ${pod.NAME} -- sh -c "${cmd}"`);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
for (const pod of UnderpostDeploy.API.get(podMatch)) {
|
|
36
|
+
shellExec(`sudo kubectl exec -i ${pod.NAME} -- sh -c "${value}"`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
18
42
|
shellExec(`cd ${npmRoot} && npm run ${key}`);
|
|
19
43
|
},
|
|
20
44
|
get(key) {
|
package/src/cli/test.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { timer } from '../client/components/core/CommonJs.js';
|
|
1
2
|
import { MariaDB } from '../db/mariadb/MariaDB.js';
|
|
2
3
|
import { getNpmRootPath } from '../server/conf.js';
|
|
3
4
|
import { actionInitLog, loggerFactory, setUpInfo } from '../server/logger.js';
|
|
@@ -28,9 +29,17 @@ class UnderpostTest {
|
|
|
28
29
|
actionInitLog();
|
|
29
30
|
shellExec(`cd ${getNpmRootPath()}/underpost && npm run test`);
|
|
30
31
|
},
|
|
31
|
-
async callback(deployList = '', options = {
|
|
32
|
+
async callback(deployList = '', options = { itc: false, sh: false, logs: false }) {
|
|
33
|
+
if (
|
|
34
|
+
options.podName &&
|
|
35
|
+
typeof options.podName === 'string' &&
|
|
36
|
+
options.podStatus &&
|
|
37
|
+
typeof options.podStatus === 'string'
|
|
38
|
+
)
|
|
39
|
+
return await UnderpostTest.API.statusMonitor(options.podName, options.podStatus, options.kindType);
|
|
40
|
+
|
|
32
41
|
if (options.sh === true || options.logs === true) {
|
|
33
|
-
const [pod] = UnderpostDeploy.API.
|
|
42
|
+
const [pod] = UnderpostDeploy.API.get(deployList);
|
|
34
43
|
if (pod) {
|
|
35
44
|
if (options.sh) return pbcopy(`sudo kubectl exec -it ${pod.NAME} -- sh`);
|
|
36
45
|
if (options.logs) return shellExec(`sudo kubectl logs -f ${pod.NAME}`);
|
|
@@ -41,7 +50,7 @@ class UnderpostTest {
|
|
|
41
50
|
for (const _deployId of deployList.split(',')) {
|
|
42
51
|
const deployId = _deployId.trim();
|
|
43
52
|
if (!deployId) continue;
|
|
44
|
-
if (options.
|
|
53
|
+
if (options.itc === true)
|
|
45
54
|
switch (deployId) {
|
|
46
55
|
case 'dd-lampp':
|
|
47
56
|
{
|
|
@@ -64,7 +73,7 @@ class UnderpostTest {
|
|
|
64
73
|
break;
|
|
65
74
|
}
|
|
66
75
|
else {
|
|
67
|
-
const pods = UnderpostDeploy.API.
|
|
76
|
+
const pods = UnderpostDeploy.API.get(deployId);
|
|
68
77
|
if (pods.length > 0)
|
|
69
78
|
for (const deployData of pods) {
|
|
70
79
|
const { NAME } = deployData;
|
|
@@ -77,6 +86,32 @@ class UnderpostTest {
|
|
|
77
86
|
}
|
|
78
87
|
} else return UnderpostTest.API.run();
|
|
79
88
|
},
|
|
89
|
+
statusMonitor(podName, status = 'Running', kindType = '', deltaMs = 1000, maxAttempts = 60 * 5) {
|
|
90
|
+
if (!(kindType && typeof kindType === 'string')) kindType = 'pods';
|
|
91
|
+
return new Promise(async (resolve) => {
|
|
92
|
+
let index = 0;
|
|
93
|
+
logger.info(`Loading instance`, { podName, status, kindType, deltaMs, maxAttempts });
|
|
94
|
+
const _monitor = async () => {
|
|
95
|
+
await timer(deltaMs);
|
|
96
|
+
const pods = UnderpostDeploy.API.get(podName, kindType);
|
|
97
|
+
const result = pods.find((p) => p.STATUS === status);
|
|
98
|
+
logger.info(
|
|
99
|
+
`Testing pod ${podName}... ${result ? 1 : 0}/1 - elapsed time ${deltaMs * (index + 1)}s - attempt ${
|
|
100
|
+
index + 1
|
|
101
|
+
}/${maxAttempts}`,
|
|
102
|
+
pods[0] ? pods[0].STATUS : 'Not found kind object',
|
|
103
|
+
);
|
|
104
|
+
if (result) return resolve(true);
|
|
105
|
+
index++;
|
|
106
|
+
if (index === maxAttempts) {
|
|
107
|
+
logger.error(`Failed to test pod ${podName} within ${maxAttempts} attempts`);
|
|
108
|
+
return resolve(false);
|
|
109
|
+
}
|
|
110
|
+
return _monitor();
|
|
111
|
+
};
|
|
112
|
+
await _monitor();
|
|
113
|
+
});
|
|
114
|
+
},
|
|
80
115
|
};
|
|
81
116
|
}
|
|
82
117
|
|
|
@@ -404,7 +404,15 @@ const CalendarCore = {
|
|
|
404
404
|
<div class="in" style="margin-bottom: 100px"></div>`;
|
|
405
405
|
};
|
|
406
406
|
|
|
407
|
+
let delayBlock = false;
|
|
407
408
|
this.Data[options.idModal].updatePanel = async () => {
|
|
409
|
+
if (delayBlock) return;
|
|
410
|
+
else {
|
|
411
|
+
delayBlock = true;
|
|
412
|
+
setTimeout(() => {
|
|
413
|
+
delayBlock = false;
|
|
414
|
+
}, 500);
|
|
415
|
+
}
|
|
408
416
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
409
417
|
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
410
418
|
if (s(`.main-body-calendar-${options.idModal}`)) {
|
|
@@ -426,7 +434,10 @@ const CalendarCore = {
|
|
|
426
434
|
},
|
|
427
435
|
});
|
|
428
436
|
|
|
429
|
-
if (options.route === 'home')
|
|
437
|
+
// if (options.route === 'home')
|
|
438
|
+
setTimeout(() => {
|
|
439
|
+
CalendarCore.Data[options.idModal].updatePanel();
|
|
440
|
+
});
|
|
430
441
|
|
|
431
442
|
return html`
|
|
432
443
|
<style>
|
|
@@ -890,8 +890,58 @@ const commitData = {
|
|
|
890
890
|
},
|
|
891
891
|
};
|
|
892
892
|
|
|
893
|
-
const
|
|
893
|
+
const emotionsData = [
|
|
894
|
+
{
|
|
895
|
+
name: 'like',
|
|
896
|
+
ad_display: {
|
|
897
|
+
es: 'Me gusta',
|
|
898
|
+
en: 'Like',
|
|
899
|
+
},
|
|
900
|
+
emoji: '👍',
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
name: 'love',
|
|
904
|
+
ad_display: {
|
|
905
|
+
es: 'Me encanta',
|
|
906
|
+
en: 'Love',
|
|
907
|
+
},
|
|
908
|
+
emoji: '❤️',
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
name: 'haha',
|
|
912
|
+
ad_display: {
|
|
913
|
+
es: 'Me divierte',
|
|
914
|
+
en: 'Haha',
|
|
915
|
+
},
|
|
916
|
+
emoji: '😂',
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
name: 'wow',
|
|
920
|
+
ad_display: {
|
|
921
|
+
es: 'Me asombra',
|
|
922
|
+
en: 'Wow',
|
|
923
|
+
},
|
|
924
|
+
emoji: '😮',
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
name: 'sad',
|
|
928
|
+
ad_display: {
|
|
929
|
+
es: 'Me entristece',
|
|
930
|
+
en: 'Sad',
|
|
931
|
+
},
|
|
932
|
+
emoji: '😢',
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
name: 'angry',
|
|
936
|
+
ad_display: {
|
|
937
|
+
es: 'Me enoja',
|
|
938
|
+
en: 'Angry',
|
|
939
|
+
},
|
|
940
|
+
emoji: '😠',
|
|
941
|
+
},
|
|
942
|
+
];
|
|
894
943
|
|
|
944
|
+
const userRoleEnum = ['admin', 'moderator', 'user', 'guest'];
|
|
895
945
|
const commonAdminGuard = (role) => userRoleEnum.indexOf(role) === userRoleEnum.indexOf('admin');
|
|
896
946
|
const commonModeratorGuard = (role) => userRoleEnum.indexOf(role) <= userRoleEnum.indexOf('moderator');
|
|
897
947
|
|
|
@@ -954,4 +1004,5 @@ export {
|
|
|
954
1004
|
getCurrentTrace,
|
|
955
1005
|
userRoleEnum,
|
|
956
1006
|
commitData,
|
|
1007
|
+
emotionsData,
|
|
957
1008
|
};
|