underpost 3.1.3 → 3.2.2
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.example +0 -2
- package/.github/workflows/ghpkg.ci.yml +4 -4
- package/.github/workflows/npmpkg.ci.yml +28 -11
- package/.github/workflows/publish.ci.yml +6 -0
- package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
- package/.github/workflows/release.cd.yml +13 -8
- package/CHANGELOG.md +396 -1
- package/CLI-HELP.md +53 -6
- package/Dockerfile +4 -2
- package/README.md +3 -2
- package/bin/build.js +18 -12
- package/bin/deploy.js +177 -124
- package/bin/file.js +3 -0
- package/conf.js +3 -2
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +5 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +88 -74
- package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +22 -15
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/file/file.ref.json +18 -0
- package/src/api/user/user.service.js +8 -7
- package/src/cli/cluster.js +7 -7
- package/src/cli/db.js +726 -825
- package/src/cli/deploy.js +151 -93
- package/src/cli/env.js +19 -0
- package/src/cli/fs.js +5 -2
- package/src/cli/index.js +45 -2
- package/src/cli/kubectl.js +211 -0
- package/src/cli/release.js +284 -0
- package/src/cli/repository.js +434 -75
- package/src/cli/run.js +189 -34
- package/src/cli/secrets.js +73 -0
- package/src/cli/test.js +3 -3
- package/src/client/Default.index.js +3 -4
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/CalendarCore.js +2 -2
- package/src/client/components/core/DropDown.js +137 -17
- package/src/client/components/core/Keyboard.js +2 -2
- package/src/client/components/core/LogIn.js +2 -2
- package/src/client/components/core/LogOut.js +2 -2
- package/src/client/components/core/Modal.js +0 -1
- package/src/client/components/core/Panel.js +0 -1
- package/src/client/components/core/PanelForm.js +19 -19
- package/src/client/components/core/SocketIo.js +82 -29
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/LogInDefault.js +3 -3
- package/src/client/components/default/LogOutDefault.js +2 -2
- package/src/client/components/default/MenuDefault.js +5 -5
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/services/core/core.service.js +20 -8
- package/src/client/services/user/user.management.js +2 -2
- package/src/index.js +24 -1
- package/src/runtime/express/Dockerfile +4 -0
- package/src/runtime/express/Express.js +18 -1
- package/src/runtime/lampp/Dockerfile +13 -2
- package/src/runtime/lampp/Lampp.js +27 -4
- package/src/runtime/wp/Dockerfile +68 -0
- package/src/runtime/wp/Wp.js +639 -0
- package/src/server/auth.js +24 -1
- package/src/server/backup.js +57 -23
- package/src/server/client-build-docs.js +9 -2
- package/src/server/client-build.js +31 -31
- package/src/server/client-formatted.js +109 -57
- package/src/server/cron.js +23 -18
- package/src/server/ipfs-client.js +24 -1
- package/src/server/peer.js +8 -0
- package/src/server/runtime.js +25 -1
- package/src/server/start.js +3 -2
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kubectl module providing low-level Kubernetes resource management primitives.
|
|
3
|
+
* Centralises pod querying, file transfer, and in-container execution operations
|
|
4
|
+
* that were previously scattered across db, deploy, and cluster modules.
|
|
5
|
+
* @module src/cli/kubectl.js
|
|
6
|
+
* @namespace UnderpostKubectl
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { loggerFactory } from '../server/logger.js';
|
|
10
|
+
import { shellExec } from '../server/process.js';
|
|
11
|
+
import Underpost from '../index.js';
|
|
12
|
+
|
|
13
|
+
const logger = loggerFactory(import.meta);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Redacts credentials from shell command strings before logging.
|
|
17
|
+
* Masks passwords in `-p<password>`, `--password=<password>`, and `-P <password>` patterns.
|
|
18
|
+
* @param {string} cmd - The raw command string.
|
|
19
|
+
* @returns {string} The command with credentials replaced by `***`.
|
|
20
|
+
* @memberof UnderpostKubectl
|
|
21
|
+
*/
|
|
22
|
+
const sanitizeCommand = (cmd) => {
|
|
23
|
+
if (typeof cmd !== 'string') return cmd;
|
|
24
|
+
return cmd
|
|
25
|
+
.replace(/-p['"]?[^\s'"]+/g, '-p***')
|
|
26
|
+
.replace(/--password=['"]?[^\s'"]+/g, '--password=***')
|
|
27
|
+
.replace(/-P\s+['"]?[^\s'"]+/g, '-P ***');
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @class UnderpostKubectl
|
|
32
|
+
* @description Kubernetes cluster resource management primitives.
|
|
33
|
+
* Provides a unified interface for kubectl operations: resource listing, in-pod
|
|
34
|
+
* command execution, file transfer, and pod discovery/filtering.
|
|
35
|
+
* All methods are stateless and safe to call from any other CLI module.
|
|
36
|
+
* @memberof UnderpostKubectl
|
|
37
|
+
*/
|
|
38
|
+
class UnderpostKubectl {
|
|
39
|
+
static API = {
|
|
40
|
+
/**
|
|
41
|
+
* Lists Kubernetes resources matching `deployId`, parsed into plain objects.
|
|
42
|
+
* Equivalent to `kubectl get <kindType> -o wide`, filtered by name substring.
|
|
43
|
+
* @param {string} deployId - Substring to match against resource names. Empty string returns all.
|
|
44
|
+
* @param {string} [kindType='pods'] - Resource kind: pods, deployments, svc, nodes, …
|
|
45
|
+
* @param {string} [namespace=''] - Namespace to query; empty string → --all-namespaces.
|
|
46
|
+
* @returns {Array<object>} Parsed rows keyed by column header (NAME, STATUS, NODE, …).
|
|
47
|
+
* @memberof UnderpostKubectl
|
|
48
|
+
*/
|
|
49
|
+
get(deployId, kindType = 'pods', namespace = '') {
|
|
50
|
+
const raw = shellExec(
|
|
51
|
+
`sudo kubectl get ${kindType}${namespace ? ` -n ${namespace}` : ` --all-namespaces`} -o wide`,
|
|
52
|
+
{ stdout: true, disableLog: true, silent: true },
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const heads = raw
|
|
56
|
+
.split(`\n`)[0]
|
|
57
|
+
.split(' ')
|
|
58
|
+
.filter((_r) => _r.trim());
|
|
59
|
+
|
|
60
|
+
const pods = raw
|
|
61
|
+
.split(`\n`)
|
|
62
|
+
.filter((r) => (deployId ? r.match(deployId) : r.trim() && !r.match('NAME')))
|
|
63
|
+
.map((r) => r.split(' ').filter((_r) => _r.trim()));
|
|
64
|
+
|
|
65
|
+
const result = [];
|
|
66
|
+
for (const row of pods) {
|
|
67
|
+
const pod = {};
|
|
68
|
+
let index = -1;
|
|
69
|
+
for (const head of heads) {
|
|
70
|
+
index++;
|
|
71
|
+
pod[head] = row[index];
|
|
72
|
+
}
|
|
73
|
+
result.push(pod);
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Executes a kubectl command with credential-safe logging and error propagation.
|
|
80
|
+
* @param {string} command - Full kubectl command string.
|
|
81
|
+
* @param {object} [options={}] - Execution options.
|
|
82
|
+
* @param {string} [options.context=''] - Human-readable label for log messages.
|
|
83
|
+
* @returns {string} stdout output from the command.
|
|
84
|
+
* @throws {Error} Re-throws any execution error after logging.
|
|
85
|
+
* @memberof UnderpostKubectl
|
|
86
|
+
*/
|
|
87
|
+
run(command, options = {}) {
|
|
88
|
+
const { context = '' } = options;
|
|
89
|
+
try {
|
|
90
|
+
logger.info(`Executing kubectl command`, { command: sanitizeCommand(command), context });
|
|
91
|
+
return shellExec(command, { stdout: true, disableLog: true });
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logger.error(`kubectl command failed`, { command: sanitizeCommand(command), error: error.message, context });
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Runs a shell command inside a pod container via `kubectl exec`.
|
|
100
|
+
* @param {object} params
|
|
101
|
+
* @param {string} params.podName - Target pod name.
|
|
102
|
+
* @param {string} params.namespace - Pod namespace.
|
|
103
|
+
* @param {string} params.command - Shell command to run inside the container.
|
|
104
|
+
* @returns {string} stdout output from the in-pod command.
|
|
105
|
+
* @throws {Error} Re-throws any execution error after logging.
|
|
106
|
+
* @memberof UnderpostKubectl
|
|
107
|
+
*/
|
|
108
|
+
exec({ podName, namespace, command }) {
|
|
109
|
+
try {
|
|
110
|
+
const kubectlCmd = `sudo kubectl exec -n ${namespace} -i ${podName} -- sh -c "${command}"`;
|
|
111
|
+
return Underpost.kubectl.run(kubectlCmd, { context: `exec in pod ${podName}` });
|
|
112
|
+
} catch (error) {
|
|
113
|
+
logger.error('Failed to execute command in pod', {
|
|
114
|
+
podName,
|
|
115
|
+
command: sanitizeCommand(command),
|
|
116
|
+
error: error.message,
|
|
117
|
+
});
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Copies a local file into a pod via `kubectl cp`.
|
|
124
|
+
* @param {object} params
|
|
125
|
+
* @param {string} params.sourcePath - Local source path.
|
|
126
|
+
* @param {string} params.podName - Target pod name.
|
|
127
|
+
* @param {string} params.namespace - Pod namespace.
|
|
128
|
+
* @param {string} params.destPath - Destination path inside the container.
|
|
129
|
+
* @returns {boolean} `true` on success, `false` on error.
|
|
130
|
+
* @memberof UnderpostKubectl
|
|
131
|
+
*/
|
|
132
|
+
cpTo({ sourcePath, podName, namespace, destPath }) {
|
|
133
|
+
try {
|
|
134
|
+
const command = `sudo kubectl cp ${sourcePath} ${namespace}/${podName}:${destPath}`;
|
|
135
|
+
Underpost.kubectl.run(command, { context: `copy to pod ${podName}` });
|
|
136
|
+
return true;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
logger.error('Failed to copy file to pod', { sourcePath, podName, destPath, error: error.message });
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Copies a file from a pod to the local filesystem via `kubectl cp`.
|
|
145
|
+
* @param {object} params
|
|
146
|
+
* @param {string} params.podName - Source pod name.
|
|
147
|
+
* @param {string} params.namespace - Pod namespace.
|
|
148
|
+
* @param {string} params.sourcePath - Source path inside the container.
|
|
149
|
+
* @param {string} params.destPath - Local destination path.
|
|
150
|
+
* @returns {boolean} `true` on success, `false` on error.
|
|
151
|
+
* @memberof UnderpostKubectl
|
|
152
|
+
*/
|
|
153
|
+
cpFrom({ podName, namespace, sourcePath, destPath }) {
|
|
154
|
+
try {
|
|
155
|
+
const command = `sudo kubectl cp ${namespace}/${podName}:${sourcePath} ${destPath}`;
|
|
156
|
+
Underpost.kubectl.run(command, { context: `copy from pod ${podName}` });
|
|
157
|
+
return true;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
logger.error('Failed to copy file from pod', { podName, sourcePath, destPath, error: error.message });
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Checks whether a file exists inside a pod container.
|
|
166
|
+
* @param {object} params
|
|
167
|
+
* @param {string} params.podName - Pod name.
|
|
168
|
+
* @param {string} params.path - Absolute path inside the container to test.
|
|
169
|
+
* @returns {boolean} `true` if the file exists.
|
|
170
|
+
* @memberof UnderpostKubectl
|
|
171
|
+
*/
|
|
172
|
+
existsFile({ podName, path }) {
|
|
173
|
+
const result = shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
174
|
+
stdout: true,
|
|
175
|
+
disableLog: true,
|
|
176
|
+
silent: true,
|
|
177
|
+
}).trim();
|
|
178
|
+
return result === 'true';
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Returns a filtered list of pods from the cluster.
|
|
183
|
+
* Supports wildcard glob patterns on pod names and optional deployId substring filtering.
|
|
184
|
+
* @param {object} [criteria={}] - Filter criteria.
|
|
185
|
+
* @param {string} [criteria.deployId] - Substring to match against pod names (forwards to `get`).
|
|
186
|
+
* @param {string} [criteria.podNames] - Comma-separated glob patterns (supports `*`).
|
|
187
|
+
* @param {string} [criteria.namespace='default'] - Kubernetes namespace to query.
|
|
188
|
+
* @returns {Array<object>} Filtered pod rows from `get`.
|
|
189
|
+
* @memberof UnderpostKubectl
|
|
190
|
+
*/
|
|
191
|
+
getFilteredPods(criteria = {}) {
|
|
192
|
+
const { podNames, namespace = 'default', deployId } = criteria;
|
|
193
|
+
try {
|
|
194
|
+
let pods = Underpost.kubectl.get(deployId || '', 'pods', namespace);
|
|
195
|
+
if (podNames) {
|
|
196
|
+
const patterns = podNames.split(',').map((p) => p.trim());
|
|
197
|
+
pods = pods.filter((pod) =>
|
|
198
|
+
patterns.some((pattern) => new RegExp('^' + pattern.replace(/\*/g, '.*') + '$').test(pod.NAME)),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
logger.info(`Found ${pods.length} pod(s) matching criteria`, { criteria, podNames: pods.map((p) => p.NAME) });
|
|
202
|
+
return pods;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
logger.error('Error filtering pods', { error: error.message, criteria });
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default UnderpostKubectl;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release orchestrator module for managing version builds and deployments of the Underpost CLI.
|
|
3
|
+
*
|
|
4
|
+
* Provides automated workflows for building new versions (bumping version numbers across
|
|
5
|
+
* all package files, manifests, and configurations) and deploying releases (committing,
|
|
6
|
+
* pushing, and syncing secrets to remote repositories).
|
|
7
|
+
*
|
|
8
|
+
* @module src/cli/release.js
|
|
9
|
+
* @namespace UnderpostRelease
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs-extra';
|
|
13
|
+
import dotenv from 'dotenv';
|
|
14
|
+
import { pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
15
|
+
import { loggerFactory } from '../server/logger.js';
|
|
16
|
+
import { timer } from '../client/components/core/CommonJs.js';
|
|
17
|
+
import Underpost from '../index.js';
|
|
18
|
+
|
|
19
|
+
const logger = loggerFactory(import.meta);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Kills any Node.js dev-server or nodemon processes that may hold file locks
|
|
23
|
+
* (e.g. overwriting package.json). Skips VSCode internals and the current process.
|
|
24
|
+
*/
|
|
25
|
+
function killDevServers() {
|
|
26
|
+
// shellExec(
|
|
27
|
+
// `kill -9 $(pgrep -f 'nodemon|node.*src/server|node.*dev' | grep -v '^${process.pid}$') 2>/dev/null || true`,
|
|
28
|
+
// );
|
|
29
|
+
shellExec(`node bin run kill 4001`);
|
|
30
|
+
shellExec(`node bin run kill 4002`);
|
|
31
|
+
shellExec(`node bin run kill 4003`);
|
|
32
|
+
shellExec(`node bin run kill 3000`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @class UnderpostRelease
|
|
37
|
+
* @description Orchestrates version builds and release deployments for the Underpost CLI.
|
|
38
|
+
* This class provides static methods to automate the full release lifecycle:
|
|
39
|
+
* building a new version (testing, bumping versions, rebuilding manifests)
|
|
40
|
+
* and deploying a release (syncing secrets, committing, and pushing to remotes).
|
|
41
|
+
* @memberof UnderpostRelease
|
|
42
|
+
*/
|
|
43
|
+
class UnderpostRelease {
|
|
44
|
+
static API = {
|
|
45
|
+
/**
|
|
46
|
+
* Builds a new version of the Underpost engine.
|
|
47
|
+
*
|
|
48
|
+
* Performs the full version build pipeline:
|
|
49
|
+
* 1. Loads production environment and pulls latest code.
|
|
50
|
+
* 2. Kills running dev servers on ports 4001-4003.
|
|
51
|
+
* 3. Builds and tests the pwa-microservices-template.
|
|
52
|
+
* 4. Bumps version in package.json, package-lock.json, and all conf package files.
|
|
53
|
+
* 5. Updates deployment YAML manifests and Docker image CI workflow with new version.
|
|
54
|
+
* 6. Updates src/index.js version string.
|
|
55
|
+
* 7. Rebuilds CLI docs, dependencies, client builds, deploy manifests, and default confs.
|
|
56
|
+
* 8. Syncs cron setup-start scripts and builds changelog.
|
|
57
|
+
*
|
|
58
|
+
* @method build
|
|
59
|
+
* @param {string} [newVersion] - The new version string to set. Defaults to current version if not provided.
|
|
60
|
+
* @param {object} [options] - Commander options object (unused, reserved for future flags).
|
|
61
|
+
* @memberof UnderpostRelease
|
|
62
|
+
*/
|
|
63
|
+
async build(newVersion, options) {
|
|
64
|
+
dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
|
|
65
|
+
shellCd(`/home/dd/engine`);
|
|
66
|
+
killDevServers();
|
|
67
|
+
Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
|
|
68
|
+
shellExec(`node bin pull . ${process.env.GITHUB_USERNAME}/engine`);
|
|
69
|
+
shellExec(`npm run update:template`);
|
|
70
|
+
shellExec(`cd ../pwa-microservices-template && npm install && npm run build`);
|
|
71
|
+
console.log(fs.existsSync(`../pwa-microservices-template/engine-private/conf/dd-default`));
|
|
72
|
+
shellExec(`cd ../pwa-microservices-template && ENABLE_FILE_LOGS=true timeout 5s npm run dev`, {
|
|
73
|
+
async: true,
|
|
74
|
+
});
|
|
75
|
+
await timer(5500);
|
|
76
|
+
const templateRunnerResult = fs.readFileSync(`../pwa-microservices-template/logs/start.js/all.log`, 'utf8');
|
|
77
|
+
logger.info('Test template runner result');
|
|
78
|
+
console.log(templateRunnerResult);
|
|
79
|
+
if (!templateRunnerResult || templateRunnerResult.toLowerCase().match('error')) {
|
|
80
|
+
logger.error('Test template runner result failed');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
killDevServers();
|
|
84
|
+
shellCd(`/home/dd/engine`);
|
|
85
|
+
Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
|
|
86
|
+
const originPackageJson = JSON.parse(fs.readFileSync(`package.json`, 'utf8'));
|
|
87
|
+
if (!newVersion) newVersion = originPackageJson.version;
|
|
88
|
+
const { version } = originPackageJson;
|
|
89
|
+
originPackageJson.version = newVersion;
|
|
90
|
+
fs.writeFileSync(`package.json`, JSON.stringify(originPackageJson, null, 4), 'utf8');
|
|
91
|
+
|
|
92
|
+
const originPackageLockJson = JSON.parse(fs.readFileSync(`package-lock.json`, 'utf8'));
|
|
93
|
+
originPackageLockJson.version = newVersion;
|
|
94
|
+
originPackageLockJson.packages[''].version = newVersion;
|
|
95
|
+
fs.writeFileSync(`package-lock.json`, JSON.stringify(originPackageLockJson, null, 4), 'utf8');
|
|
96
|
+
|
|
97
|
+
if (fs.existsSync(`./engine-private/conf`)) {
|
|
98
|
+
const files = await fs.readdir(`./engine-private/conf`, { recursive: true });
|
|
99
|
+
for (const relativePath of files) {
|
|
100
|
+
const filePah = `./engine-private/conf/${relativePath.replaceAll(`\\`, '/')}`;
|
|
101
|
+
if (filePah.split('/').pop() === 'package.json') {
|
|
102
|
+
const originPackage = JSON.parse(fs.readFileSync(filePah, 'utf8'));
|
|
103
|
+
originPackage.version = newVersion;
|
|
104
|
+
fs.writeFileSync(filePah, JSON.stringify(originPackage, null, 4), 'utf8');
|
|
105
|
+
}
|
|
106
|
+
if (filePah.split('/').pop() === 'deployment.yaml') {
|
|
107
|
+
fs.writeFileSync(
|
|
108
|
+
filePah,
|
|
109
|
+
fs
|
|
110
|
+
.readFileSync(filePah, 'utf8')
|
|
111
|
+
.replaceAll(`v${version}`, `v${newVersion}`)
|
|
112
|
+
.replaceAll(`engine.version: ${version}`, `engine.version: ${newVersion}`),
|
|
113
|
+
'utf8',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fs.writeFileSync(
|
|
120
|
+
`./manifests/deployment/dd-default-development/deployment.yaml`,
|
|
121
|
+
fs
|
|
122
|
+
.readFileSync(`./manifests/deployment/dd-default-development/deployment.yaml`, 'utf8')
|
|
123
|
+
.replaceAll(`underpost:v${version}`, `underpost:v${newVersion}`),
|
|
124
|
+
'utf8',
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (fs.existsSync(`./.github/workflows/docker-image.ci.yml`))
|
|
128
|
+
fs.writeFileSync(
|
|
129
|
+
`./.github/workflows/docker-image.ci.yml`,
|
|
130
|
+
fs
|
|
131
|
+
.readFileSync(`./.github/workflows/docker-image.ci.yml`, 'utf8')
|
|
132
|
+
.replaceAll(`underpost-engine:v${version}`, `underpost-engine:v${newVersion}`),
|
|
133
|
+
'utf8',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
fs.writeFileSync(
|
|
137
|
+
`./src/index.js`,
|
|
138
|
+
fs.readFileSync(`./src/index.js`, 'utf8').replaceAll(`${version}`, `${newVersion}`),
|
|
139
|
+
'utf8',
|
|
140
|
+
);
|
|
141
|
+
shellExec(`node bin/deploy cli-docs ${version} ${newVersion}`);
|
|
142
|
+
shellExec(`node bin/deploy update-dependencies`);
|
|
143
|
+
shellExec(`node bin/build dd`);
|
|
144
|
+
shellExec(`node bin deploy --build-manifest --sync --info-router --replicas 1 dd production`);
|
|
145
|
+
shellExec(`node bin deploy --build-manifest --sync --info-router --replicas 1 dd development`);
|
|
146
|
+
shellExec(`node bin/deploy build-default-confs`);
|
|
147
|
+
shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
|
|
148
|
+
shellExec(`node bin new --deploy-id dd-default`);
|
|
149
|
+
console.log(fs.existsSync(`./engine-private/conf/dd-default`));
|
|
150
|
+
shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
|
|
151
|
+
shellExec(`node bin cron --dev --setup-start`);
|
|
152
|
+
shellExec(`node bin cmt --changelog-build`);
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Runs the local equivalent of an engine-*.ci.yml GitHub Actions workflow.
|
|
157
|
+
*
|
|
158
|
+
* Mirrors the CI pipeline locally:
|
|
159
|
+
* 1. Loads production environment (for GITHUB_TOKEN / GITHUB_USERNAME).
|
|
160
|
+
* 2. Clones pwa-microservices-template and engine-{suffix} (bare) into the parent dir (/home/dd).
|
|
161
|
+
* 3. Builds dd-{suffix} development from the engine directory.
|
|
162
|
+
* 4. Replaces .git in pwa-microservices-template with the bare-cloned git, then commits and pushes
|
|
163
|
+
* to the underpostnet/engine-{suffix} remote repository.
|
|
164
|
+
*
|
|
165
|
+
* @method ci
|
|
166
|
+
* @param {string} deployId - The deploy-id suffix (e.g., "cyberia", "core", "lampp", "test").
|
|
167
|
+
* Accepts "cyberia", "dd-cyberia", or "engine-cyberia" — the prefix is stripped automatically.
|
|
168
|
+
* @param {string} [message] - Optional commit message. Defaults to the last commit message of pwa-microservices-template.
|
|
169
|
+
* @param {object} [options] - Commander options object (unused, reserved for future flags).
|
|
170
|
+
* @memberof UnderpostRelease
|
|
171
|
+
*/
|
|
172
|
+
async ci(deployId, message, options) {
|
|
173
|
+
dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
|
|
174
|
+
const suffix = deployId.replace(/^(dd-|engine-)/, '');
|
|
175
|
+
const repoName = `engine-${suffix}`;
|
|
176
|
+
const buildTarget = `dd-${suffix}`;
|
|
177
|
+
const githubOrg = process.env.GITHUB_USERNAME || 'underpostnet';
|
|
178
|
+
shellCd('/home/dd');
|
|
179
|
+
shellExec(`sudo rm -rf /home/dd/pwa-microservices-template`);
|
|
180
|
+
shellExec(`node engine/bin clone ${githubOrg}/pwa-microservices-template`);
|
|
181
|
+
// Use the message passed from the caller (engine repo changelog);
|
|
182
|
+
// fall back to the engine repo's last commit if not provided.
|
|
183
|
+
let commitMsg = message;
|
|
184
|
+
if (!commitMsg) {
|
|
185
|
+
shellCd('/home/dd/engine');
|
|
186
|
+
const rawMsg = shellExec(`node bin cmt --changelog 1 --changelog-no-hash`, {
|
|
187
|
+
stdout: true,
|
|
188
|
+
silent: true,
|
|
189
|
+
}).trim();
|
|
190
|
+
commitMsg = Underpost.repo.sanitizeChangelogMessage(rawMsg);
|
|
191
|
+
shellCd('/home/dd');
|
|
192
|
+
}
|
|
193
|
+
commitMsg = (commitMsg || '').trim() || `Update ${repoName} repository`;
|
|
194
|
+
logger.info(`CI push commit message: ${commitMsg}`);
|
|
195
|
+
shellExec(`node engine/bin clone --bare ${githubOrg}/${repoName}`);
|
|
196
|
+
shellCd('/home/dd/engine');
|
|
197
|
+
shellExec(`node bin/build ${buildTarget}`);
|
|
198
|
+
shellCd('/home/dd/pwa-microservices-template');
|
|
199
|
+
shellExec(`rm -rf ./.git`);
|
|
200
|
+
shellExec(`mv ../${repoName}.git ./.git`);
|
|
201
|
+
shellExec(`git config --local core.bare false`);
|
|
202
|
+
shellExec(`git reset`);
|
|
203
|
+
Underpost.repo.initLocalRepo({ path: '/home/dd/pwa-microservices-template' });
|
|
204
|
+
return {
|
|
205
|
+
triggerCmd: `cd /home/dd/pwa-microservices-template && git add . && git commit -m "${commitMsg}" && node ../engine/bin push . ${githubOrg}/${repoName}`,
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Runs the pwa-microservices-template update and push flow locally.
|
|
211
|
+
*
|
|
212
|
+
* Always removes and re-clones pwa-microservices-template, then:
|
|
213
|
+
* 1. Runs update:template (node bin/file update-template) to sync engine sources.
|
|
214
|
+
* 2. Installs dependencies and builds the template.
|
|
215
|
+
* 3. Commits and pushes to the pwa-microservices-template remote repository.
|
|
216
|
+
*
|
|
217
|
+
* @method pwa
|
|
218
|
+
* @param {string} [message] - Optional commit message. Defaults to last commit message of pwa-microservices-template.
|
|
219
|
+
* @param {object} [options] - Commander options object (unused, reserved for future flags).
|
|
220
|
+
* @memberof UnderpostRelease
|
|
221
|
+
*/
|
|
222
|
+
async pwa(message, options) {
|
|
223
|
+
dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
|
|
224
|
+
const githubOrg = process.env.GITHUB_USERNAME || 'underpostnet';
|
|
225
|
+
// Use the message passed from the caller (engine repo changelog);
|
|
226
|
+
// fall back to the engine repo's last commit if not provided.
|
|
227
|
+
let commitMsg = message;
|
|
228
|
+
if (!commitMsg) {
|
|
229
|
+
shellCd('/home/dd/engine');
|
|
230
|
+
const rawMsg = shellExec(`node bin cmt --changelog 1 --changelog-no-hash`, {
|
|
231
|
+
stdout: true,
|
|
232
|
+
silent: true,
|
|
233
|
+
}).trim();
|
|
234
|
+
commitMsg = Underpost.repo.sanitizeChangelogMessage(rawMsg);
|
|
235
|
+
}
|
|
236
|
+
commitMsg = (commitMsg || '').trim() || `Update pwa-microservices-template repository`;
|
|
237
|
+
shellCd('/home/dd');
|
|
238
|
+
shellExec(`sudo rm -rf /home/dd/pwa-microservices-template`);
|
|
239
|
+
shellExec(`node engine/bin clone ${githubOrg}/pwa-microservices-template`);
|
|
240
|
+
shellCd('/home/dd/engine');
|
|
241
|
+
shellExec(`npm run update:template`);
|
|
242
|
+
shellExec(`cd ../pwa-microservices-template && npm install && npm run build`);
|
|
243
|
+
shellCd('/home/dd/pwa-microservices-template');
|
|
244
|
+
shellExec(`git add .`);
|
|
245
|
+
// shellExec(`git commit -m "${commitMsg}"`);
|
|
246
|
+
return {
|
|
247
|
+
triggerCmd: `node bin push . ${githubOrg}/engine && cd /home/dd/pwa-microservices-template && git commit -m "${commitMsg}" && node ../engine/bin push . ${githubOrg}/pwa-microservices-template`,
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Deploys a new version release to remote repositories.
|
|
253
|
+
*
|
|
254
|
+
* Performs the release deployment pipeline:
|
|
255
|
+
* 1. Loads production environment from dd-cron.
|
|
256
|
+
* 2. Syncs Underpost secrets from the production env file.
|
|
257
|
+
* 3. Builds the dd configuration.
|
|
258
|
+
* 4. Stages all changes in both engine and engine-private repositories.
|
|
259
|
+
* 5. Commits with a release message including the version tag.
|
|
260
|
+
* 6. Pushes both repositories to their respective GitHub remotes.
|
|
261
|
+
*
|
|
262
|
+
* @method deploy
|
|
263
|
+
* @param {string} [version] - The version string for the release commit message (e.g., "3.1.4").
|
|
264
|
+
* @param {object} [options] - Commander options object (unused, reserved for future flags).
|
|
265
|
+
* @memberof UnderpostRelease
|
|
266
|
+
*/
|
|
267
|
+
async deploy(version, options) {
|
|
268
|
+
dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
|
|
269
|
+
killDevServers();
|
|
270
|
+
shellExec(
|
|
271
|
+
`node bin secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
|
|
272
|
+
);
|
|
273
|
+
shellExec(`node bin/build dd conf`);
|
|
274
|
+
shellExec(`git add . && cd ./engine-private && git add .`);
|
|
275
|
+
shellExec(`node bin cmt . ci package-pwa-microservices-template 'New release v:${version}'`);
|
|
276
|
+
shellExec(`node bin cmt ./engine-private ci package-pwa-microservices-template`);
|
|
277
|
+
shellExec(`node bin push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
278
|
+
shellExec(`cd ./engine-private && node ../bin push . ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export { UnderpostRelease };
|
|
284
|
+
export default UnderpostRelease;
|