underpost 3.2.30 → 3.2.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ghpkg.ci.yml +87 -0
- package/.github/workflows/npmpkg.ci.yml +9 -6
- package/.github/workflows/publish.ci.yml +3 -3
- package/.github/workflows/pwa-microservices-template-page.cd.yml +0 -7
- package/.github/workflows/release.cd.yml +1 -1
- package/CHANGELOG.md +1230 -971
- package/CLI-HELP.md +14 -6
- package/README.md +3 -3
- package/bin/build.js +40 -4
- package/bin/deploy.js +2 -2
- package/bump.config.js +1 -0
- package/docker-compose.yml +26 -26
- 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-default-development/deployment.yaml +2 -2
- package/package.json +15 -15
- package/scripts/disk-clean.sh +85 -60
- package/scripts/test-monitor.sh +1 -1
- package/src/api/core/core.controller.js +4 -65
- package/src/api/core/core.router.js +8 -14
- package/src/api/default/default.controller.js +2 -70
- package/src/api/default/default.router.js +7 -17
- package/src/api/document/document.controller.js +5 -77
- package/src/api/document/document.router.js +9 -13
- package/src/api/file/file.controller.js +9 -53
- package/src/api/file/file.router.js +14 -6
- package/src/api/test/test.controller.js +8 -53
- package/src/api/test/test.router.js +1 -4
- package/src/cli/cluster.js +104 -11
- package/src/cli/db.js +4 -2
- package/src/cli/deploy.js +60 -11
- package/src/cli/docker-compose.js +212 -1
- package/src/cli/fs.js +45 -25
- package/src/cli/image.js +147 -51
- package/src/cli/index.js +26 -6
- package/src/cli/release.js +50 -4
- package/src/cli/repository.js +98 -24
- package/src/cli/run.js +380 -178
- package/src/cli/secrets.js +75 -46
- package/src/cli/ssh.js +30 -11
- package/src/client/components/core/Modal.js +38 -4
- package/src/index.js +1 -1
- package/src/server/catalog.js +2 -0
- package/src/server/conf.js +163 -3
- package/src/server/downloader.js +3 -3
- package/src/server/middlewares.js +152 -0
package/src/cli/index.js
CHANGED
|
@@ -108,18 +108,24 @@ program
|
|
|
108
108
|
.option('--edit', 'Edit last commit.')
|
|
109
109
|
.option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the commit context.')
|
|
110
110
|
.option('--cached', 'Commit staged changes only or context.')
|
|
111
|
-
.option('--hashes <hashes>', 'Comma-separated list of specific file hashes of commits.')
|
|
112
|
-
.option('--extension <extension>', 'specific file extensions of commits.')
|
|
113
111
|
.option(
|
|
114
|
-
'--
|
|
115
|
-
'
|
|
112
|
+
'--init-repo [origin]',
|
|
113
|
+
'Initialize a git repository at the specified path. Optionally set the git remote origin URL.',
|
|
116
114
|
)
|
|
115
|
+
.option('--hashes <hashes>', 'Comma-separated list of specific file hashes of commits.')
|
|
116
|
+
.option('--extension <extension>', 'specific file extensions of commits.')
|
|
117
|
+
.option('--changelog', 'Print the plain changelog of the last N commits (see --from-n-commit, default 1).')
|
|
117
118
|
.option('--changelog-build', 'Builds a CHANGELOG.md file based on the commit history')
|
|
118
119
|
.option('--changelog-min-version <version>', 'Sets the minimum version limit for --changelog-build (default: 2.85.0)')
|
|
119
120
|
.option(
|
|
120
121
|
'--changelog-no-hash',
|
|
121
122
|
'Excludes commit hashes from the generated changelog entries (used with --changelog-build).',
|
|
122
123
|
)
|
|
124
|
+
.option(
|
|
125
|
+
'--changelog-msg',
|
|
126
|
+
'Print the sanitized, commit-ready changelog message of the last N commits (see --from-n-commit, default 1). Empty when there are no tagged entries.',
|
|
127
|
+
)
|
|
128
|
+
.option('--from-n-commit <n>', 'Number of latest commits to include in --changelog/--changelog-msg (default: 1).')
|
|
123
129
|
.option('--unpush', 'With --log, automatically sets range to unpushed commits ahead of remote.')
|
|
124
130
|
.option('-b', 'Shows the current Git branch name.')
|
|
125
131
|
.option('-p [branch]', 'Shows the reflog for the specified branch.')
|
|
@@ -434,25 +440,31 @@ program
|
|
|
434
440
|
.option('--rm <image-id>', 'Removes specified Underpost Dockerfile images.')
|
|
435
441
|
.option('--path [path]', 'The path to the Dockerfile directory.')
|
|
436
442
|
.option('--image-name [image-name]', 'Sets a custom name for the Docker image.')
|
|
437
|
-
.option('--image-path [image-path]', 'Sets the output path for the tar image archive.')
|
|
443
|
+
.option('--image-out-path [image-out-path]', 'Sets the output path for the tar image archive.')
|
|
438
444
|
.option('--dockerfile-name [dockerfile-name]', 'Sets a custom name for the Dockerfile.')
|
|
439
445
|
.option('--podman-save', 'Exports the built image as a tar file using Podman.')
|
|
440
|
-
.option('--pull-base', 'Pulls base
|
|
446
|
+
.option('--pull-base', 'Pulls the base image prerequisites (rockylinux:9) on the host; combine with --build.')
|
|
441
447
|
.option('--spec', 'Get current cached list of container images used by all pods')
|
|
442
448
|
.option('--namespace <namespace>', 'Kubernetes namespace for image operations (defaults to "default").')
|
|
443
449
|
.option('--kind', 'Set kind cluster env image context management.')
|
|
444
450
|
.option('--kubeadm', 'Set kubeadm cluster env image context management.')
|
|
445
451
|
.option('--k3s', 'Set k3s cluster env image context management.')
|
|
452
|
+
.option('--docker-compose', 'Load the built image tar into the local Docker store for Docker Compose availability.')
|
|
446
453
|
.option('--node-name', 'Set node name for kubeadm or k3s cluster env image context management.')
|
|
447
454
|
.option('--reset', 'Performs a build without using the cache.')
|
|
448
455
|
.option('--dev', 'Use development mode.')
|
|
449
456
|
.option('--pull-dockerhub <dockerhub-image>', 'Sets a custom Docker Hub image for base image pulls.')
|
|
457
|
+
.option(
|
|
458
|
+
'--import-tar <tar-path>',
|
|
459
|
+
'Load a pre-built image tar archive (e.g. ./image-v1.0.0.tar) into the enabled target(s) without building. Combine with --kind, --kubeadm, --k3s and/or --docker-compose; the archive is loaded into each enabled one.',
|
|
460
|
+
)
|
|
450
461
|
.description('Manages Docker images, including building, saving, and loading into Kubernetes clusters.')
|
|
451
462
|
.action(async (options) => {
|
|
452
463
|
if (options.rm) Underpost.image.rm({ ...options, imageName: options.rm });
|
|
453
464
|
if (options.ls) Underpost.image.list({ ...options, log: true });
|
|
454
465
|
if (options.pullBase) Underpost.image.pullBaseImages(options);
|
|
455
466
|
if (options.build) Underpost.image.build(options);
|
|
467
|
+
if (options.importTar) Underpost.image.importTar(options);
|
|
456
468
|
if (options.pullDockerhub)
|
|
457
469
|
Underpost.image.pullDockerHubImage({ ...options, dockerhubImage: options.pullDockerhub });
|
|
458
470
|
});
|
|
@@ -692,6 +704,7 @@ program
|
|
|
692
704
|
.option('--kubeadm', 'Sets the kubeadm cluster context for the runner execution.')
|
|
693
705
|
.option('--k3s', 'Sets the k3s cluster context for the runner execution.')
|
|
694
706
|
.option('--kind', 'Sets the kind cluster context for the runner execution.')
|
|
707
|
+
.option('--traffic <traffic>', 'Blue/green traffic colour to bake into generated manifests (default: blue).')
|
|
695
708
|
.option('--git-clean', 'Runs git clean on volume mount paths before copying.')
|
|
696
709
|
.option('--deploy-id <deploy-id>', 'Sets deploy id context for the runner execution.')
|
|
697
710
|
.option('--user <user>', 'Sets user context for the runner execution.')
|
|
@@ -749,6 +762,7 @@ program
|
|
|
749
762
|
'--test',
|
|
750
763
|
'Enables test/generic-purpose mode for the runner (e.g. use self-signed TLS instead of cert-manager).',
|
|
751
764
|
)
|
|
765
|
+
.option('--branch <branch>', 'Sets the branch for git operations (default: current branch).')
|
|
752
766
|
.description('Runs specified scripts using various runners.')
|
|
753
767
|
.action(Underpost.run.callback);
|
|
754
768
|
|
|
@@ -765,6 +779,12 @@ program
|
|
|
765
779
|
'--deploy-id <deploy-id>',
|
|
766
780
|
"Deployment to run as the app container (default: dd-default). 'dd-default' self-bootstraps a fresh engine; any other id runs the standard 'underpost start' command (mirrors src/cli/deploy.js).",
|
|
767
781
|
)
|
|
782
|
+
.option(
|
|
783
|
+
'--docker-compose-id <docker-compose-id>',
|
|
784
|
+
'Selects a canonical custom-workflow stack at engine-private/conf/<deploy-id>/docker-compose/<docker-compose-id>/ ' +
|
|
785
|
+
'(docker-compose.yml + compose.env + nginx.conf, used as-is; nginx/env generation is skipped). ' +
|
|
786
|
+
'e.g. --deploy-id dd-cyberia --docker-compose-id cyberia for the Cyberia MMO ecosystem.',
|
|
787
|
+
)
|
|
768
788
|
.option('--env <env>', 'Deployment environment for non-default deploy ids (default: development).')
|
|
769
789
|
.option('--generate', 'Render dynamic supporting files (nginx router config, env-file, app-command override).')
|
|
770
790
|
.option('--up', 'Start the full stack detached (regenerates config first).')
|
package/src/cli/release.js
CHANGED
|
@@ -117,9 +117,57 @@ const buildVersionBumpTargets = () => [
|
|
|
117
117
|
/(underpost-engine:v)\d+\.\d+\.\d+/g,
|
|
118
118
|
/(type=raw,value=v)\d+\.\d+\.\d+/g,
|
|
119
119
|
/(UNDERPOST_VERSION=)\d+\.\d+\.\d+/g,
|
|
120
|
+
/(UNDERPOST_VERSION:\s*['"]?)\d+\.\d+\.\d+/g,
|
|
120
121
|
],
|
|
121
122
|
},
|
|
122
123
|
|
|
124
|
+
// ── Docker-compose image-tag defaults. Root compose + generator + cyberia runtime compose.
|
|
125
|
+
// Tags live in `${VAR:-vX.Y.Z}` / `VAR=vX.Y.Z` shapes bumpp cannot detect. ──
|
|
126
|
+
{
|
|
127
|
+
file: 'docker-compose.yml',
|
|
128
|
+
patterns: /(_TAG:-v)\d+\.\d+\.\d+/g,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
file: 'src/cli/docker-compose.js',
|
|
132
|
+
patterns: /(_TAG=v)\d+\.\d+\.\d+/g,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
file: 'src/runtime/engine-cyberia/docker-compose.yml',
|
|
136
|
+
patterns: /(_TAG:-v)\d+\.\d+\.\d+/g,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
file: 'engine-private/conf/dd-cyberia/docker-compose/cyberia/docker-compose.yml',
|
|
140
|
+
patterns: /(_TAG:-v)\d+\.\d+\.\d+/g,
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// ── Cyberia CLI dev image tar/name defaults (bin/cyberia.js). ──
|
|
144
|
+
{
|
|
145
|
+
file: 'bin/cyberia.js',
|
|
146
|
+
patterns: [/(-dev_v)\d+\.\d+\.\d+(?=\.tar)/g, /(-dev:v)\d+\.\d+\.\d+/g],
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
// ── Runtime Dockerfiles: `ARG UNDERPOST_VERSION=X.Y.Z` build-arg defaults. ──
|
|
150
|
+
{
|
|
151
|
+
dir: 'src/runtime',
|
|
152
|
+
match: /^Dockerfile(\.\w+)?$/,
|
|
153
|
+
patterns: /(ARG UNDERPOST_VERSION=)\d+\.\d+\.\d+/g,
|
|
154
|
+
recursive: true,
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// ── Runtime compose.env shipped tag defaults ──
|
|
158
|
+
{
|
|
159
|
+
dir: 'src/runtime',
|
|
160
|
+
match: /^compose\.env$/,
|
|
161
|
+
patterns: /(_TAG=v)\d+\.\d+\.\d+/g,
|
|
162
|
+
recursive: true,
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// ── Deploy-monitor smoke-test image default (scripts/test-monitor.sh). ──
|
|
166
|
+
{
|
|
167
|
+
file: 'scripts/test-monitor.sh',
|
|
168
|
+
patterns: /(underpost\/[a-z0-9-]+:v)\d+\.\d+\.\d+/g,
|
|
169
|
+
},
|
|
170
|
+
|
|
123
171
|
// ── engine-private confs (gitignored — bumped only if present). ──
|
|
124
172
|
{
|
|
125
173
|
dir: 'engine-private/conf',
|
|
@@ -448,11 +496,10 @@ class UnderpostRelease {
|
|
|
448
496
|
let commitMsg = message;
|
|
449
497
|
if (!commitMsg) {
|
|
450
498
|
shellCd('/home/dd/engine');
|
|
451
|
-
|
|
499
|
+
commitMsg = shellExec(`node bin cmt --changelog-msg --changelog-no-hash`, {
|
|
452
500
|
stdout: true,
|
|
453
501
|
silent: true,
|
|
454
502
|
}).trim();
|
|
455
|
-
commitMsg = Underpost.repo.sanitizeChangelogMessage(rawMsg);
|
|
456
503
|
shellCd('/home/dd');
|
|
457
504
|
}
|
|
458
505
|
commitMsg = (commitMsg || '').trim() || `Update ${repoName} repository`;
|
|
@@ -492,11 +539,10 @@ class UnderpostRelease {
|
|
|
492
539
|
let commitMsg = message;
|
|
493
540
|
if (!commitMsg) {
|
|
494
541
|
shellCd('/home/dd/engine');
|
|
495
|
-
|
|
542
|
+
commitMsg = shellExec(`node bin cmt --changelog-msg --changelog-no-hash`, {
|
|
496
543
|
stdout: true,
|
|
497
544
|
silent: true,
|
|
498
545
|
}).trim();
|
|
499
|
-
commitMsg = Underpost.repo.sanitizeChangelogMessage(rawMsg);
|
|
500
546
|
}
|
|
501
547
|
commitMsg = (commitMsg || '').trim() || `Update pwa-microservices-template repository`;
|
|
502
548
|
shellCd('/home/dd');
|
package/src/cli/repository.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getDataDeploy,
|
|
22
22
|
buildReplicaId,
|
|
23
23
|
writeEnv,
|
|
24
|
+
readConfInstances,
|
|
24
25
|
} from '../server/conf.js';
|
|
25
26
|
import { buildClient, unzipClientBuild, mergeClientBuildZip } from '../client-builder/client-build.js';
|
|
26
27
|
import { DefaultConf } from '../../conf.js';
|
|
@@ -145,6 +146,14 @@ class UnderpostRepository {
|
|
|
145
146
|
) {
|
|
146
147
|
if (!repoPath) repoPath = '.';
|
|
147
148
|
|
|
149
|
+
if (options.initRepo) {
|
|
150
|
+
Underpost.repo.initLocalRepo({
|
|
151
|
+
path: repoPath,
|
|
152
|
+
origin: typeof options.initRepo === 'string' ? options.initRepo : undefined,
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
148
157
|
if (options.hasChanges) {
|
|
149
158
|
const status = shellExec(`cd ${repoPath} && git status --porcelain`, {
|
|
150
159
|
stdout: true,
|
|
@@ -218,7 +227,7 @@ class UnderpostRepository {
|
|
|
218
227
|
return;
|
|
219
228
|
}
|
|
220
229
|
|
|
221
|
-
if (options.changelog !== undefined || options.changelogBuild) {
|
|
230
|
+
if (options.changelog !== undefined || options.changelogBuild || options.changelogMsg !== undefined) {
|
|
222
231
|
const releaseMatch = 'New release v:';
|
|
223
232
|
// Helper: parse [<tag>] commits into grouped sections
|
|
224
233
|
const buildSectionChangelog = (commits) => {
|
|
@@ -255,7 +264,8 @@ class UnderpostRepository {
|
|
|
255
264
|
stdout: true,
|
|
256
265
|
silent: true,
|
|
257
266
|
disableLog: true,
|
|
258
|
-
|
|
267
|
+
silentOnError: true,
|
|
268
|
+
}).toString();
|
|
259
269
|
return rawLog
|
|
260
270
|
.split('\n')
|
|
261
271
|
.map((line) => {
|
|
@@ -346,15 +356,18 @@ class UnderpostRepository {
|
|
|
346
356
|
fs.writeFileSync(changelogPath, `# Changelog\n\n${changelog}`);
|
|
347
357
|
logger.info('CHANGELOG.md built at', changelogPath);
|
|
348
358
|
} else {
|
|
349
|
-
// --changelog
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
359
|
+
// --changelog / --changelog-msg: message from the last N commits, where N is --from-n-commit
|
|
360
|
+
// (default 1, last commit only). No auto-detection.
|
|
361
|
+
const n = parseInt(options.fromNCommit) > 0 ? parseInt(options.fromNCommit) : 1;
|
|
362
|
+
const sections = buildVersionSections(fetchHistory(n));
|
|
363
|
+
const changelog = renderSections(sections);
|
|
364
|
+
if (options.changelogMsg !== undefined) {
|
|
365
|
+
// Sanitized, commit-ready message; empty string when there are no tagged entries so
|
|
366
|
+
// callers fall back to their own generic default instead of a placeholder.
|
|
367
|
+
console.log(Underpost.repo.sanitizeChangelogMessage(changelog));
|
|
368
|
+
} else {
|
|
369
|
+
console.log(changelog || `No changelog entries found.\n`);
|
|
370
|
+
}
|
|
358
371
|
}
|
|
359
372
|
|
|
360
373
|
return;
|
|
@@ -1257,17 +1270,40 @@ Prevent build private config repo.`,
|
|
|
1257
1270
|
return copiedFiles;
|
|
1258
1271
|
},
|
|
1259
1272
|
|
|
1273
|
+
/**
|
|
1274
|
+
* Resolves the default branch for a remote GitHub repository by querying
|
|
1275
|
+
* `git ls-remote --symref` and extracting the HEAD ref target.
|
|
1276
|
+
* Falls back to `main` when detection fails.
|
|
1277
|
+
* @param {string} repo - The GitHub repository (e.g., "owner/repo").
|
|
1278
|
+
* @returns {string} The default branch name (e.g. "main" or "master").
|
|
1279
|
+
* @memberof UnderpostRepository
|
|
1280
|
+
*/
|
|
1281
|
+
getDefaultBranch(repo) {
|
|
1282
|
+
if (!repo) return 'main';
|
|
1283
|
+
const authUrl = Underpost.repo.resolveAuthUrl(repo);
|
|
1284
|
+
const raw = shellExec(
|
|
1285
|
+
`GIT_TERMINAL_PROMPT=0 git -c credential.helper= ls-remote --symref "${authUrl}" HEAD 2>&1`,
|
|
1286
|
+
{ stdout: true, silent: true, disableLog: true, silentOnError: true },
|
|
1287
|
+
);
|
|
1288
|
+
// --symref emits a line like: ref: refs/heads/main HEAD
|
|
1289
|
+
const match = typeof raw === 'string' ? raw.match(/^ref:\s*refs\/heads\/(\S+)\tHEAD$/m) : null;
|
|
1290
|
+
const branch = match ? match[1] : 'main';
|
|
1291
|
+
logger.info('getDefaultBranch', { repo, branch });
|
|
1292
|
+
return branch;
|
|
1293
|
+
},
|
|
1294
|
+
|
|
1260
1295
|
/**
|
|
1261
1296
|
* Dispatches a GitHub Actions workflow using gh CLI or curl fallback.
|
|
1262
1297
|
* @param {object} options - Dispatch options.
|
|
1263
1298
|
* @param {string} options.repo - The GitHub repository (e.g., "owner/repo").
|
|
1264
1299
|
* @param {string} options.workflowFile - The workflow file name (e.g., "engine-core.cd.yml").
|
|
1265
|
-
* @param {string} [options.ref
|
|
1300
|
+
* @param {string} [options.ref] - The git ref to dispatch against. Auto-detects the remote's default branch when omitted.
|
|
1266
1301
|
* @param {object} [options.inputs={}] - Key-value inputs for the workflow_dispatch event.
|
|
1267
1302
|
* @memberof UnderpostRepository
|
|
1268
1303
|
*/
|
|
1269
|
-
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: '
|
|
1270
|
-
const { repo, workflowFile,
|
|
1304
|
+
dispatchWorkflow(options = { repo: '', workflowFile: '', ref: '', inputs: {} }) {
|
|
1305
|
+
const { repo, workflowFile, inputs } = options;
|
|
1306
|
+
const ref = options.ref || Underpost.repo.getDefaultBranch(repo);
|
|
1271
1307
|
const ghAvailable = shellExec('command -v gh 2>/dev/null', {
|
|
1272
1308
|
stdout: true,
|
|
1273
1309
|
silent: true,
|
|
@@ -1344,14 +1380,18 @@ Prevent build private config repo.`,
|
|
|
1344
1380
|
if (!url) return false;
|
|
1345
1381
|
const authUrl = Underpost.repo.resolveAuthUrl(url);
|
|
1346
1382
|
// GIT_TERMINAL_PROMPT=0 prevents git from hanging on credential prompts inside containers.
|
|
1347
|
-
|
|
1383
|
+
// `-c credential.helper=` disables any host-configured credential helper so its stderr
|
|
1384
|
+
// warnings don't pollute the ls-remote output; the token is already embedded in authUrl.
|
|
1385
|
+
const raw = shellExec(`GIT_TERMINAL_PROMPT=0 git -c credential.helper= ls-remote "${authUrl}" HEAD 2>&1`, {
|
|
1348
1386
|
stdout: true,
|
|
1349
1387
|
silent: true,
|
|
1350
1388
|
disableLog: true,
|
|
1351
1389
|
silentOnError: true,
|
|
1352
1390
|
});
|
|
1353
|
-
|
|
1354
|
-
|
|
1391
|
+
const refLine = typeof raw === 'string' ? (raw.match(/^[0-9a-f]{40}\t.*$/m) || [])[0] : undefined;
|
|
1392
|
+
const accessible = !!refLine;
|
|
1393
|
+
logger.info('isRemoteRepo', { url, accessible, ref: refLine || (raw || '').trim().split('\n').pop() });
|
|
1394
|
+
return accessible;
|
|
1355
1395
|
},
|
|
1356
1396
|
|
|
1357
1397
|
/**
|
|
@@ -1422,17 +1462,31 @@ Prevent build private config repo.`,
|
|
|
1422
1462
|
* @memberof UnderpostRepository
|
|
1423
1463
|
*/
|
|
1424
1464
|
getUnpushedCount(repoPath = '.', fallback = 1) {
|
|
1465
|
+
// Every git call is silentOnError: a detached HEAD (CI checkout) or a missing upstream must
|
|
1466
|
+
// degrade to the fallback, never throw — otherwise the thrown error is logged to stdout and
|
|
1467
|
+
// can be captured as a commit message by callers that read this command's output.
|
|
1425
1468
|
const branch = shellExec(`cd ${repoPath} && git branch --show-current`, {
|
|
1426
1469
|
stdout: true,
|
|
1427
1470
|
silent: true,
|
|
1428
1471
|
disableLog: true,
|
|
1429
|
-
|
|
1430
|
-
|
|
1472
|
+
silentOnError: true,
|
|
1473
|
+
})
|
|
1474
|
+
.toString()
|
|
1475
|
+
.trim();
|
|
1476
|
+
if (!branch) return { count: fallback, branch: '', hasUnpushed: false };
|
|
1477
|
+
shellExec(`cd ${repoPath} && git fetch origin 2>/dev/null`, {
|
|
1478
|
+
silent: true,
|
|
1479
|
+
disableLog: true,
|
|
1480
|
+
silentOnError: true,
|
|
1481
|
+
});
|
|
1431
1482
|
const raw = shellExec(`cd ${repoPath} && git rev-list --count origin/${branch}..HEAD 2>/dev/null`, {
|
|
1432
1483
|
stdout: true,
|
|
1433
1484
|
silent: true,
|
|
1434
1485
|
disableLog: true,
|
|
1435
|
-
|
|
1486
|
+
silentOnError: true,
|
|
1487
|
+
})
|
|
1488
|
+
.toString()
|
|
1489
|
+
.trim();
|
|
1436
1490
|
const count = parseInt(raw);
|
|
1437
1491
|
const hasUnpushed = !isNaN(count) && count > 0;
|
|
1438
1492
|
return { count: hasUnpushed ? count : fallback, branch, hasUnpushed };
|
|
@@ -1447,7 +1501,7 @@ Prevent build private config repo.`,
|
|
|
1447
1501
|
*/
|
|
1448
1502
|
sanitizeChangelogMessage(message) {
|
|
1449
1503
|
if (!message) return '';
|
|
1450
|
-
|
|
1504
|
+
const sanitized = message
|
|
1451
1505
|
.replace(/^##\s+\d{4}-\d{2}-\d{2}\s*/gm, '')
|
|
1452
1506
|
.replace(/^###\s+(\S+)\s*/gm, '[$1] ')
|
|
1453
1507
|
.replace(/^- /gm, '')
|
|
@@ -1459,6 +1513,9 @@ Prevent build private config repo.`,
|
|
|
1459
1513
|
.join('\n')
|
|
1460
1514
|
.trim()
|
|
1461
1515
|
.replaceAll('] - ', '] ');
|
|
1516
|
+
// The empty-changelog placeholder must never become a commit message; return empty so
|
|
1517
|
+
// callers fall back to their own generic default.
|
|
1518
|
+
return sanitized === 'No changelog entries found.' ? '' : sanitized;
|
|
1462
1519
|
},
|
|
1463
1520
|
/**
|
|
1464
1521
|
* Initializes a git repository at the given path and configures user identity
|
|
@@ -1783,12 +1840,17 @@ Prevent build private config repo.`,
|
|
|
1783
1840
|
* 4. Falls back to `${GITHUB_USERNAME}/engine` when no match is found.
|
|
1784
1841
|
*
|
|
1785
1842
|
* @param {string} [runtime=''] - The runtime identifier to look up (e.g. `'cyberia-server'`, `'cyberia-client'`).
|
|
1843
|
+
* @param {boolean} [ownRuntimeRepo=false] - Whether to check for the runtime's own repository.
|
|
1786
1844
|
* @returns {string} The resolved `owner/repo` string.
|
|
1787
1845
|
* @memberof UnderpostRepository
|
|
1788
1846
|
*/
|
|
1789
|
-
resolveInstanceRepo(runtime = '') {
|
|
1847
|
+
resolveInstanceRepo(runtime = '', ownRuntimeRepo = false) {
|
|
1790
1848
|
const fallback = `${process.env.GITHUB_USERNAME}/engine`;
|
|
1791
1849
|
if (!runtime) return fallback;
|
|
1850
|
+
// A `.dev` suffix selects the development image workflow
|
|
1851
|
+
// (docker-image.<runtime>.dev.ci.yml) but resolves to the same instance
|
|
1852
|
+
// repo as its production counterpart, so strip it before matching.
|
|
1853
|
+
runtime = runtime.replace(/\.dev$/, '');
|
|
1792
1854
|
const ddRouter = './engine-private/deploy/dd.router';
|
|
1793
1855
|
const deployIds = fs.existsSync(ddRouter)
|
|
1794
1856
|
? fs
|
|
@@ -1801,8 +1863,10 @@ Prevent build private config repo.`,
|
|
|
1801
1863
|
const confPath = `./engine-private/conf/${deployId}/conf.instances.json`;
|
|
1802
1864
|
if (!fs.existsSync(confPath)) continue;
|
|
1803
1865
|
try {
|
|
1804
|
-
|
|
1805
|
-
|
|
1866
|
+
// readConfInstances returns the bare array of entries. The template
|
|
1867
|
+
// entries carry runtime + metadata.repository, so the un-expanded list
|
|
1868
|
+
// is enough here (no need to expand variants).
|
|
1869
|
+
const match = readConfInstances(deployId).find((i) => i && i.runtime === runtime);
|
|
1806
1870
|
if (match && match.metadata && match.metadata.repository) {
|
|
1807
1871
|
logger.info(`[resolveInstanceRepo] resolved from ${confPath}`, {
|
|
1808
1872
|
runtime,
|
|
@@ -1814,6 +1878,16 @@ Prevent build private config repo.`,
|
|
|
1814
1878
|
logger.warn(`[resolveInstanceRepo] failed to parse ${confPath}: ${err.message}`);
|
|
1815
1879
|
}
|
|
1816
1880
|
}
|
|
1881
|
+
if (ownRuntimeRepo) {
|
|
1882
|
+
const runtimeRepo = Underpost.repo.isRemoteRepo(`${process.env.GITHUB_USERNAME}/${runtime}`);
|
|
1883
|
+
if (runtimeRepo) {
|
|
1884
|
+
logger.info(`[resolveInstanceRepo] resolved from ${process.env.GITHUB_USERNAME}/${runtime}`, {
|
|
1885
|
+
runtime,
|
|
1886
|
+
repo: `${process.env.GITHUB_USERNAME}/${runtime}`,
|
|
1887
|
+
});
|
|
1888
|
+
return `${process.env.GITHUB_USERNAME}/${runtime}`;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1817
1891
|
return fallback;
|
|
1818
1892
|
},
|
|
1819
1893
|
|