cyberia 3.2.9 → 3.2.22
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/engine-cyberia.cd.yml +7 -0
- package/.github/workflows/engine-cyberia.ci.yml +14 -2
- package/.github/workflows/ghpkg.ci.yml +1 -0
- package/.github/workflows/npmpkg.ci.yml +10 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -0
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +363 -1
- package/CLI-HELP.md +975 -1061
- package/README.md +190 -348
- package/bin/build.js +102 -125
- package/bin/build.template.js +33 -0
- package/bin/cyberia.js +238 -56
- package/bin/deploy.js +16 -3
- package/bin/index.js +238 -56
- package/bump.config.js +26 -0
- package/conf.js +131 -24
- package/deployment.yaml +76 -2
- package/hardhat/package-lock.json +113 -144
- package/hardhat/package.json +4 -3
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +76 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +31 -19
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/scripts/test-monitor.sh +250 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +38 -33
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +16 -16
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +5 -5
- package/src/api/crypto/crypto.router.js +18 -12
- package/src/api/crypto/crypto.service.js +3 -3
- package/src/api/cyberia-action/cyberia-action.model.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +22 -18
- package/src/api/cyberia-action/cyberia-action.service.js +5 -5
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +25 -20
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +6 -6
- package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
- package/src/api/cyberia-entity/cyberia-entity.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-fallback-world.js +79 -4
- package/src/api/cyberia-instance/cyberia-instance.router.js +57 -52
- package/src/api/cyberia-instance/cyberia-instance.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-world-generator.js +3 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +14 -48
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +5 -5
- package/src/api/cyberia-map/cyberia-map.router.js +35 -30
- package/src/api/cyberia-map/cyberia-map.service.js +7 -7
- package/src/api/cyberia-quest/cyberia-quest.model.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +22 -18
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +22 -18
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +5 -5
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +458 -0
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +5 -5
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +9 -7
- package/src/api/instance/instance.router.js +29 -24
- package/src/api/instance/instance.service.js +6 -6
- package/src/api/ipfs/ipfs.router.js +21 -16
- package/src/api/ipfs/ipfs.service.js +8 -8
- package/src/api/object-layer/object-layer.router.js +512 -507
- package/src/api/object-layer/object-layer.service.js +17 -14
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +22 -18
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +5 -5
- package/src/api/test/test.router.js +17 -12
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +5 -4
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +100 -35
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +700 -232
- package/src/cli/db.js +59 -60
- package/src/cli/deploy.js +291 -294
- package/src/cli/env.js +1 -4
- package/src/cli/fs.js +13 -3
- package/src/cli/image.js +58 -4
- package/src/cli/index.js +127 -15
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +396 -9
- package/src/cli/release.js +355 -146
- package/src/cli/repository.js +169 -30
- package/src/cli/run.js +347 -117
- package/src/cli/secrets.js +11 -2
- package/src/cli/test.js +9 -3
- package/src/client/Default.index.js +9 -3
- package/src/client/components/core/Auth.js +5 -0
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/client/components/core/PanelForm.js +14 -10
- package/src/client/components/core/Worker.js +162 -363
- package/src/client/components/cyberia/MapEngineCyberia.js +1 -1
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +330 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +55 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +223 -361
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +114 -327
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +200 -222
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +212 -185
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +2 -2
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +23 -1
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +982 -0
- package/src/client/sw/core.sw.js +174 -112
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +130 -21
- package/src/grpc/cyberia/grpc-server.js +25 -57
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +10 -7
- package/src/runtime/cyberia-client/Dockerfile.dev +67 -0
- package/src/runtime/cyberia-server/Dockerfile +11 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +47 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Dockerfile +3 -3
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/catalog-underpost.js +61 -0
- package/src/server/catalog.js +77 -0
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +496 -135
- package/src/server/ipfs-client.js +5 -3
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime-status.js +235 -0
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +44 -11
- package/src/server/valkey.js +2 -0
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- package/test/deploy-monitor.test.js +251 -0
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/manifests/deployment/dd-test-development/deployment.yaml +0 -254
- package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -574
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +0 -467
- package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
- /package/src/client/ssr/{offline → views}/Maintenance.js +0 -0
- /package/src/client/ssr/{offline → views}/NoNetworkConnection.js +0 -0
- /package/src/client/ssr/{pages → views}/Test.js +0 -0
package/src/cli/release.js
CHANGED
|
@@ -10,26 +10,308 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import fs from 'fs-extra';
|
|
13
|
+
import path from 'path';
|
|
13
14
|
import dotenv from 'dotenv';
|
|
14
15
|
import { pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
16
|
+
import { Dns } from '../server/dns.js';
|
|
15
17
|
import { loggerFactory } from '../server/logger.js';
|
|
16
18
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
17
19
|
import Underpost from '../index.js';
|
|
18
20
|
|
|
19
21
|
const logger = loggerFactory(import.meta);
|
|
20
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Files that must never be touched by a version bump, even if they happen to contain a
|
|
25
|
+
* literal version string. CHANGELOG is historical; logs/ and node_modules/ are runtime
|
|
26
|
+
* outputs; engine-private/.env.* and secrets must not be rewritten by regex.
|
|
27
|
+
*/
|
|
28
|
+
const VERSION_BUMP_SKIP = [
|
|
29
|
+
/(^|\/)CHANGELOG\.md$/i,
|
|
30
|
+
/(^|\/)logs\//,
|
|
31
|
+
/(^|\/)node_modules\//,
|
|
32
|
+
/(^|\/)\.git\//,
|
|
33
|
+
/(^|\/)engine-private\/.*\.env(\..*)?$/,
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const isSkipped = (filePath) => VERSION_BUMP_SKIP.some((re) => re.test(filePath));
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Declarative regex-based version bump targets for files bumpp cannot handle natively
|
|
40
|
+
* (image tags, doc strings, README badges, build-args, etc.).
|
|
41
|
+
*
|
|
42
|
+
* Each target is one of:
|
|
43
|
+
* - { file: 'path/to/file', patterns: RegExp | RegExp[] }
|
|
44
|
+
* - { dir: 'dir', match: RegExp, patterns: RegExp | RegExp[], recursive?: boolean }
|
|
45
|
+
*
|
|
46
|
+
* Every pattern MUST have exactly one capture group: the prefix to preserve. The replacement
|
|
47
|
+
* is `$1<newVersion>`. Use a lookahead `(?=...)` to anchor a trailing context (closing quote,
|
|
48
|
+
* backtick, etc.) without consuming it. This keeps the callback signature trivial.
|
|
49
|
+
*
|
|
50
|
+
* The walker iterates targets, applies patterns to each matching file, and reports the
|
|
51
|
+
* number of substitutions per file. Files that match nothing are silently skipped.
|
|
52
|
+
*/
|
|
53
|
+
const buildVersionBumpTargets = () => [
|
|
54
|
+
// ── src/index.js — anchored to the static class field, never a bare replaceAll. ──
|
|
55
|
+
{
|
|
56
|
+
file: 'src/index.js',
|
|
57
|
+
patterns: /(static version = ['"]v)\d+\.\d+\.\d+(?=['"])/g,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// ── README + CLI-HELP fallbacks. CLI-HELP is regenerated by `deploy cli-docs`, but bump
|
|
61
|
+
// it too so the file is consistent if the regeneration step is skipped. ──
|
|
62
|
+
{
|
|
63
|
+
file: 'README.md',
|
|
64
|
+
patterns: [
|
|
65
|
+
/(socket\.dev\/api\/badge\/npm\/package\/underpost\/)\d+\.\d+\.\d+/g,
|
|
66
|
+
/(socket\.dev\/npm\/package\/underpost\/overview\/)\d+\.\d+\.\d+/g,
|
|
67
|
+
/(ci\/cd cli v)\d+\.\d+\.\d+/gi,
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
file: 'CLI-HELP.md',
|
|
72
|
+
patterns: /(ci\/cd cli v)\d+\.\d+\.\d+/gi,
|
|
73
|
+
optional: true,
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// ── Cyberia + nexodev docs. ──
|
|
77
|
+
{
|
|
78
|
+
dir: 'src/client/public/cyberia-docs',
|
|
79
|
+
match: /\.md$/,
|
|
80
|
+
patterns: [/(\*\*(?:Current )?[Vv]ersion:\*\* )\d+\.\d+\.\d+/g, /(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g],
|
|
81
|
+
recursive: true,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
dir: 'src/client/public/nexodev/docs/references',
|
|
85
|
+
match: /\.md$/,
|
|
86
|
+
patterns: [
|
|
87
|
+
/(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g,
|
|
88
|
+
/(UNDERPOST_VERSION=)\d+\.\d+\.\d+/g,
|
|
89
|
+
/(ci\/cd cli v)\d+\.\d+\.\d+/gi,
|
|
90
|
+
// version tag bumps inside markdown narrative, e.g. `v3.2.9`, `v3.2.10`, …
|
|
91
|
+
/(`v)\d+\.\d+\.\d+(?=`)/g,
|
|
92
|
+
],
|
|
93
|
+
recursive: true,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
// ── Kubernetes manifests. Covers deployment.yaml + cronjob yamls under dd-cron. ──
|
|
97
|
+
{
|
|
98
|
+
dir: 'manifests/deployment',
|
|
99
|
+
match: /deployment\.yaml$/,
|
|
100
|
+
patterns: [/(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g, /(engine\.version: )\d+\.\d+\.\d+/g],
|
|
101
|
+
recursive: true,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
dir: 'manifests/cronjobs',
|
|
105
|
+
match: /\.yaml$/,
|
|
106
|
+
patterns: /(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g,
|
|
107
|
+
recursive: true,
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// ── GitHub Actions workflows. Single sweep across docker-image.*.ci.yml, engine-*.cd.yml,
|
|
111
|
+
// and the root docker-image.ci.yml — replaces previous three separate loops. ──
|
|
112
|
+
{
|
|
113
|
+
dir: '.github/workflows',
|
|
114
|
+
match: /\.(yml|yaml)$/,
|
|
115
|
+
patterns: [
|
|
116
|
+
/(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g,
|
|
117
|
+
/(underpost-engine:v)\d+\.\d+\.\d+/g,
|
|
118
|
+
/(type=raw,value=v)\d+\.\d+\.\d+/g,
|
|
119
|
+
/(UNDERPOST_VERSION=)\d+\.\d+\.\d+/g,
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// ── engine-private confs (gitignored — bumped only if present). ──
|
|
124
|
+
{
|
|
125
|
+
dir: 'engine-private/conf',
|
|
126
|
+
match: /(?:deployment\.yaml|conf\.instances\.json)$/,
|
|
127
|
+
patterns: [
|
|
128
|
+
/(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g,
|
|
129
|
+
/(underpost-engine:v)\d+\.\d+\.\d+/g,
|
|
130
|
+
/(engine\.version: )\d+\.\d+\.\d+/g,
|
|
131
|
+
/(v)\d+\.\d+\.\d+/g,
|
|
132
|
+
],
|
|
133
|
+
recursive: true,
|
|
134
|
+
optional: true,
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Walks a directory (optionally recursively) and returns paths matching `match`.
|
|
140
|
+
*/
|
|
141
|
+
const walkDir = (dir, match, recursive) => {
|
|
142
|
+
if (!fs.existsSync(dir)) return [];
|
|
143
|
+
const out = [];
|
|
144
|
+
const stack = [dir];
|
|
145
|
+
while (stack.length) {
|
|
146
|
+
const cur = stack.pop();
|
|
147
|
+
let entries;
|
|
148
|
+
try {
|
|
149
|
+
entries = fs.readdirSync(cur, { withFileTypes: true });
|
|
150
|
+
} catch {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
for (const ent of entries) {
|
|
154
|
+
const full = path.join(cur, ent.name);
|
|
155
|
+
if (ent.isDirectory()) {
|
|
156
|
+
if (recursive) stack.push(full);
|
|
157
|
+
} else if (ent.isFile() && match.test(ent.name) && !isSkipped(full)) {
|
|
158
|
+
out.push(full);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Applies an array of regex patterns to a single file in place. Substitutes only when the
|
|
167
|
+
* matched version literally equals `oldVersion` — narrative references to other versions
|
|
168
|
+
* (e.g. example tags `(v3.2.9, v3.2.10, …)`) are left untouched.
|
|
169
|
+
*
|
|
170
|
+
* Returns the substitution count (0 if nothing matched).
|
|
171
|
+
*/
|
|
172
|
+
const bumpFile = (filePath, patterns, oldVersion, newVersion, { dryRun }) => {
|
|
173
|
+
if (isSkipped(filePath)) return 0;
|
|
174
|
+
if (!fs.existsSync(filePath)) return 0;
|
|
175
|
+
const original = fs.readFileSync(filePath, 'utf8');
|
|
176
|
+
const regexes = Array.isArray(patterns) ? patterns : [patterns];
|
|
177
|
+
let updated = original;
|
|
178
|
+
let count = 0;
|
|
179
|
+
for (const re of regexes) {
|
|
180
|
+
updated = updated.replace(re, (m, prefix) => {
|
|
181
|
+
const matchedVersion = m.match(/\d+\.\d+\.\d+/)?.[0];
|
|
182
|
+
if (matchedVersion !== oldVersion) return m;
|
|
183
|
+
count += 1;
|
|
184
|
+
return `${prefix}${newVersion}`;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (count > 0 && updated !== original && !dryRun) {
|
|
188
|
+
fs.writeFileSync(filePath, updated, 'utf8');
|
|
189
|
+
}
|
|
190
|
+
return count;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Bumps every non-canonical file declared in VERSION_BUMP_TARGETS.
|
|
195
|
+
* Returns a per-file report so callers can print a summary.
|
|
196
|
+
*
|
|
197
|
+
* @param {string} oldVersion - The version currently in the files (pre-bump).
|
|
198
|
+
* @param {string} newVersion - The version to write.
|
|
199
|
+
* @param {{dryRun?: boolean}} [opts]
|
|
200
|
+
* @returns {Array<{file: string, count: number}>}
|
|
201
|
+
*/
|
|
202
|
+
const bumpAuxiliaryFiles = (oldVersion, newVersion, { dryRun = false } = {}) => {
|
|
203
|
+
const report = [];
|
|
204
|
+
if (oldVersion === newVersion) return report;
|
|
205
|
+
for (const target of buildVersionBumpTargets()) {
|
|
206
|
+
const files = target.file ? [target.file] : walkDir(target.dir, target.match, target.recursive ?? false);
|
|
207
|
+
for (const file of files) {
|
|
208
|
+
if (target.optional && !fs.existsSync(file)) continue;
|
|
209
|
+
const count = bumpFile(file, target.patterns, oldVersion, newVersion, { dryRun });
|
|
210
|
+
if (count > 0) report.push({ file, count });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return report;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Prints a per-file change summary table.
|
|
218
|
+
*/
|
|
219
|
+
const printBumpReport = (report, { dryRun }) => {
|
|
220
|
+
const header = dryRun ? 'Version bump (dry-run) — would change:' : 'Version bump — files updated:';
|
|
221
|
+
logger.info(header);
|
|
222
|
+
if (!report.length) {
|
|
223
|
+
console.log(' (no files matched)');
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const maxLen = Math.max(...report.map((r) => r.file.length));
|
|
227
|
+
for (const { file, count } of report) {
|
|
228
|
+
console.log(` ${file.padEnd(maxLen + 2)} ${count} match${count === 1 ? '' : 'es'}`);
|
|
229
|
+
}
|
|
230
|
+
console.log(` Total: ${report.length} file(s), ${report.reduce((s, r) => s + r.count, 0)} substitution(s)`);
|
|
231
|
+
};
|
|
232
|
+
|
|
21
233
|
/**
|
|
22
234
|
* Kills any Node.js dev-server or nodemon processes that may hold file locks
|
|
23
235
|
* (e.g. overwriting package.json). Skips VSCode internals and the current process.
|
|
24
236
|
*/
|
|
25
237
|
function killDevServers() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
238
|
+
for (const port of [4001, 4002, 4003, 3000]) shellExec(`node bin run kill ${port}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const TEMPLATE_PATH = '../pwa-microservices-template';
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Runs a command in an ISOLATED environment. `release build` loads the engine's
|
|
245
|
+
* `dd-cron/.env.production` (DEPLOY_ID=dd-cron, DB creds, secrets, …) into its own `process.env`,
|
|
246
|
+
* which `shellExec` children would otherwise inherit — and the template's `dotenv.config()` runs
|
|
247
|
+
* without override, so it could never reclaim those keys. `env -i` starts the child with an empty
|
|
248
|
+
* environment; only PATH/HOME-class essentials are re-added so node/npm/git still resolve. The
|
|
249
|
+
* template then reads only its own `.env`, resolving `dd-default` exactly like a fresh clone.
|
|
250
|
+
*/
|
|
251
|
+
const ISOLATED_ENV = 'env -i HOME="$HOME" PATH="$PATH" USER="$USER" LOGNAME="$LOGNAME" TERM="$TERM" LANG="$LANG"';
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Builds the pwa-microservices-template from scratch and smoke-tests its default workflow.
|
|
255
|
+
*
|
|
256
|
+
* 1. Cleans the engine, pulls latest, and rebuilds the template via `bin/build.template`.
|
|
257
|
+
* 2. Derives `.env` + `.env.example` from the template `.env.example` (DHCP host IP + file
|
|
258
|
+
* logs), both written from the same `dd-default` content so the default startup workflow
|
|
259
|
+
* bootstraps `engine-private` from scratch out of them. `.env` is rewritten because it is
|
|
260
|
+
* gitignored (git clean never removes it) and may otherwise hold a stale `dd-cron`.
|
|
261
|
+
* 3. Installs deps, then builds + runs the template `dev` server in an ISOLATED env
|
|
262
|
+
* (see `ISOLATED_ENV`) so it resolves `dd-default` like a fresh clone, and asserts the
|
|
263
|
+
* startup log is error-free.
|
|
264
|
+
*
|
|
265
|
+
* @returns {boolean} true when the template started cleanly, false otherwise.
|
|
266
|
+
*/
|
|
267
|
+
async function buildAndTestTemplate(opts = {}) {
|
|
268
|
+
killDevServers();
|
|
269
|
+
Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
|
|
270
|
+
shellExec(`node bin pull . ${process.env.GITHUB_USERNAME}/engine`);
|
|
271
|
+
fs.removeSync(TEMPLATE_PATH);
|
|
272
|
+
shellExec(`npm run build:template`);
|
|
273
|
+
shellExec(`node bin run shared-dir ${TEMPLATE_PATH}`);
|
|
274
|
+
|
|
275
|
+
const upsertEnvVar = (content, key, value) => {
|
|
276
|
+
const re = new RegExp(`^(${key}=).*`, 'm');
|
|
277
|
+
if (re.test(content)) return content.replace(re, `$1${value}`);
|
|
278
|
+
return `${content.trimEnd()}\n${key}=${value}\n`;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const dhcpHostIp = Dns.getLocalIPv4Address();
|
|
282
|
+
logger.info(`DHCP host IP for template test: ${dhcpHostIp}`);
|
|
283
|
+
let envContent = fs.readFileSync(`${TEMPLATE_PATH}/.env.example`, 'utf8');
|
|
284
|
+
if (dhcpHostIp) envContent = envContent.replace(/127\.0\.0\.1/g, dhcpHostIp);
|
|
285
|
+
envContent = upsertEnvVar(envContent, 'ENABLE_FILE_LOGS', 'true');
|
|
286
|
+
if (opts.mongoHost) envContent = upsertEnvVar(envContent, 'DB_HOST', opts.mongoHost);
|
|
287
|
+
if (opts.mongoUser) envContent = upsertEnvVar(envContent, 'DB_USER', opts.mongoUser);
|
|
288
|
+
if (opts.mongoPassword) envContent = upsertEnvVar(envContent, 'DB_PASSWORD', opts.mongoPassword);
|
|
289
|
+
if (opts.valkeyHost) envContent = upsertEnvVar(envContent, 'VALKEY_HOST', opts.valkeyHost);
|
|
290
|
+
// fs.writeFileSync(`${TEMPLATE_PATH}/.env`, envContent, 'utf8');
|
|
291
|
+
fs.writeFileSync(`${TEMPLATE_PATH}/.env.example`, envContent, 'utf8');
|
|
292
|
+
shellExec(`cd ${TEMPLATE_PATH} && npm install`);
|
|
293
|
+
shellExec(`cd ${TEMPLATE_PATH} && node bin env clean`);
|
|
294
|
+
// Build + run in an isolated env so the template resolves dd-default from its own .env and
|
|
295
|
+
// never inherits the engine's dd-cron deploy selection. See ISOLATED_ENV above.
|
|
296
|
+
//
|
|
297
|
+
// ENABLE_FILE_LOGS must be passed inline: src/server.js builds start.js's logger at import
|
|
298
|
+
// time, before Config.build() loads the template .env, so the var has to be present in the
|
|
299
|
+
// process env from the start for logs/start.js/all.log (the success probe below) to be written.
|
|
300
|
+
shellExec(`cd ${TEMPLATE_PATH} && ${ISOLATED_ENV} npm run build`);
|
|
301
|
+
shellExec(`cd ${TEMPLATE_PATH} && ${ISOLATED_ENV} ENABLE_FILE_LOGS=true timeout 5s npm run dev`, { async: true });
|
|
302
|
+
await timer(5500);
|
|
303
|
+
|
|
304
|
+
const templateLogPath = `${TEMPLATE_PATH}/logs/start.js/all.log`;
|
|
305
|
+
const runnerResult = fs.existsSync(templateLogPath) ? fs.readFileSync(templateLogPath, 'utf8') : '';
|
|
306
|
+
logger.info('Test template runner result');
|
|
307
|
+
killDevServers();
|
|
308
|
+
shellCd(`/home/dd/engine`);
|
|
309
|
+
Underpost.repo.clean({ paths: ['/home/dd/engine', '/home/dd/engine/engine-private '] });
|
|
310
|
+
if (!runnerResult || runnerResult.toLowerCase().match('error')) {
|
|
311
|
+
logger.error('Test template runner result failed');
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
return true;
|
|
33
315
|
}
|
|
34
316
|
|
|
35
317
|
/**
|
|
@@ -46,166 +328,93 @@ class UnderpostRelease {
|
|
|
46
328
|
* Builds a new version of the Underpost engine.
|
|
47
329
|
*
|
|
48
330
|
* Performs the full version build pipeline:
|
|
49
|
-
* 1. Loads production
|
|
50
|
-
* 2.
|
|
51
|
-
* 3.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
331
|
+
* 1. Loads production env and pulls latest code; kills dev servers on ports 4001-4003.
|
|
332
|
+
* 2. Builds and smoke-tests the pwa-microservices-template (aborts on error).
|
|
333
|
+
* 3. Canonical version files: delegates to `bumpp` (driven by `bump.config.js`). Bumps
|
|
334
|
+
* package.json, package-lock.json (root + packages['']), and every
|
|
335
|
+
* engine-private/conf/**\/package.json.
|
|
336
|
+
* 4. Auxiliary files: anchored-regex walker over VERSION_BUMP_TARGETS — covers
|
|
337
|
+
* src/index.js, README, cyberia-docs, nexodev docs, manifests (deployment + cronjobs),
|
|
338
|
+
* .github/workflows (image tags, type=raw, UNDERPOST_VERSION build-args), and
|
|
339
|
+
* engine-private confs (deployment.yaml + conf.instances.json). Files in
|
|
340
|
+
* VERSION_BUMP_SKIP (CHANGELOG, logs/, .env.*, node_modules/) are never touched.
|
|
341
|
+
* The walker only rewrites occurrences whose version literally equals the pre-bump
|
|
342
|
+
* version — narrative references like `(v3.2.9, v3.2.10, …)` are preserved.
|
|
343
|
+
* 5. Rebuilds CLI docs, deps, client bundle, deploy manifests, default confs.
|
|
344
|
+
* 6. Syncs cron setup-start scripts and builds the changelog.
|
|
345
|
+
*
|
|
346
|
+
* With `options.dryRun: true`, steps 3–4 print a per-file substitution report and exit
|
|
347
|
+
* without writing files or running steps 5–6.
|
|
57
348
|
*
|
|
58
349
|
* @method build
|
|
59
350
|
* @param {string} [newVersion] - The new version string to set. Defaults to current version if not provided.
|
|
60
|
-
* @param {
|
|
351
|
+
* @param {{dryRun?: boolean, mongoHost?: string, mongoUser?: string, mongoPassword?: string, valkeyHost?: string}} [options] - Commander options.
|
|
352
|
+
* `--dry-run` previews changes without writing files.
|
|
353
|
+
* `--mongo-host` overrides `DB_HOST` in the template `.env.example` smoke test.
|
|
354
|
+
* `--mongo-user` overrides `DB_USER` in the template `.env.example` smoke test.
|
|
355
|
+
* `--mongo-password` overrides `DB_PASSWORD` in the template `.env.example` smoke test.
|
|
356
|
+
* `--valkey-host` overrides `VALKEY_HOST` in the template `.env.example` smoke test.
|
|
61
357
|
* @memberof UnderpostRelease
|
|
62
358
|
*/
|
|
63
|
-
async build(newVersion, options) {
|
|
359
|
+
async build(newVersion, options = {}) {
|
|
360
|
+
const dryRun = !!options.dryRun;
|
|
64
361
|
dotenv.config({ path: `./engine-private/conf/dd-cron/.env.production`, override: true });
|
|
65
362
|
shellCd(`/home/dd/engine`);
|
|
66
|
-
|
|
67
|
-
|
|
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 '] });
|
|
363
|
+
|
|
364
|
+
// ── Resolve from/to versions up front. Used by every bump step + downstream commands. ──
|
|
86
365
|
const originPackageJson = JSON.parse(fs.readFileSync(`package.json`, 'utf8'));
|
|
87
|
-
if (!newVersion) newVersion = originPackageJson.version;
|
|
88
366
|
const { version } = originPackageJson;
|
|
89
|
-
|
|
90
|
-
|
|
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-engine:v${version}`, `underpost-engine:v${newVersion}`),
|
|
124
|
-
'utf8',
|
|
125
|
-
);
|
|
367
|
+
if (!newVersion) newVersion = version;
|
|
368
|
+
logger.info(`Release build — bumping ${version} → ${newVersion}${dryRun ? ' (dry-run)' : ''}`);
|
|
126
369
|
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
// Update underpost/* image versions in all engine-*.cd.yml workflows.
|
|
137
|
-
for (const wf of fs.readdirSync(`./.github/workflows`)) {
|
|
138
|
-
if (!wf.match(/^engine-.+\.cd\.yml$/)) continue;
|
|
139
|
-
const wfPath = `./.github/workflows/${wf}`;
|
|
140
|
-
const updated = fs
|
|
141
|
-
.readFileSync(wfPath, 'utf8')
|
|
142
|
-
.replace(/underpost\/([^:'"]+):v[0-9]+\.[0-9]+\.[0-9]+/g, `underpost/$1:v${newVersion}`);
|
|
143
|
-
fs.writeFileSync(wfPath, updated, 'utf8');
|
|
370
|
+
if (!dryRun) {
|
|
371
|
+
const templateOk = await buildAndTestTemplate(options);
|
|
372
|
+
if (!templateOk) return;
|
|
144
373
|
}
|
|
145
374
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
'
|
|
154
|
-
|
|
155
|
-
|
|
375
|
+
// ── Canonical version files: delegate to bumpp (package.json, package-lock.json,
|
|
376
|
+
// engine-private/conf/**/package.json). bumpp owns lockfile semantics (root version
|
|
377
|
+
// + packages[''].version) so we don't reimplement them. ──
|
|
378
|
+
const { versionBump } = await import('bumpp');
|
|
379
|
+
const bumppResult = await versionBump({
|
|
380
|
+
release: newVersion,
|
|
381
|
+
files: [
|
|
382
|
+
'package.json',
|
|
383
|
+
'package-lock.json',
|
|
384
|
+
...(fs.existsSync('./engine-private/conf') ? ['engine-private/conf/**/package.json'] : []),
|
|
385
|
+
],
|
|
386
|
+
commit: false,
|
|
387
|
+
tag: false,
|
|
388
|
+
push: false,
|
|
389
|
+
confirm: false,
|
|
390
|
+
recursive: false,
|
|
391
|
+
ignoreScripts: true,
|
|
392
|
+
dry: dryRun,
|
|
393
|
+
});
|
|
394
|
+
logger.info(`bumpp updated ${bumppResult?.files?.length ?? 0} canonical file(s).`);
|
|
395
|
+
|
|
396
|
+
// ── Auxiliary files: anchored-regex walker over VERSION_BUMP_TARGETS. ──
|
|
397
|
+
const report = bumpAuxiliaryFiles(version, newVersion, { dryRun });
|
|
398
|
+
printBumpReport(report, { dryRun });
|
|
156
399
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
for (const relativePath of confFiles) {
|
|
161
|
-
const filePath = `./engine-private/conf/${relativePath.replaceAll('\\', '/')}`;
|
|
162
|
-
if (filePath.split('/').pop() !== 'conf.instances.json' || !fs.existsSync(filePath)) continue;
|
|
163
|
-
|
|
164
|
-
let instances;
|
|
165
|
-
try {
|
|
166
|
-
instances = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
167
|
-
} catch {
|
|
168
|
-
logger.warn(`Skipping invalid JSON file: ${filePath}`);
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (!Array.isArray(instances)) continue;
|
|
173
|
-
|
|
174
|
-
let updated = false;
|
|
175
|
-
for (const instance of instances) {
|
|
176
|
-
if (!instance || typeof instance !== 'object') continue;
|
|
177
|
-
if (!instance.image || typeof instance.image !== 'string') continue;
|
|
178
|
-
if (!instance.image.startsWith('underpost/')) continue;
|
|
179
|
-
|
|
180
|
-
const baseImage = instance.image.split('@')[0].split(':')[0];
|
|
181
|
-
const nextImage = `${baseImage}:v${newVersion}`;
|
|
182
|
-
if (instance.image !== nextImage) {
|
|
183
|
-
instance.image = nextImage;
|
|
184
|
-
updated = true;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (updated) fs.writeFileSync(filePath, JSON.stringify(instances, null, 2), 'utf8');
|
|
189
|
-
}
|
|
400
|
+
if (dryRun) {
|
|
401
|
+
logger.info('Dry-run complete. No files modified. Re-run without --dry-run to apply.');
|
|
402
|
+
return { from: version, to: newVersion, files: report.map((r) => r.file), dryRun: true };
|
|
190
403
|
}
|
|
191
404
|
|
|
192
|
-
|
|
193
|
-
`./src/index.js`,
|
|
194
|
-
fs.readFileSync(`./src/index.js`, 'utf8').replaceAll(`${version}`, `${newVersion}`),
|
|
195
|
-
'utf8',
|
|
196
|
-
);
|
|
405
|
+
// ── Downstream regenerations and manifest sync (unchanged from previous flow). ──
|
|
197
406
|
shellExec(`node bin/deploy cli-docs ${version} ${newVersion}`);
|
|
198
407
|
shellExec(`node bin/deploy update-dependencies`);
|
|
199
408
|
shellExec(`node bin/build dd`);
|
|
200
|
-
shellExec(`node bin
|
|
201
|
-
shellExec(`node bin
|
|
202
|
-
shellExec(`node bin/deploy build-default-confs`);
|
|
409
|
+
shellExec(`node bin run build-cluster-deployment-manifests`);
|
|
410
|
+
shellExec(`node bin new --default-conf --conf-workflow-id template`);
|
|
203
411
|
shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
|
|
204
412
|
shellExec(`node bin new --deploy-id dd-default`);
|
|
205
413
|
console.log(fs.existsSync(`./engine-private/conf/dd-default`));
|
|
206
414
|
shellExec(`sudo rm -rf ./engine-private/conf/dd-default`);
|
|
207
415
|
shellExec(`node bin cron --kubeadm --setup-start --git`); // --apply
|
|
208
416
|
shellExec(`node bin cmt --changelog-build`);
|
|
417
|
+
return { from: version, to: newVersion, files: report.map((r) => r.file), dryRun: false };
|
|
209
418
|
},
|
|
210
419
|
|
|
211
420
|
/**
|
|
@@ -266,7 +475,7 @@ class UnderpostRelease {
|
|
|
266
475
|
* Runs the pwa-microservices-template update and push flow locally.
|
|
267
476
|
*
|
|
268
477
|
* Always removes and re-clones pwa-microservices-template, then:
|
|
269
|
-
* 1. Runs
|
|
478
|
+
* 1. Runs build:template (node bin/build.template) to sync engine sources.
|
|
270
479
|
* 2. Installs dependencies and builds the template.
|
|
271
480
|
* 3. Commits and pushes to the pwa-microservices-template remote repository.
|
|
272
481
|
*
|
|
@@ -294,7 +503,7 @@ class UnderpostRelease {
|
|
|
294
503
|
shellExec(`sudo rm -rf /home/dd/pwa-microservices-template`);
|
|
295
504
|
shellExec(`node engine/bin clone ${githubOrg}/pwa-microservices-template`);
|
|
296
505
|
shellCd('/home/dd/engine');
|
|
297
|
-
shellExec(`npm run
|
|
506
|
+
shellExec(`npm run build:template`);
|
|
298
507
|
shellExec(`cd ../pwa-microservices-template && npm install && npm run build`);
|
|
299
508
|
shellCd('/home/dd/pwa-microservices-template');
|
|
300
509
|
shellExec(`git add .`);
|
|
@@ -326,7 +535,7 @@ class UnderpostRelease {
|
|
|
326
535
|
shellExec(
|
|
327
536
|
`node bin secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
|
|
328
537
|
);
|
|
329
|
-
shellExec(`node bin/build dd conf`);
|
|
538
|
+
shellExec(`node bin/build dd --conf`);
|
|
330
539
|
shellExec(`git add . && cd ./engine-private && git add .`);
|
|
331
540
|
shellExec(`node bin cmt . ci package-pwa-microservices-template 'New release v:${version}'`);
|
|
332
541
|
shellExec(`node bin cmt ./engine-private ci package-pwa-microservices-template`);
|