cyberia 3.2.12 → 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 +34 -24
- package/.github/workflows/engine-cyberia.ci.yml +27 -5
- package/.github/workflows/ghpkg.ci.yml +89 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +19 -12
- 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 +451 -1
- package/CLI-HELP.md +1040 -1130
- 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 +128 -136
- package/bin/build.template.js +25 -179
- package/bin/cyberia.js +1089 -188
- package/bin/deploy.js +6 -3
- package/bin/index.js +1089 -188
- package/bump.config.js +1 -0
- package/compose.env +131 -0
- package/conf.js +19 -1
- package/deployment.yaml +74 -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 +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +74 -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 +34 -22
- package/pv-pvc.yaml +32 -0
- package/scripts/disk-clean.sh +85 -60
- package/scripts/kubeadm-node-setup.sh +317 -0
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/rocky-kickstart.sh +877 -185
- package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
- package/scripts/test-monitor.sh +248 -0
- 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 -122
- 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 +326 -292
- package/src/cli/docker-compose.js +648 -0
- package/src/cli/env.js +12 -6
- package/src/cli/fs.js +75 -30
- package/src/cli/image.js +187 -55
- package/src/cli/index.js +157 -6
- package/src/cli/kickstart.js +142 -20
- package/src/cli/monitor.js +387 -6
- package/src/cli/release.js +72 -15
- package/src/cli/repository.js +339 -40
- package/src/cli/run.js +678 -186
- 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/core/PanelForm.js +44 -44
- 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 +92 -20
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +272 -50
- 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 +28 -12
- package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +27 -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/db/mongo/MongooseDB.js +2 -1
- 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 +6 -4
- 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/projects/underpost/catalog-underpost.js +60 -0
- package/src/runtime/cyberia-client/Dockerfile +31 -83
- package/src/runtime/cyberia-client/Dockerfile.dev +23 -30
- package/src/runtime/cyberia-server/Dockerfile +23 -42
- package/src/runtime/cyberia-server/Dockerfile.dev +20 -35
- 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/runtime/wp/Dockerfile +3 -3
- package/src/server/catalog.js +72 -0
- package/src/server/conf.js +415 -60
- package/src/server/runtime-status.js +252 -0
- package/src/server/start.js +42 -11
- package/src/server.js +6 -2
- package/test/cyberia-instance-conf-defaults.test.js +140 -0
- package/test/deploy-monitor.test.js +267 -0
- package/test/shape-generator.test.js +7 -1
- package/typedoc.dd-cyberia.json +3 -1
- package/typedoc.json +3 -1
- package/manifests/deployment/dd-test-development/deployment.yaml +0 -256
- package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
- /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
|
@@ -8,6 +8,7 @@ import dotenv from 'dotenv';
|
|
|
8
8
|
import { commitData } from '../client/components/core/CommonJs.js';
|
|
9
9
|
import { pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
10
10
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
11
|
+
import path from 'path';
|
|
11
12
|
import fs from 'fs-extra';
|
|
12
13
|
import {
|
|
13
14
|
getNpmRootPath,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
buildReplicaId,
|
|
22
23
|
writeEnv,
|
|
23
24
|
} from '../server/conf.js';
|
|
24
|
-
import { buildClient, unzipClientBuild, mergeClientBuildZip } from '../
|
|
25
|
+
import { buildClient, unzipClientBuild, mergeClientBuildZip } from '../client-builder/client-build.js';
|
|
25
26
|
import { DefaultConf } from '../../conf.js';
|
|
26
27
|
import Underpost from '../index.js';
|
|
27
28
|
|
|
@@ -105,6 +106,9 @@ class UnderpostRepository {
|
|
|
105
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.
|
|
106
107
|
* @param {string} [options.changelogMinVersion=''] - If set, overrides the default minimum version limit (2.85.0) for --changelog-build.
|
|
107
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`).
|
|
108
112
|
* @memberof UnderpostRepository
|
|
109
113
|
*/
|
|
110
114
|
commit(
|
|
@@ -133,16 +137,46 @@ class UnderpostRepository {
|
|
|
133
137
|
p: undefined,
|
|
134
138
|
bc: '',
|
|
135
139
|
isRemoteRepo: '',
|
|
140
|
+
hasChanges: false,
|
|
141
|
+
remoteUrl: false,
|
|
142
|
+
switchRepo: '',
|
|
143
|
+
targetBranch: '',
|
|
136
144
|
},
|
|
137
145
|
) {
|
|
138
146
|
if (!repoPath) repoPath = '.';
|
|
139
147
|
|
|
148
|
+
if (options.hasChanges) {
|
|
149
|
+
const status = shellExec(`cd ${repoPath} && git status --porcelain`, {
|
|
150
|
+
stdout: true,
|
|
151
|
+
silent: true,
|
|
152
|
+
disableLog: true,
|
|
153
|
+
}).trim();
|
|
154
|
+
process.stdout.write(status ? '1' : '');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
140
158
|
if (options.isRemoteRepo) {
|
|
141
159
|
const accessible = Underpost.repo.isRemoteRepo(options.isRemoteRepo);
|
|
142
160
|
console.log(accessible);
|
|
143
161
|
return;
|
|
144
162
|
}
|
|
145
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
|
+
|
|
146
180
|
if (options.bc) {
|
|
147
181
|
console.log(
|
|
148
182
|
shellExec(`cd ${repoPath} && git for-each-ref --contains ${options.bc} --format='%(refname:short)'`, {
|
|
@@ -184,7 +218,7 @@ class UnderpostRepository {
|
|
|
184
218
|
return;
|
|
185
219
|
}
|
|
186
220
|
|
|
187
|
-
if (options.changelog !== undefined || options.changelogBuild) {
|
|
221
|
+
if (options.changelog !== undefined || options.changelogBuild || options.changelogMsg !== undefined) {
|
|
188
222
|
const releaseMatch = 'New release v:';
|
|
189
223
|
// Helper: parse [<tag>] commits into grouped sections
|
|
190
224
|
const buildSectionChangelog = (commits) => {
|
|
@@ -221,7 +255,8 @@ class UnderpostRepository {
|
|
|
221
255
|
stdout: true,
|
|
222
256
|
silent: true,
|
|
223
257
|
disableLog: true,
|
|
224
|
-
|
|
258
|
+
silentOnError: true,
|
|
259
|
+
}).toString();
|
|
225
260
|
return rawLog
|
|
226
261
|
.split('\n')
|
|
227
262
|
.map((line) => {
|
|
@@ -312,15 +347,18 @@ class UnderpostRepository {
|
|
|
312
347
|
fs.writeFileSync(changelogPath, `# Changelog\n\n${changelog}`);
|
|
313
348
|
logger.info('CHANGELOG.md built at', changelogPath);
|
|
314
349
|
} else {
|
|
315
|
-
// --changelog
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
+
}
|
|
324
362
|
}
|
|
325
363
|
|
|
326
364
|
return;
|
|
@@ -556,7 +594,7 @@ class UnderpostRepository {
|
|
|
556
594
|
// Handle sync-conf operation
|
|
557
595
|
if (options.syncConf) {
|
|
558
596
|
logger.info(`Syncing configuration for deploy ID: ${deployId}`);
|
|
559
|
-
shellExec(`node bin/build ${deployId} conf`);
|
|
597
|
+
shellExec(`node bin/build ${deployId} --conf`);
|
|
560
598
|
logger.info('Configuration synced successfully');
|
|
561
599
|
return resolve(true);
|
|
562
600
|
}
|
|
@@ -608,7 +646,8 @@ class UnderpostRepository {
|
|
|
608
646
|
const npmRoot = getNpmRootPath();
|
|
609
647
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
610
648
|
const destFolder = `./${projectName}`;
|
|
611
|
-
|
|
649
|
+
const deployId = projectName.startsWith('dd-') ? projectName : `dd-${projectName}`;
|
|
650
|
+
logger.info('build app', { destFolder, deployId });
|
|
612
651
|
if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
|
|
613
652
|
fs.mkdirSync(destFolder, { recursive: true });
|
|
614
653
|
if (!options.dev) {
|
|
@@ -621,8 +660,9 @@ class UnderpostRepository {
|
|
|
621
660
|
UnderpostRepository.API.initLocalRepo({ path: destFolder });
|
|
622
661
|
shellExec(`cd ${destFolder} && git add . && git commit -m "Base template implementation"`);
|
|
623
662
|
}
|
|
624
|
-
shellExec(`cd ${destFolder} &&
|
|
625
|
-
shellExec(`cd ${destFolder} &&
|
|
663
|
+
shellExec(`cd ${destFolder} && node bin new --deploy-id ${deployId} --default-conf`);
|
|
664
|
+
shellExec(`cd ${destFolder} && node bin client ${deployId}`);
|
|
665
|
+
shellExec(`cd ${destFolder} && DEPLOY_ID=${deployId} npm run dev`);
|
|
626
666
|
}
|
|
627
667
|
return resolve(true);
|
|
628
668
|
} catch (error) {
|
|
@@ -852,6 +892,7 @@ class UnderpostRepository {
|
|
|
852
892
|
}
|
|
853
893
|
}
|
|
854
894
|
await buildClient({
|
|
895
|
+
deployId: resolvedDeployId,
|
|
855
896
|
buildZip: options.buildZip || false,
|
|
856
897
|
split: options.split || '',
|
|
857
898
|
fullBuild: options.liteBuild ? false : true,
|
|
@@ -862,7 +903,12 @@ class UnderpostRepository {
|
|
|
862
903
|
logger.warn('Skip replica client build: replica folder not found', { replicaDeployId });
|
|
863
904
|
continue;
|
|
864
905
|
}
|
|
865
|
-
await Underpost.repo.client(replicaDeployId
|
|
906
|
+
await Underpost.repo.client(replicaDeployId, '', '', '', {
|
|
907
|
+
buildZip: options.buildZip || false,
|
|
908
|
+
split: options.split || '',
|
|
909
|
+
liteBuild: options.liteBuild || false,
|
|
910
|
+
iconsBuild: options.iconsBuild || false,
|
|
911
|
+
});
|
|
866
912
|
}
|
|
867
913
|
|
|
868
914
|
return resolve(true);
|
|
@@ -937,7 +983,7 @@ Prevent build private config repo.`,
|
|
|
937
983
|
deployVersion: packageJsonDeploy.version,
|
|
938
984
|
};
|
|
939
985
|
}
|
|
940
|
-
shellExec(`node bin/build ${deployId} conf`);
|
|
986
|
+
shellExec(`node bin/build ${deployId} --conf`);
|
|
941
987
|
return {
|
|
942
988
|
validVersion: true,
|
|
943
989
|
engineVersion: packageJsonEngine.version,
|
|
@@ -1215,17 +1261,40 @@ Prevent build private config repo.`,
|
|
|
1215
1261
|
return copiedFiles;
|
|
1216
1262
|
},
|
|
1217
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
|
+
|
|
1218
1286
|
/**
|
|
1219
1287
|
* Dispatches a GitHub Actions workflow using gh CLI or curl fallback.
|
|
1220
1288
|
* @param {object} options - Dispatch options.
|
|
1221
1289
|
* @param {string} options.repo - The GitHub repository (e.g., "owner/repo").
|
|
1222
1290
|
* @param {string} options.workflowFile - The workflow file name (e.g., "engine-core.cd.yml").
|
|
1223
|
-
* @param {string} [options.ref
|
|
1291
|
+
* @param {string} [options.ref] - The git ref to dispatch against. Auto-detects the remote's default branch when omitted.
|
|
1224
1292
|
* @param {object} [options.inputs={}] - Key-value inputs for the workflow_dispatch event.
|
|
1225
1293
|
* @memberof UnderpostRepository
|
|
1226
1294
|
*/
|
|
1227
|
-
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: '
|
|
1228
|
-
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);
|
|
1229
1298
|
const ghAvailable = shellExec('command -v gh 2>/dev/null', {
|
|
1230
1299
|
stdout: true,
|
|
1231
1300
|
silent: true,
|
|
@@ -1302,14 +1371,77 @@ Prevent build private config repo.`,
|
|
|
1302
1371
|
if (!url) return false;
|
|
1303
1372
|
const authUrl = Underpost.repo.resolveAuthUrl(url);
|
|
1304
1373
|
// GIT_TERMINAL_PROMPT=0 prevents git from hanging on credential prompts inside containers.
|
|
1305
|
-
|
|
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`, {
|
|
1306
1377
|
stdout: true,
|
|
1307
1378
|
silent: true,
|
|
1308
1379
|
disableLog: true,
|
|
1309
1380
|
silentOnError: true,
|
|
1310
1381
|
});
|
|
1311
|
-
|
|
1312
|
-
|
|
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`);
|
|
1313
1445
|
},
|
|
1314
1446
|
|
|
1315
1447
|
/**
|
|
@@ -1321,17 +1453,31 @@ Prevent build private config repo.`,
|
|
|
1321
1453
|
* @memberof UnderpostRepository
|
|
1322
1454
|
*/
|
|
1323
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.
|
|
1324
1459
|
const branch = shellExec(`cd ${repoPath} && git branch --show-current`, {
|
|
1325
1460
|
stdout: true,
|
|
1326
1461
|
silent: true,
|
|
1327
1462
|
disableLog: true,
|
|
1328
|
-
|
|
1329
|
-
|
|
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
|
+
});
|
|
1330
1473
|
const raw = shellExec(`cd ${repoPath} && git rev-list --count origin/${branch}..HEAD 2>/dev/null`, {
|
|
1331
1474
|
stdout: true,
|
|
1332
1475
|
silent: true,
|
|
1333
1476
|
disableLog: true,
|
|
1334
|
-
|
|
1477
|
+
silentOnError: true,
|
|
1478
|
+
})
|
|
1479
|
+
.toString()
|
|
1480
|
+
.trim();
|
|
1335
1481
|
const count = parseInt(raw);
|
|
1336
1482
|
const hasUnpushed = !isNaN(count) && count > 0;
|
|
1337
1483
|
return { count: hasUnpushed ? count : fallback, branch, hasUnpushed };
|
|
@@ -1346,7 +1492,7 @@ Prevent build private config repo.`,
|
|
|
1346
1492
|
*/
|
|
1347
1493
|
sanitizeChangelogMessage(message) {
|
|
1348
1494
|
if (!message) return '';
|
|
1349
|
-
|
|
1495
|
+
const sanitized = message
|
|
1350
1496
|
.replace(/^##\s+\d{4}-\d{2}-\d{2}\s*/gm, '')
|
|
1351
1497
|
.replace(/^###\s+(\S+)\s*/gm, '[$1] ')
|
|
1352
1498
|
.replace(/^- /gm, '')
|
|
@@ -1358,6 +1504,9 @@ Prevent build private config repo.`,
|
|
|
1358
1504
|
.join('\n')
|
|
1359
1505
|
.trim()
|
|
1360
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;
|
|
1361
1510
|
},
|
|
1362
1511
|
/**
|
|
1363
1512
|
* Initializes a git repository at the given path and configures user identity
|
|
@@ -1374,8 +1523,9 @@ Prevent build private config repo.`,
|
|
|
1374
1523
|
const gitEmail = process.env.GITHUB_EMAIL || `development@underpost.net`;
|
|
1375
1524
|
|
|
1376
1525
|
if (!fs.existsSync(`${repoPath}/.git`)) {
|
|
1377
|
-
shellExec(`
|
|
1526
|
+
shellExec(`mkdir -p "${repoPath}" && git init "${repoPath}"`);
|
|
1378
1527
|
}
|
|
1528
|
+
|
|
1379
1529
|
shellExec(`cd "${repoPath}" && git config user.name '${gitUsername}'`);
|
|
1380
1530
|
shellExec(`cd "${repoPath}" && git config user.email '${gitEmail}'`);
|
|
1381
1531
|
shellExec(`cd "${repoPath}" && git config core.filemode false`);
|
|
@@ -1462,18 +1612,63 @@ Prevent build private config repo.`,
|
|
|
1462
1612
|
},
|
|
1463
1613
|
|
|
1464
1614
|
/**
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
*
|
|
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.
|
|
1470
1632
|
* @memberof UnderpostRepository
|
|
1471
1633
|
*/
|
|
1472
|
-
runtimeSiteRoot(runtime, host) {
|
|
1473
|
-
const
|
|
1634
|
+
runtimeSiteRoot({ runtime, host, routePath = '/', directory } = {}) {
|
|
1635
|
+
const runtimeBase = {
|
|
1474
1636
|
wp: `/opt/lampp/htdocs/wp/${host}`,
|
|
1475
1637
|
};
|
|
1476
|
-
|
|
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
|
+
);
|
|
1477
1672
|
},
|
|
1478
1673
|
|
|
1479
1674
|
/**
|
|
@@ -1522,12 +1717,28 @@ Prevent build private config repo.`,
|
|
|
1522
1717
|
const entry = confServer[host][routePath];
|
|
1523
1718
|
if (!entry.repository) continue;
|
|
1524
1719
|
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1720
|
+
const siteRootArgs = { runtime: entry.runtime, host, directory: entry.directory };
|
|
1721
|
+
const repoRoot = Underpost.repo.runtimeSiteRoot({ ...siteRootArgs, routePath });
|
|
1722
|
+
if (!repoRoot) {
|
|
1527
1723
|
logger.warn(`backupPodRepositories: no site-root mapping for runtime '${entry.runtime}' (${host})`);
|
|
1528
1724
|
continue;
|
|
1529
1725
|
}
|
|
1530
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
|
+
|
|
1531
1742
|
const repoName = entry.repository.split('/').pop().split('.')[0];
|
|
1532
1743
|
|
|
1533
1744
|
// Build the backup script — secrets are injected as env vars in the exec,
|
|
@@ -1620,12 +1831,17 @@ Prevent build private config repo.`,
|
|
|
1620
1831
|
* 4. Falls back to `${GITHUB_USERNAME}/engine` when no match is found.
|
|
1621
1832
|
*
|
|
1622
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.
|
|
1623
1835
|
* @returns {string} The resolved `owner/repo` string.
|
|
1624
1836
|
* @memberof UnderpostRepository
|
|
1625
1837
|
*/
|
|
1626
|
-
resolveInstanceRepo(runtime = '') {
|
|
1838
|
+
resolveInstanceRepo(runtime = '', ownRuntimeRepo = false) {
|
|
1627
1839
|
const fallback = `${process.env.GITHUB_USERNAME}/engine`;
|
|
1628
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$/, '');
|
|
1629
1845
|
const ddRouter = './engine-private/deploy/dd.router';
|
|
1630
1846
|
const deployIds = fs.existsSync(ddRouter)
|
|
1631
1847
|
? fs
|
|
@@ -1651,8 +1867,91 @@ Prevent build private config repo.`,
|
|
|
1651
1867
|
logger.warn(`[resolveInstanceRepo] failed to parse ${confPath}: ${err.message}`);
|
|
1652
1868
|
}
|
|
1653
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
|
+
}
|
|
1654
1880
|
return fallback;
|
|
1655
1881
|
},
|
|
1882
|
+
|
|
1883
|
+
/**
|
|
1884
|
+
* Performs a shallow sparse Git checkout of a single subdirectory from any
|
|
1885
|
+
* GitHub repository into a local target directory.
|
|
1886
|
+
*
|
|
1887
|
+
* Uses `--depth 1 --no-checkout` + `git sparse-checkout` so only the
|
|
1888
|
+
* requested path is fetched — no full clone of the remote repo.
|
|
1889
|
+
* Skips the clone entirely when `<targetDir>/<subPath>` already exists on
|
|
1890
|
+
* disk (idempotent).
|
|
1891
|
+
*
|
|
1892
|
+
* Requires `GITHUB_TOKEN` to be set in the environment for authenticated
|
|
1893
|
+
* access to private repositories.
|
|
1894
|
+
*
|
|
1895
|
+
* @param {string} subPath - The subdirectory path within the remote repo to
|
|
1896
|
+
* check out (e.g. `'conf/dd-prototype'`, `'src/api/payments'`).
|
|
1897
|
+
* @param {object} [options]
|
|
1898
|
+
* @param {string} [options.repoOwner='underpostnet'] - GitHub organisation or
|
|
1899
|
+
* user that owns the repository.
|
|
1900
|
+
* @param {string} [options.repoName='engine-private'] - Name of the
|
|
1901
|
+
* repository on GitHub.
|
|
1902
|
+
* @param {string} [options.targetDir='./engine-private'] - Local directory
|
|
1903
|
+
* where the repo will be cloned.
|
|
1904
|
+
* @returns {boolean} `true` when the checkout was performed, `false` when it
|
|
1905
|
+
* was skipped because the target path already existed.
|
|
1906
|
+
* @memberof UnderpostRepository
|
|
1907
|
+
*/
|
|
1908
|
+
sparseCheckoutDirectory(
|
|
1909
|
+
subPath,
|
|
1910
|
+
options = { repoOwner: 'underpostnet', repoName: 'engine-private', targetDir: './engine-private' },
|
|
1911
|
+
) {
|
|
1912
|
+
const { repoOwner = 'underpostnet', repoName = 'engine-private', targetDir = './engine-private' } = options;
|
|
1913
|
+
const localPath = `${targetDir}/${subPath}`;
|
|
1914
|
+
if (fs.existsSync(localPath)) {
|
|
1915
|
+
logger.info('[sparseCheckoutDirectory] path already present, skipping', localPath);
|
|
1916
|
+
return false;
|
|
1917
|
+
}
|
|
1918
|
+
const authUrl = `https://${process.env.GITHUB_TOKEN}@github.com/${repoOwner}/${repoName}.git`;
|
|
1919
|
+
shellExec(`git clone --depth 1 --no-checkout ${authUrl} ${targetDir}`, { disableLog: true });
|
|
1920
|
+
shellExec(`cd ${targetDir} && git sparse-checkout set ${subPath} && git checkout`, { disableLog: true });
|
|
1921
|
+
logger.info('[sparseCheckoutDirectory] sparse checkout complete', localPath);
|
|
1922
|
+
return true;
|
|
1923
|
+
},
|
|
1924
|
+
|
|
1925
|
+
/**
|
|
1926
|
+
* Ensures a deploy's public source repo (e.g. `engine-prototype`) is present
|
|
1927
|
+
* next to the engine and reset to a pristine HEAD, so catalog `sourceMoves`
|
|
1928
|
+
* can (re)pull custom sources even after a previous build moved them out of
|
|
1929
|
+
* the source tree.
|
|
1930
|
+
*
|
|
1931
|
+
* Clones `../<repoName>` when missing; otherwise restores a clean checkout
|
|
1932
|
+
* (`git checkout .` brings back any moved-out tracked files) and pulls latest.
|
|
1933
|
+
* Mirrors the sibling-repo handling used by `syncPrivateConf`.
|
|
1934
|
+
*
|
|
1935
|
+
* @param {string} repoName - Public source repo name (e.g. `engine-prototype`).
|
|
1936
|
+
* @returns {boolean} `true` when the repo is available on disk.
|
|
1937
|
+
* @memberof UnderpostRepository
|
|
1938
|
+
*/
|
|
1939
|
+
pullSourceRepo(repoName) {
|
|
1940
|
+
const username = process.env.GITHUB_USERNAME;
|
|
1941
|
+
if (!username || !repoName) return false;
|
|
1942
|
+
const repoPath = `../${repoName}`;
|
|
1943
|
+
const gitUri = `${username}/${repoName}`;
|
|
1944
|
+
if (!fs.existsSync(repoPath)) {
|
|
1945
|
+
shellExec(`cd .. && underpost clone ${gitUri}`, { silent: true });
|
|
1946
|
+
} else {
|
|
1947
|
+
const repoAbsPath = path.resolve(repoPath);
|
|
1948
|
+
shellExec(`git config --global --add safe.directory '${repoAbsPath}'`);
|
|
1949
|
+
shellExec(`cd ${repoPath} && git checkout . && git clean -f -d && underpost pull . ${gitUri}`, {
|
|
1950
|
+
silent: true,
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
return fs.existsSync(repoPath);
|
|
1954
|
+
},
|
|
1656
1955
|
};
|
|
1657
1956
|
}
|
|
1658
1957
|
|