cyberia 3.2.22 → 3.2.70
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 +127 -68
- package/.github/workflows/cyberia-client.cd.yml +40 -0
- package/.github/workflows/cyberia-server.cd.yml +40 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +49 -0
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +48 -0
- package/.github/workflows/docker-image.cyberia-server.ci.yml +69 -0
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +69 -0
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +52 -0
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +52 -0
- package/.github/workflows/engine-cyberia.cd.yml +33 -24
- package/.github/workflows/engine-cyberia.ci.yml +13 -3
- package/.github/workflows/ghpkg.ci.yml +88 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +10 -7
- package/.github/workflows/publish.ci.yml +2 -2
- package/.github/workflows/publish.cyberia.ci.yml +5 -16
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -8
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/CHANGELOG.md +301 -1
- package/CLI-HELP.md +71 -6
- package/Dockerfile +141 -43
- package/Dockerfile.dev +143 -0
- package/Dockerfile.test +165 -0
- package/README.md +1 -1
- package/baremetal/commission-workflows.json +1 -0
- package/bin/build.js +31 -0
- package/bin/cyberia.js +1080 -184
- package/bin/deploy.js +2 -2
- package/bin/index.js +1080 -184
- package/bump.config.js +1 -0
- package/compose.env +131 -0
- package/conf.js +18 -1
- package/deployment.yaml +2 -2
- package/docker-compose.yml +316 -0
- package/hardhat/hardhat.config.js +2 -2
- package/hardhat/package-lock.json +620 -2041
- package/hardhat/package.json +7 -5
- package/hardhat/scripts/deployObjectLayerToken.js +18 -18
- package/hardhat/test/ObjectLayerToken.js +378 -274
- package/ipfs/configure-ipfs.sh +13 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +32 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/mongodb/entrypoint.sh +76 -0
- package/nginx.conf +87 -0
- package/package.json +31 -19
- package/pv-pvc.yaml +32 -0
- package/scripts/disk-clean.sh +85 -60
- package/scripts/kubeadm-node-setup.sh +317 -0
- package/scripts/rocky-kickstart.sh +877 -185
- package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
- package/scripts/test-monitor.sh +3 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +43 -7
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +17 -25
- package/src/api/cyberia-action/cyberia-action.controller.js +19 -0
- package/src/api/cyberia-action/cyberia-action.model.js +21 -29
- package/src/api/cyberia-action/cyberia-action.router.js +42 -7
- package/src/api/cyberia-action/cyberia-action.service.js +20 -4
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +58 -57
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +37 -6
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +8 -2
- package/src/api/cyberia-entity/cyberia-entity.router.js +39 -7
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +74 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +63 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +62 -10
- package/src/api/cyberia-instance/cyberia-instance.model.js +32 -2
- package/src/api/cyberia-instance/cyberia-instance.router.js +6 -6
- package/src/api/cyberia-instance/cyberia-world-generator.js +116 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +3 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +39 -7
- package/src/api/cyberia-map/cyberia-map.router.js +21 -6
- package/src/api/cyberia-quest/cyberia-quest.controller.js +38 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +47 -7
- package/src/api/cyberia-quest/cyberia-quest.service.js +59 -4
- package/src/api/cyberia-saga/cyberia-saga.controller.js +74 -0
- package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
- package/src/api/cyberia-saga/cyberia-saga.router.js +63 -0
- package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +551 -129
- package/src/api/cyberia-skill/cyberia-skill.controller.js +74 -0
- package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
- package/src/api/cyberia-skill/cyberia-skill.router.js +63 -0
- package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
- package/src/api/ipfs/ipfs.service.js +28 -15
- package/src/api/object-layer/object-layer.router.js +25 -15
- package/src/api/object-layer/object-layer.service.js +15 -20
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +39 -7
- package/src/cli/baremetal.js +717 -16
- package/src/cli/cluster.js +80 -5
- package/src/cli/deploy.js +127 -11
- package/src/cli/docker-compose.js +648 -0
- package/src/cli/env.js +11 -2
- package/src/cli/fs.js +75 -30
- package/src/cli/image.js +129 -51
- package/src/cli/index.js +110 -6
- package/src/cli/kickstart.js +142 -20
- package/src/cli/release.js +46 -4
- package/src/cli/repository.js +238 -33
- package/src/cli/run.js +520 -114
- package/src/cli/secrets.js +82 -48
- package/src/cli/ssh.js +234 -0
- package/src/cli/static.js +2 -2
- package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
- package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
- package/src/client/components/cyberia/InstanceEngineCyberia.js +219 -13
- package/src/client/components/cyberia/MapEngineCyberia.js +154 -71
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +40 -63
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +34 -20
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +195 -4
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +66 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +8 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +45 -27
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +3 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +39 -22
- package/src/client/public/cyberia-docs/CYBERIA-LORE.md +88 -0
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +8 -1
- package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +5 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +2 -2
- package/src/client/services/cyberia-map/cyberia-map.management.js +2 -2
- package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
- package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -6
- package/src/{server → client-builder}/client-build-docs.js +15 -5
- package/src/{server → client-builder}/client-build-live.js +3 -3
- package/src/{server → client-builder}/client-build.js +25 -22
- package/src/{server → client-builder}/client-dev-server.js +3 -3
- package/src/{server → client-builder}/client-icons.js +2 -2
- package/src/{server → client-builder}/ssr.js +5 -5
- package/src/client.build.js +1 -3
- package/src/client.dev.js +1 -1
- package/src/db/mongo/MongoBootstrap.js +12 -12
- package/src/grpc/cyberia/grpc-server.js +255 -70
- package/src/index.js +12 -1
- package/src/mailer/EmailRender.js +1 -1
- package/src/{server → projects/cyberia}/atlas-sprite-sheet-generator.js +2 -2
- package/src/{server → projects/cyberia}/besu-genesis-generator.js +3 -3
- package/src/projects/cyberia/catalog-cyberia.js +81 -0
- package/src/projects/cyberia/gemini-client.js +175 -0
- package/src/projects/cyberia/generate-saga.js +2107 -0
- package/src/{server → projects/cyberia}/ipfs-client.js +2 -2
- package/src/{server → projects/cyberia}/object-layer.js +12 -108
- package/src/{server → projects/cyberia}/semantic-layer-generator-floor.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator-resource.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator-skin.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator.js +2 -2
- package/src/{server → projects/cyberia}/shape-generator.js +2 -2
- package/src/{server → projects/underpost}/catalog-underpost.js +1 -2
- package/src/runtime/cyberia-client/Dockerfile +27 -61
- package/src/runtime/cyberia-client/Dockerfile.dev +20 -12
- package/src/runtime/cyberia-server/Dockerfile +21 -20
- package/src/runtime/cyberia-server/Dockerfile.dev +17 -8
- package/src/runtime/engine-cyberia/Dockerfile +143 -0
- package/src/runtime/engine-cyberia/Dockerfile.dev +143 -0
- package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
- package/src/runtime/engine-cyberia/compose.env +131 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +316 -0
- package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
- package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
- package/src/runtime/engine-cyberia/nginx.conf +87 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/nginx/Nginx.js +250 -0
- package/src/server/catalog.js +9 -14
- package/src/server/conf.js +3 -6
- package/src/server/runtime-status.js +18 -1
- package/src/server/start.js +12 -2
- package/src/server.js +6 -2
- package/test/cyberia-instance-conf-defaults.test.js +140 -0
- package/test/deploy-monitor.test.js +26 -10
- package/test/shape-generator.test.js +7 -1
- package/typedoc.dd-cyberia.json +3 -1
- package/typedoc.json +3 -1
- /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
- /package/src/{server → client-builder}/client-formatted.js +0 -0
package/src/cli/repository.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
buildReplicaId,
|
|
23
23
|
writeEnv,
|
|
24
24
|
} from '../server/conf.js';
|
|
25
|
-
import { buildClient, unzipClientBuild, mergeClientBuildZip } from '../
|
|
25
|
+
import { buildClient, unzipClientBuild, mergeClientBuildZip } from '../client-builder/client-build.js';
|
|
26
26
|
import { DefaultConf } from '../../conf.js';
|
|
27
27
|
import Underpost from '../index.js';
|
|
28
28
|
|
|
@@ -106,6 +106,9 @@ class UnderpostRepository {
|
|
|
106
106
|
* @param {boolean} [options.changelogBuild=false] - If true, scrapes all git history and builds a full CHANGELOG.md. Commits containing 'New release v:' are used as version section titles. Only commits starting with '[<tag>]' are included as entries.
|
|
107
107
|
* @param {string} [options.changelogMinVersion=''] - If set, overrides the default minimum version limit (2.85.0) for --changelog-build.
|
|
108
108
|
* @param {boolean} [options.changelogNoHash=false] - If true, omits commit hashes from the changelog entries.
|
|
109
|
+
* @param {boolean} [options.remoteUrl=false] - If true, prints the current git remote URL (origin) in plain text and returns.
|
|
110
|
+
* @param {string} [options.switchRepo=''] - If set, switches the remote `origin` to this URL and force-pulls the target branch, overwriting the current working tree.
|
|
111
|
+
* @param {string} [options.targetBranch=''] - Target branch for `switchRepo` (defaults to `master`).
|
|
109
112
|
* @memberof UnderpostRepository
|
|
110
113
|
*/
|
|
111
114
|
commit(
|
|
@@ -135,6 +138,9 @@ class UnderpostRepository {
|
|
|
135
138
|
bc: '',
|
|
136
139
|
isRemoteRepo: '',
|
|
137
140
|
hasChanges: false,
|
|
141
|
+
remoteUrl: false,
|
|
142
|
+
switchRepo: '',
|
|
143
|
+
targetBranch: '',
|
|
138
144
|
},
|
|
139
145
|
) {
|
|
140
146
|
if (!repoPath) repoPath = '.';
|
|
@@ -155,6 +161,22 @@ class UnderpostRepository {
|
|
|
155
161
|
return;
|
|
156
162
|
}
|
|
157
163
|
|
|
164
|
+
if (options.remoteUrl) {
|
|
165
|
+
const url = Underpost.repo.getRemoteUrl({ path: repoPath });
|
|
166
|
+
if (options.copy) pbcopy(url);
|
|
167
|
+
else console.log(url);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (options.switchRepo) {
|
|
172
|
+
Underpost.repo.switchRemote({
|
|
173
|
+
path: repoPath,
|
|
174
|
+
url: options.switchRepo,
|
|
175
|
+
branch: options.targetBranch || 'master',
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
158
180
|
if (options.bc) {
|
|
159
181
|
console.log(
|
|
160
182
|
shellExec(`cd ${repoPath} && git for-each-ref --contains ${options.bc} --format='%(refname:short)'`, {
|
|
@@ -196,7 +218,7 @@ class UnderpostRepository {
|
|
|
196
218
|
return;
|
|
197
219
|
}
|
|
198
220
|
|
|
199
|
-
if (options.changelog !== undefined || options.changelogBuild) {
|
|
221
|
+
if (options.changelog !== undefined || options.changelogBuild || options.changelogMsg !== undefined) {
|
|
200
222
|
const releaseMatch = 'New release v:';
|
|
201
223
|
// Helper: parse [<tag>] commits into grouped sections
|
|
202
224
|
const buildSectionChangelog = (commits) => {
|
|
@@ -233,7 +255,8 @@ class UnderpostRepository {
|
|
|
233
255
|
stdout: true,
|
|
234
256
|
silent: true,
|
|
235
257
|
disableLog: true,
|
|
236
|
-
|
|
258
|
+
silentOnError: true,
|
|
259
|
+
}).toString();
|
|
237
260
|
return rawLog
|
|
238
261
|
.split('\n')
|
|
239
262
|
.map((line) => {
|
|
@@ -324,15 +347,18 @@ class UnderpostRepository {
|
|
|
324
347
|
fs.writeFileSync(changelogPath, `# Changelog\n\n${changelog}`);
|
|
325
348
|
logger.info('CHANGELOG.md built at', changelogPath);
|
|
326
349
|
} else {
|
|
327
|
-
// --changelog
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
350
|
+
// --changelog / --changelog-msg: message from the last N commits, where N is --from-n-commit
|
|
351
|
+
// (default 1, last commit only). No auto-detection.
|
|
352
|
+
const n = parseInt(options.fromNCommit) > 0 ? parseInt(options.fromNCommit) : 1;
|
|
353
|
+
const sections = buildVersionSections(fetchHistory(n));
|
|
354
|
+
const changelog = renderSections(sections);
|
|
355
|
+
if (options.changelogMsg !== undefined) {
|
|
356
|
+
// Sanitized, commit-ready message; empty string when there are no tagged entries so
|
|
357
|
+
// callers fall back to their own generic default instead of a placeholder.
|
|
358
|
+
console.log(Underpost.repo.sanitizeChangelogMessage(changelog));
|
|
359
|
+
} else {
|
|
360
|
+
console.log(changelog || `No changelog entries found.\n`);
|
|
361
|
+
}
|
|
336
362
|
}
|
|
337
363
|
|
|
338
364
|
return;
|
|
@@ -1235,17 +1261,40 @@ Prevent build private config repo.`,
|
|
|
1235
1261
|
return copiedFiles;
|
|
1236
1262
|
},
|
|
1237
1263
|
|
|
1264
|
+
/**
|
|
1265
|
+
* Resolves the default branch for a remote GitHub repository by querying
|
|
1266
|
+
* `git ls-remote --symref` and extracting the HEAD ref target.
|
|
1267
|
+
* Falls back to `main` when detection fails.
|
|
1268
|
+
* @param {string} repo - The GitHub repository (e.g., "owner/repo").
|
|
1269
|
+
* @returns {string} The default branch name (e.g. "main" or "master").
|
|
1270
|
+
* @memberof UnderpostRepository
|
|
1271
|
+
*/
|
|
1272
|
+
getDefaultBranch(repo) {
|
|
1273
|
+
if (!repo) return 'main';
|
|
1274
|
+
const authUrl = Underpost.repo.resolveAuthUrl(repo);
|
|
1275
|
+
const raw = shellExec(
|
|
1276
|
+
`GIT_TERMINAL_PROMPT=0 git -c credential.helper= ls-remote --symref "${authUrl}" HEAD 2>&1`,
|
|
1277
|
+
{ stdout: true, silent: true, disableLog: true, silentOnError: true },
|
|
1278
|
+
);
|
|
1279
|
+
// --symref emits a line like: ref: refs/heads/main HEAD
|
|
1280
|
+
const match = typeof raw === 'string' ? raw.match(/^ref:\s*refs\/heads\/(\S+)\tHEAD$/m) : null;
|
|
1281
|
+
const branch = match ? match[1] : 'main';
|
|
1282
|
+
logger.info('getDefaultBranch', { repo, branch });
|
|
1283
|
+
return branch;
|
|
1284
|
+
},
|
|
1285
|
+
|
|
1238
1286
|
/**
|
|
1239
1287
|
* Dispatches a GitHub Actions workflow using gh CLI or curl fallback.
|
|
1240
1288
|
* @param {object} options - Dispatch options.
|
|
1241
1289
|
* @param {string} options.repo - The GitHub repository (e.g., "owner/repo").
|
|
1242
1290
|
* @param {string} options.workflowFile - The workflow file name (e.g., "engine-core.cd.yml").
|
|
1243
|
-
* @param {string} [options.ref
|
|
1291
|
+
* @param {string} [options.ref] - The git ref to dispatch against. Auto-detects the remote's default branch when omitted.
|
|
1244
1292
|
* @param {object} [options.inputs={}] - Key-value inputs for the workflow_dispatch event.
|
|
1245
1293
|
* @memberof UnderpostRepository
|
|
1246
1294
|
*/
|
|
1247
|
-
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: '
|
|
1248
|
-
const { repo, workflowFile,
|
|
1295
|
+
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: '', inputs: {} }) {
|
|
1296
|
+
const { repo, workflowFile, inputs } = options;
|
|
1297
|
+
const ref = options.ref || Underpost.repo.getDefaultBranch(repo);
|
|
1249
1298
|
const ghAvailable = shellExec('command -v gh 2>/dev/null', {
|
|
1250
1299
|
stdout: true,
|
|
1251
1300
|
silent: true,
|
|
@@ -1322,14 +1371,77 @@ Prevent build private config repo.`,
|
|
|
1322
1371
|
if (!url) return false;
|
|
1323
1372
|
const authUrl = Underpost.repo.resolveAuthUrl(url);
|
|
1324
1373
|
// GIT_TERMINAL_PROMPT=0 prevents git from hanging on credential prompts inside containers.
|
|
1325
|
-
|
|
1374
|
+
// `-c credential.helper=` disables any host-configured credential helper so its stderr
|
|
1375
|
+
// warnings don't pollute the ls-remote output; the token is already embedded in authUrl.
|
|
1376
|
+
const raw = shellExec(`GIT_TERMINAL_PROMPT=0 git -c credential.helper= ls-remote "${authUrl}" HEAD 2>&1`, {
|
|
1326
1377
|
stdout: true,
|
|
1327
1378
|
silent: true,
|
|
1328
1379
|
disableLog: true,
|
|
1329
1380
|
silentOnError: true,
|
|
1330
1381
|
});
|
|
1331
|
-
|
|
1332
|
-
|
|
1382
|
+
const refLine = typeof raw === 'string' ? (raw.match(/^[0-9a-f]{40}\t.*$/m) || [])[0] : undefined;
|
|
1383
|
+
const accessible = !!refLine;
|
|
1384
|
+
logger.info('isRemoteRepo', { url, accessible, ref: refLine || (raw || '').trim().split('\n').pop() });
|
|
1385
|
+
return accessible;
|
|
1386
|
+
},
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* Returns the current URL of a git remote in plain text.
|
|
1390
|
+
* @param {object} [opts]
|
|
1391
|
+
* @param {string} [opts.path='.'] - Path to the git repository.
|
|
1392
|
+
* @param {string} [opts.remote='origin'] - Remote name to query.
|
|
1393
|
+
* @returns {string} The remote URL, or '' when the remote is not configured.
|
|
1394
|
+
* @memberof UnderpostRepository
|
|
1395
|
+
*/
|
|
1396
|
+
getRemoteUrl({ path: repoPath = '.', remote = 'origin' } = {}) {
|
|
1397
|
+
return shellExec(`cd "${repoPath}" && git remote get-url ${remote}`, {
|
|
1398
|
+
stdout: true,
|
|
1399
|
+
silent: true,
|
|
1400
|
+
disableLog: true,
|
|
1401
|
+
silentOnError: true,
|
|
1402
|
+
}).trim();
|
|
1403
|
+
},
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* Switches a local repository onto a different remote and force-syncs its
|
|
1407
|
+
* working tree to a target branch, discarding local commits and tracked
|
|
1408
|
+
* changes — effectively "switch repo to <url>#<branch>".
|
|
1409
|
+
*
|
|
1410
|
+
* Sequence (idempotent, re-runnable):
|
|
1411
|
+
* 1. Normalize the URL (`owner/repo` → full GitHub HTTPS) and set/add the
|
|
1412
|
+
* remote, storing the token-free URL so no secret leaks into `.git/config`.
|
|
1413
|
+
* 2. Force-fetch the target branch (auth injected inline for private repos).
|
|
1414
|
+
* 3. Reset the working tree to the fetched tip and check out the target
|
|
1415
|
+
* branch, overwriting any current tracked content.
|
|
1416
|
+
*
|
|
1417
|
+
* Untracked files are intentionally left in place (no `git clean`).
|
|
1418
|
+
*
|
|
1419
|
+
* @param {object} opts
|
|
1420
|
+
* @param {string} opts.url - New remote URL (full URL or "owner/repo" short form).
|
|
1421
|
+
* @param {string} [opts.path='.'] - Path to the git repository.
|
|
1422
|
+
* @param {string} [opts.branch='master'] - Target branch to overwrite the current tree with.
|
|
1423
|
+
* @param {string} [opts.remote='origin'] - Remote name to set and fetch from.
|
|
1424
|
+
* @returns {void}
|
|
1425
|
+
* @memberof UnderpostRepository
|
|
1426
|
+
*/
|
|
1427
|
+
switchRemote({ url, path: repoPath = '.', branch = 'master', remote = 'origin' }) {
|
|
1428
|
+
if (!url) throw new Error('switchRemote requires a target remote url');
|
|
1429
|
+
if (!fs.existsSync(`${repoPath}/.git`)) throw new Error(`switchRemote: not a git repository: ${repoPath}`);
|
|
1430
|
+
// Token-free URL for the stored remote; auth-injected URL only for the fetch.
|
|
1431
|
+
let normalized = url;
|
|
1432
|
+
if (!url.startsWith('http://') && !url.startsWith('https://') && !url.startsWith('git@')) {
|
|
1433
|
+
normalized = `https://github.com/${url}`;
|
|
1434
|
+
}
|
|
1435
|
+
const authUrl = Underpost.repo.resolveAuthUrl(url);
|
|
1436
|
+
const current = Underpost.repo.getRemoteUrl({ path: repoPath, remote });
|
|
1437
|
+
if (!current) shellExec(`cd "${repoPath}" && git remote add ${remote} "${normalized}"`);
|
|
1438
|
+
else shellExec(`cd "${repoPath}" && git remote set-url ${remote} "${normalized}"`);
|
|
1439
|
+
logger.info('switchRemote', { path: repoPath, remote, branch, url: normalized });
|
|
1440
|
+
shellExec(`cd "${repoPath}" && GIT_TERMINAL_PROMPT=0 git fetch --force "${authUrl}" ${branch}`);
|
|
1441
|
+
// reset --hard first clears the worktree so the checkout cannot be blocked
|
|
1442
|
+
// by conflicting local changes; -B points the target branch at the fetched tip.
|
|
1443
|
+
shellExec(`cd "${repoPath}" && git reset --hard FETCH_HEAD`);
|
|
1444
|
+
shellExec(`cd "${repoPath}" && git checkout -B ${branch} FETCH_HEAD`);
|
|
1333
1445
|
},
|
|
1334
1446
|
|
|
1335
1447
|
/**
|
|
@@ -1341,17 +1453,31 @@ Prevent build private config repo.`,
|
|
|
1341
1453
|
* @memberof UnderpostRepository
|
|
1342
1454
|
*/
|
|
1343
1455
|
getUnpushedCount(repoPath = '.', fallback = 1) {
|
|
1456
|
+
// Every git call is silentOnError: a detached HEAD (CI checkout) or a missing upstream must
|
|
1457
|
+
// degrade to the fallback, never throw — otherwise the thrown error is logged to stdout and
|
|
1458
|
+
// can be captured as a commit message by callers that read this command's output.
|
|
1344
1459
|
const branch = shellExec(`cd ${repoPath} && git branch --show-current`, {
|
|
1345
1460
|
stdout: true,
|
|
1346
1461
|
silent: true,
|
|
1347
1462
|
disableLog: true,
|
|
1348
|
-
|
|
1349
|
-
|
|
1463
|
+
silentOnError: true,
|
|
1464
|
+
})
|
|
1465
|
+
.toString()
|
|
1466
|
+
.trim();
|
|
1467
|
+
if (!branch) return { count: fallback, branch: '', hasUnpushed: false };
|
|
1468
|
+
shellExec(`cd ${repoPath} && git fetch origin 2>/dev/null`, {
|
|
1469
|
+
silent: true,
|
|
1470
|
+
disableLog: true,
|
|
1471
|
+
silentOnError: true,
|
|
1472
|
+
});
|
|
1350
1473
|
const raw = shellExec(`cd ${repoPath} && git rev-list --count origin/${branch}..HEAD 2>/dev/null`, {
|
|
1351
1474
|
stdout: true,
|
|
1352
1475
|
silent: true,
|
|
1353
1476
|
disableLog: true,
|
|
1354
|
-
|
|
1477
|
+
silentOnError: true,
|
|
1478
|
+
})
|
|
1479
|
+
.toString()
|
|
1480
|
+
.trim();
|
|
1355
1481
|
const count = parseInt(raw);
|
|
1356
1482
|
const hasUnpushed = !isNaN(count) && count > 0;
|
|
1357
1483
|
return { count: hasUnpushed ? count : fallback, branch, hasUnpushed };
|
|
@@ -1366,7 +1492,7 @@ Prevent build private config repo.`,
|
|
|
1366
1492
|
*/
|
|
1367
1493
|
sanitizeChangelogMessage(message) {
|
|
1368
1494
|
if (!message) return '';
|
|
1369
|
-
|
|
1495
|
+
const sanitized = message
|
|
1370
1496
|
.replace(/^##\s+\d{4}-\d{2}-\d{2}\s*/gm, '')
|
|
1371
1497
|
.replace(/^###\s+(\S+)\s*/gm, '[$1] ')
|
|
1372
1498
|
.replace(/^- /gm, '')
|
|
@@ -1378,6 +1504,9 @@ Prevent build private config repo.`,
|
|
|
1378
1504
|
.join('\n')
|
|
1379
1505
|
.trim()
|
|
1380
1506
|
.replaceAll('] - ', '] ');
|
|
1507
|
+
// The empty-changelog placeholder must never become a commit message; return empty so
|
|
1508
|
+
// callers fall back to their own generic default.
|
|
1509
|
+
return sanitized === 'No changelog entries found.' ? '' : sanitized;
|
|
1381
1510
|
},
|
|
1382
1511
|
/**
|
|
1383
1512
|
* Initializes a git repository at the given path and configures user identity
|
|
@@ -1483,18 +1612,63 @@ Prevent build private config repo.`,
|
|
|
1483
1612
|
},
|
|
1484
1613
|
|
|
1485
1614
|
/**
|
|
1486
|
-
*
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
-
*
|
|
1615
|
+
* Resolves the in-pod site-root directory where a conf route's repository lives.
|
|
1616
|
+
*
|
|
1617
|
+
* General-purpose resolution, independent of any single runtime:
|
|
1618
|
+
* 1. An explicit `directory` (the conf-declared document root) always wins.
|
|
1619
|
+
* 2. Otherwise the runtime's base directory is used (e.g. `wp` → `/opt/lampp/htdocs/wp/<host>`).
|
|
1620
|
+
* 3. A subdirectory route (e.g. `/wp`) appends `<subDir>` to the resolved root.
|
|
1621
|
+
*
|
|
1622
|
+
* This mirrors {@link WpService.createApp}'s `vhostDir`/`wpDir` layout so backups target the
|
|
1623
|
+
* exact directory provisioning created, including subdirectory installs and custom directories.
|
|
1624
|
+
*
|
|
1625
|
+
* @param {object} opts
|
|
1626
|
+
* @param {string} opts.runtime - The runtime identifier (e.g. 'wp').
|
|
1627
|
+
* @param {string} opts.host - The virtual-host name.
|
|
1628
|
+
* @param {string} [opts.routePath='/'] - The conf route path the repository is mounted under.
|
|
1629
|
+
* @param {string} [opts.directory] - Explicit document root from conf; overrides the runtime base.
|
|
1630
|
+
* @returns {string|null} Absolute path inside the pod, or null when neither a directory nor a
|
|
1631
|
+
* known runtime base resolves.
|
|
1491
1632
|
* @memberof UnderpostRepository
|
|
1492
1633
|
*/
|
|
1493
|
-
runtimeSiteRoot(runtime, host) {
|
|
1494
|
-
const
|
|
1634
|
+
runtimeSiteRoot({ runtime, host, routePath = '/', directory } = {}) {
|
|
1635
|
+
const runtimeBase = {
|
|
1495
1636
|
wp: `/opt/lampp/htdocs/wp/${host}`,
|
|
1496
1637
|
};
|
|
1497
|
-
|
|
1638
|
+
const vhostDir = directory || runtimeBase[runtime];
|
|
1639
|
+
if (!vhostDir) return null;
|
|
1640
|
+
const subDir = routePath && routePath !== '/' ? routePath.replace(/^\/+/, '').replace(/\/+$/, '') : '';
|
|
1641
|
+
return subDir ? `${vhostDir}/${subDir}` : vhostDir;
|
|
1642
|
+
},
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Probes a running pod for the first candidate directory that is a git repository
|
|
1646
|
+
* (i.e. contains a `.git` entry). Used to locate a site root before backing it up so a
|
|
1647
|
+
* missing/unprovisioned directory is detected up-front instead of producing an opaque
|
|
1648
|
+
* shell `exit 1` from a failed `cd`.
|
|
1649
|
+
*
|
|
1650
|
+
* @param {object} opts
|
|
1651
|
+
* @param {string} opts.podName - Target pod name.
|
|
1652
|
+
* @param {string} opts.namespace - Kubernetes namespace.
|
|
1653
|
+
* @param {string[]} opts.candidates - Absolute paths to probe, most-specific first.
|
|
1654
|
+
* @returns {string|null} The first candidate that is a git repo, or null if none match.
|
|
1655
|
+
* @memberof UnderpostRepository
|
|
1656
|
+
*/
|
|
1657
|
+
podRepoDir({ podName, namespace, candidates }) {
|
|
1658
|
+
const probe = candidates.map((dir) => `if [ -d '${dir}/.git' ]; then echo '${dir}'; exit 0; fi`).join('; ');
|
|
1659
|
+
let out = '';
|
|
1660
|
+
try {
|
|
1661
|
+
out = Underpost.kubectl.exec({ podName, namespace, command: `${probe}; echo ''` }) || '';
|
|
1662
|
+
} catch (err) {
|
|
1663
|
+
logger.warn(`podRepoDir: probe failed in pod ${podName}`, err.message);
|
|
1664
|
+
return null;
|
|
1665
|
+
}
|
|
1666
|
+
return (
|
|
1667
|
+
out
|
|
1668
|
+
.split('\n')
|
|
1669
|
+
.map((line) => line.trim())
|
|
1670
|
+
.find(Boolean) || null
|
|
1671
|
+
);
|
|
1498
1672
|
},
|
|
1499
1673
|
|
|
1500
1674
|
/**
|
|
@@ -1543,12 +1717,28 @@ Prevent build private config repo.`,
|
|
|
1543
1717
|
const entry = confServer[host][routePath];
|
|
1544
1718
|
if (!entry.repository) continue;
|
|
1545
1719
|
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1720
|
+
const siteRootArgs = { runtime: entry.runtime, host, directory: entry.directory };
|
|
1721
|
+
const repoRoot = Underpost.repo.runtimeSiteRoot({ ...siteRootArgs, routePath });
|
|
1722
|
+
if (!repoRoot) {
|
|
1548
1723
|
logger.warn(`backupPodRepositories: no site-root mapping for runtime '${entry.runtime}' (${host})`);
|
|
1549
1724
|
continue;
|
|
1550
1725
|
}
|
|
1551
1726
|
|
|
1727
|
+
// Probe the pod for the actual git repo so an unprovisioned/missing site root is
|
|
1728
|
+
// detected and skipped cleanly instead of failing the in-pod `cd` with exit 1.
|
|
1729
|
+
// Fall back to the vhost dir (root route) to cover conf/path drift.
|
|
1730
|
+
const vhostRoot = Underpost.repo.runtimeSiteRoot({ ...siteRootArgs, routePath: '/' });
|
|
1731
|
+
const candidates = [...new Set([repoRoot, vhostRoot].filter(Boolean))];
|
|
1732
|
+
const siteRoot = Underpost.repo.podRepoDir({ podName, namespace, candidates });
|
|
1733
|
+
if (!siteRoot) {
|
|
1734
|
+
logger.warn(
|
|
1735
|
+
`backupPodRepositories: no git repository found in pod ${podName} for ${host} (checked ${candidates.join(
|
|
1736
|
+
', ',
|
|
1737
|
+
)}) — site may not be provisioned yet; skipping`,
|
|
1738
|
+
);
|
|
1739
|
+
continue;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1552
1742
|
const repoName = entry.repository.split('/').pop().split('.')[0];
|
|
1553
1743
|
|
|
1554
1744
|
// Build the backup script — secrets are injected as env vars in the exec,
|
|
@@ -1641,12 +1831,17 @@ Prevent build private config repo.`,
|
|
|
1641
1831
|
* 4. Falls back to `${GITHUB_USERNAME}/engine` when no match is found.
|
|
1642
1832
|
*
|
|
1643
1833
|
* @param {string} [runtime=''] - The runtime identifier to look up (e.g. `'cyberia-server'`, `'cyberia-client'`).
|
|
1834
|
+
* @param {boolean} [ownRuntimeRepo=false] - Whether to check for the runtime's own repository.
|
|
1644
1835
|
* @returns {string} The resolved `owner/repo` string.
|
|
1645
1836
|
* @memberof UnderpostRepository
|
|
1646
1837
|
*/
|
|
1647
|
-
resolveInstanceRepo(runtime = '') {
|
|
1838
|
+
resolveInstanceRepo(runtime = '', ownRuntimeRepo = false) {
|
|
1648
1839
|
const fallback = `${process.env.GITHUB_USERNAME}/engine`;
|
|
1649
1840
|
if (!runtime) return fallback;
|
|
1841
|
+
// A `.dev` suffix selects the development image workflow
|
|
1842
|
+
// (docker-image.<runtime>.dev.ci.yml) but resolves to the same instance
|
|
1843
|
+
// repo as its production counterpart, so strip it before matching.
|
|
1844
|
+
runtime = runtime.replace(/\.dev$/, '');
|
|
1650
1845
|
const ddRouter = './engine-private/deploy/dd.router';
|
|
1651
1846
|
const deployIds = fs.existsSync(ddRouter)
|
|
1652
1847
|
? fs
|
|
@@ -1672,6 +1867,16 @@ Prevent build private config repo.`,
|
|
|
1672
1867
|
logger.warn(`[resolveInstanceRepo] failed to parse ${confPath}: ${err.message}`);
|
|
1673
1868
|
}
|
|
1674
1869
|
}
|
|
1870
|
+
if (ownRuntimeRepo) {
|
|
1871
|
+
const runtimeRepo = Underpost.repo.isRemoteRepo(`${process.env.GITHUB_USERNAME}/${runtime}`);
|
|
1872
|
+
if (runtimeRepo) {
|
|
1873
|
+
logger.info(`[resolveInstanceRepo] resolved from ${process.env.GITHUB_USERNAME}/${runtime}`, {
|
|
1874
|
+
runtime,
|
|
1875
|
+
repo: `${process.env.GITHUB_USERNAME}/${runtime}`,
|
|
1876
|
+
});
|
|
1877
|
+
return `${process.env.GITHUB_USERNAME}/${runtime}`;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1675
1880
|
return fallback;
|
|
1676
1881
|
},
|
|
1677
1882
|
|