openxiangda 1.0.235 → 1.0.237
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/lib/cli.js +5 -16
- package/lib/delivery-v2-cli.js +30 -0
- package/lib/delivery-v2-executor.js +216 -3
- package/lib/release-plan.js +39 -6
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -166,7 +166,10 @@ const {
|
|
|
166
166
|
withReleaseClientSessionArgs,
|
|
167
167
|
} = require('./application-environments');
|
|
168
168
|
const { startDeveloperCenter } = require('./developer-center');
|
|
169
|
-
const {
|
|
169
|
+
const {
|
|
170
|
+
createDeliveryV2Cli,
|
|
171
|
+
deliveryV2SourceRevision,
|
|
172
|
+
} = require('./delivery-v2-cli');
|
|
170
173
|
const {
|
|
171
174
|
describeOpenApiOperation,
|
|
172
175
|
listOpenApiOperations,
|
|
@@ -1477,20 +1480,6 @@ function getDeliveryV2Cli() {
|
|
|
1477
1480
|
return deliveryV2Cli;
|
|
1478
1481
|
}
|
|
1479
1482
|
|
|
1480
|
-
function deliveryV2SourceRevision(packageDigest) {
|
|
1481
|
-
return {
|
|
1482
|
-
repo: `sha256:${packageDigest}`,
|
|
1483
|
-
repositoryId: `sha256:${packageDigest}`,
|
|
1484
|
-
repoAliases: [`sha256:${packageDigest}`],
|
|
1485
|
-
baseCommit: packageDigest,
|
|
1486
|
-
treeHash: packageDigest,
|
|
1487
|
-
branch: 'delivery-v2',
|
|
1488
|
-
mainBranch: null,
|
|
1489
|
-
remoteName: null,
|
|
1490
|
-
remoteUrlHash: null,
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
1483
|
function installDeliveryV2Context(target, run, targets = {}) {
|
|
1495
1484
|
const control = run?.control || {};
|
|
1496
1485
|
const publishLeaseId = String(control.publishLeaseId || '').trim();
|
|
@@ -1509,7 +1498,7 @@ function installDeliveryV2Context(target, run, targets = {}) {
|
|
|
1509
1498
|
'DELIVERY_CONTROL_INVALID: ReleaseRun 缺少 publishLease/baseline/change/session/package 控制信息'
|
|
1510
1499
|
);
|
|
1511
1500
|
}
|
|
1512
|
-
const sourceRevision = deliveryV2SourceRevision(packageDigest);
|
|
1501
|
+
const sourceRevision = deliveryV2SourceRevision(target, packageDigest);
|
|
1513
1502
|
saveChangeBaseline(target, {
|
|
1514
1503
|
baselineId,
|
|
1515
1504
|
appType: target.appType,
|
package/lib/delivery-v2-cli.js
CHANGED
|
@@ -166,6 +166,35 @@ function createClientSessionId() {
|
|
|
166
166
|
.toString('hex')}`;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
function deliveryV2SourceRevision(target, packageDigest) {
|
|
170
|
+
const packageRepositoryId = `sha256:${packageDigest}`;
|
|
171
|
+
const logicalRepositoryId = String(
|
|
172
|
+
target?.logicalApp?.sourceRepositoryId ||
|
|
173
|
+
target?.state?.logicalApp?.sourceRepositoryId ||
|
|
174
|
+
''
|
|
175
|
+
)
|
|
176
|
+
.trim()
|
|
177
|
+
.toLowerCase();
|
|
178
|
+
const repoAliases = Array.from(
|
|
179
|
+
new Set(
|
|
180
|
+
[packageRepositoryId, logicalRepositoryId].filter(value =>
|
|
181
|
+
/^sha256:[a-f0-9]{64}$/.test(value)
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
).sort();
|
|
185
|
+
return {
|
|
186
|
+
repo: packageRepositoryId,
|
|
187
|
+
repositoryId: packageRepositoryId,
|
|
188
|
+
repoAliases,
|
|
189
|
+
baseCommit: packageDigest,
|
|
190
|
+
treeHash: packageDigest,
|
|
191
|
+
branch: 'delivery-v2',
|
|
192
|
+
mainBranch: null,
|
|
193
|
+
remoteName: null,
|
|
194
|
+
remoteUrlHash: null,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
169
198
|
function usageError(message) {
|
|
170
199
|
const error = new Error(message);
|
|
171
200
|
error.code = 'DELIVERY_USAGE_ERROR';
|
|
@@ -213,4 +242,5 @@ function assertDependencies(value) {
|
|
|
213
242
|
|
|
214
243
|
module.exports = {
|
|
215
244
|
createDeliveryV2Cli,
|
|
245
|
+
deliveryV2SourceRevision,
|
|
216
246
|
};
|
|
@@ -232,6 +232,11 @@ function createDeliveryV2Executor(dependencies) {
|
|
|
232
232
|
activeRun,
|
|
233
233
|
input.targets
|
|
234
234
|
);
|
|
235
|
+
restoreDeliveryCheckpointFiles(
|
|
236
|
+
input.executionRoot,
|
|
237
|
+
activeRun,
|
|
238
|
+
executionTarget
|
|
239
|
+
);
|
|
235
240
|
activeRun = await checkpoint(
|
|
236
241
|
input.config,
|
|
237
242
|
executionTarget,
|
|
@@ -297,7 +302,11 @@ function createDeliveryV2Executor(dependencies) {
|
|
|
297
302
|
completed: index + 1,
|
|
298
303
|
total: steps.length,
|
|
299
304
|
},
|
|
300
|
-
result: compactStepResult(step.id, result
|
|
305
|
+
result: compactStepResult(step.id, result, {
|
|
306
|
+
executionRoot: input.executionRoot,
|
|
307
|
+
run: activeRun,
|
|
308
|
+
target: executionTarget,
|
|
309
|
+
}),
|
|
301
310
|
}
|
|
302
311
|
);
|
|
303
312
|
}
|
|
@@ -800,7 +809,7 @@ function packageSummary(manifest, previousManifest) {
|
|
|
800
809
|
};
|
|
801
810
|
}
|
|
802
811
|
|
|
803
|
-
function compactStepResult(stepId, result) {
|
|
812
|
+
function compactStepResult(stepId, result, context = {}) {
|
|
804
813
|
if (!result || typeof result !== 'object') return { ok: true };
|
|
805
814
|
if (stepId === 'app-finalize') {
|
|
806
815
|
return {
|
|
@@ -811,10 +820,212 @@ function compactStepResult(stepId, result) {
|
|
|
811
820
|
null,
|
|
812
821
|
};
|
|
813
822
|
}
|
|
814
|
-
|
|
823
|
+
const compact = {
|
|
815
824
|
ok: true,
|
|
816
825
|
id: result.id || result.release?.id || null,
|
|
817
826
|
};
|
|
827
|
+
const stagedResources = normalizeCheckpointStagedResources(
|
|
828
|
+
Array.isArray(result.stagedResources)
|
|
829
|
+
? result.stagedResources
|
|
830
|
+
: result.stagedResource
|
|
831
|
+
? [result.stagedResource]
|
|
832
|
+
: []
|
|
833
|
+
);
|
|
834
|
+
if (stagedResources.length > 0) {
|
|
835
|
+
compact.stagedResources = stagedResources;
|
|
836
|
+
}
|
|
837
|
+
const satisfiedSelectors = uniqueStrings(result.satisfiedSelectors);
|
|
838
|
+
if (satisfiedSelectors.length > 0) {
|
|
839
|
+
compact.satisfiedSelectors = satisfiedSelectors;
|
|
840
|
+
}
|
|
841
|
+
if (stepId === 'backend-stage') {
|
|
842
|
+
const bindingContracts = readDeliverySupportFile(
|
|
843
|
+
context.executionRoot,
|
|
844
|
+
context.run,
|
|
845
|
+
context.target,
|
|
846
|
+
'backend-binding-contracts.json'
|
|
847
|
+
);
|
|
848
|
+
if (bindingContracts) {
|
|
849
|
+
compact.backendBindingContracts = bindingContracts;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return compact;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function restoreDeliveryCheckpointFiles(executionRoot, run, target) {
|
|
856
|
+
const changeId = String(run?.control?.changeId || '').trim();
|
|
857
|
+
if (!changeId) return { stagedResourceCount: 0, restored: false };
|
|
858
|
+
const checkpointResults = Object.values(run?.result || {});
|
|
859
|
+
const staged = new Map();
|
|
860
|
+
const satisfiedSelectors = [];
|
|
861
|
+
let backendBindingContracts = null;
|
|
862
|
+
for (const result of checkpointResults) {
|
|
863
|
+
for (const resource of normalizeCheckpointStagedResources(
|
|
864
|
+
result?.stagedResources || []
|
|
865
|
+
)) {
|
|
866
|
+
staged.set(checkpointStagedResourceKey(resource), resource);
|
|
867
|
+
}
|
|
868
|
+
satisfiedSelectors.push(...uniqueStrings(result?.satisfiedSelectors));
|
|
869
|
+
if (result?.backendBindingContracts) {
|
|
870
|
+
backendBindingContracts = cloneJson(result.backendBindingContracts);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (staged.size === 0 && !backendBindingContracts) {
|
|
874
|
+
return { stagedResourceCount: 0, restored: false };
|
|
875
|
+
}
|
|
876
|
+
const releaseDir = deliveryReleaseDirectory(
|
|
877
|
+
executionRoot,
|
|
878
|
+
changeId,
|
|
879
|
+
target?.deploymentId
|
|
880
|
+
);
|
|
881
|
+
fs.mkdirSync(releaseDir, { recursive: true });
|
|
882
|
+
const resources = Array.from(staged.values()).sort((left, right) =>
|
|
883
|
+
checkpointStagedResourceKey(left).localeCompare(
|
|
884
|
+
checkpointStagedResourceKey(right)
|
|
885
|
+
)
|
|
886
|
+
);
|
|
887
|
+
if (resources.length > 0) {
|
|
888
|
+
writeJsonAtomic(
|
|
889
|
+
path.join(releaseDir, 'staged-resources.json'),
|
|
890
|
+
resources
|
|
891
|
+
);
|
|
892
|
+
writeJsonAtomic(
|
|
893
|
+
path.join(releaseDir, 'staged-resources.context.json'),
|
|
894
|
+
{
|
|
895
|
+
contractVersion: 'staged_resources_context_v1',
|
|
896
|
+
appType: target.appType,
|
|
897
|
+
profile: target.profileName,
|
|
898
|
+
changeId,
|
|
899
|
+
deploymentId: target.deploymentId || null,
|
|
900
|
+
baselineId: run.control?.baselineId || null,
|
|
901
|
+
clientSessionId: run.control?.clientSessionId || null,
|
|
902
|
+
initializedAt: new Date().toISOString(),
|
|
903
|
+
restoredFromDeliveryRunId: run.id,
|
|
904
|
+
...(uniqueStrings(satisfiedSelectors).length > 0
|
|
905
|
+
? { satisfiedSelectors: uniqueStrings(satisfiedSelectors) }
|
|
906
|
+
: {}),
|
|
907
|
+
}
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
if (backendBindingContracts) {
|
|
911
|
+
writeJsonAtomic(
|
|
912
|
+
path.join(releaseDir, 'backend-binding-contracts.json'),
|
|
913
|
+
backendBindingContracts
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
return {
|
|
917
|
+
stagedResourceCount: resources.length,
|
|
918
|
+
restored: true,
|
|
919
|
+
backendBindingContracts: Boolean(backendBindingContracts),
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function readDeliverySupportFile(
|
|
924
|
+
executionRoot,
|
|
925
|
+
run,
|
|
926
|
+
target,
|
|
927
|
+
fileName
|
|
928
|
+
) {
|
|
929
|
+
const changeId = String(run?.control?.changeId || '').trim();
|
|
930
|
+
if (!changeId || !executionRoot) return null;
|
|
931
|
+
const file = path.join(
|
|
932
|
+
deliveryReleaseDirectory(
|
|
933
|
+
executionRoot,
|
|
934
|
+
changeId,
|
|
935
|
+
target?.deploymentId
|
|
936
|
+
),
|
|
937
|
+
fileName
|
|
938
|
+
);
|
|
939
|
+
if (!fs.existsSync(file)) return null;
|
|
940
|
+
try {
|
|
941
|
+
return cloneJson(JSON.parse(fs.readFileSync(file, 'utf8')));
|
|
942
|
+
} catch {
|
|
943
|
+
throw deliveryError(
|
|
944
|
+
'DELIVERY_CHECKPOINT_FILE_INVALID',
|
|
945
|
+
`${fileName} 不是合法 JSON,不能创建可恢复检查点`,
|
|
946
|
+
false
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function deliveryReleaseDirectory(executionRoot, changeId, deploymentId) {
|
|
952
|
+
const normalizedChangeId = String(changeId || '').trim();
|
|
953
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(normalizedChangeId)) {
|
|
954
|
+
throw deliveryError(
|
|
955
|
+
'DELIVERY_CONTROL_INVALID',
|
|
956
|
+
'ReleaseRun changeId 不能用于恢复暂存资源',
|
|
957
|
+
false
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
const base = path.join(
|
|
961
|
+
path.resolve(executionRoot),
|
|
962
|
+
'.openxiangda',
|
|
963
|
+
'releases',
|
|
964
|
+
normalizedChangeId
|
|
965
|
+
);
|
|
966
|
+
return deploymentId ? path.join(base, String(deploymentId)) : base;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function normalizeCheckpointStagedResources(values) {
|
|
970
|
+
if (!Array.isArray(values)) return [];
|
|
971
|
+
const supportedKinds = new Set([
|
|
972
|
+
'RuntimeRelease',
|
|
973
|
+
'PageRelease',
|
|
974
|
+
'BackendRelease',
|
|
975
|
+
'WorkflowRelease',
|
|
976
|
+
'FormRelease',
|
|
977
|
+
]);
|
|
978
|
+
return values
|
|
979
|
+
.filter(value => value && typeof value === 'object' && !Array.isArray(value))
|
|
980
|
+
.filter(value => supportedKinds.has(String(value.kind || '').trim()))
|
|
981
|
+
.filter(value => {
|
|
982
|
+
const releaseId = String(
|
|
983
|
+
value.identity?.releaseId || value.releaseId || ''
|
|
984
|
+
).trim();
|
|
985
|
+
const hash = String(value.hash || value.resourceHash || '')
|
|
986
|
+
.trim()
|
|
987
|
+
.toLowerCase();
|
|
988
|
+
const formUuid = String(
|
|
989
|
+
value.identity?.formUuid || value.formUuid || ''
|
|
990
|
+
).trim();
|
|
991
|
+
return (
|
|
992
|
+
Boolean(releaseId) &&
|
|
993
|
+
/^[a-f0-9]{64}$/.test(hash) &&
|
|
994
|
+
(value.kind !== 'FormRelease' || Boolean(formUuid))
|
|
995
|
+
);
|
|
996
|
+
})
|
|
997
|
+
.map(cloneJson);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
function checkpointStagedResourceKey(resource) {
|
|
1001
|
+
if (resource.kind === 'FormRelease') {
|
|
1002
|
+
return `FormRelease:${
|
|
1003
|
+
resource.identity?.formUuid || resource.formUuid
|
|
1004
|
+
}`;
|
|
1005
|
+
}
|
|
1006
|
+
return String(resource.kind);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function uniqueStrings(values) {
|
|
1010
|
+
return Array.from(
|
|
1011
|
+
new Set(
|
|
1012
|
+
(Array.isArray(values) ? values : [])
|
|
1013
|
+
.map(value => String(value || '').trim())
|
|
1014
|
+
.filter(Boolean)
|
|
1015
|
+
)
|
|
1016
|
+
).sort();
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function writeJsonAtomic(file, value) {
|
|
1020
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
1021
|
+
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, {
|
|
1022
|
+
mode: 0o600,
|
|
1023
|
+
});
|
|
1024
|
+
fs.renameSync(temporary, file);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
function cloneJson(value) {
|
|
1028
|
+
return JSON.parse(JSON.stringify(value));
|
|
818
1029
|
}
|
|
819
1030
|
|
|
820
1031
|
function structuredFailure(error, runId, stage, component) {
|
|
@@ -949,7 +1160,9 @@ function assertDependencies(value) {
|
|
|
949
1160
|
|
|
950
1161
|
module.exports = {
|
|
951
1162
|
CONFIG_TARGET_BY_RESOURCE_TYPE,
|
|
1163
|
+
compactStepResult,
|
|
952
1164
|
createDeliveryV2Executor,
|
|
953
1165
|
releaseTargets,
|
|
1166
|
+
restoreDeliveryCheckpointFiles,
|
|
954
1167
|
structuredFailure,
|
|
955
1168
|
};
|
package/lib/release-plan.js
CHANGED
|
@@ -251,11 +251,14 @@ function buildTargetedResourceReleaseSteps(
|
|
|
251
251
|
function buildDirectConfigurationReleaseSteps(
|
|
252
252
|
targets,
|
|
253
253
|
profileArg,
|
|
254
|
-
changeId
|
|
254
|
+
changeId,
|
|
255
|
+
options = {}
|
|
255
256
|
) {
|
|
257
|
+
const excludedTypes = new Set(options.excludeTypes || []);
|
|
256
258
|
return Object.entries(targets.resourceSelectors || {})
|
|
257
259
|
.filter(
|
|
258
260
|
([type, selectors]) =>
|
|
261
|
+
!excludedTypes.has(type) &&
|
|
259
262
|
directResourceTypeForKey(type) &&
|
|
260
263
|
uniqueSorted(selectors || []).length > 0
|
|
261
264
|
)
|
|
@@ -318,11 +321,24 @@ function buildWorkspaceReleaseSteps(
|
|
|
318
321
|
Object.values(targets.resourceSelectors || {}).some(
|
|
319
322
|
selectors => (selectors || []).length > 0
|
|
320
323
|
);
|
|
324
|
+
const formPermissionGroups = uniqueSorted(
|
|
325
|
+
targets.resourceSelectors?.formPermissionGroups || []
|
|
326
|
+
);
|
|
327
|
+
const stagesFormRelease =
|
|
328
|
+
runtimeMode === 'react-spa' &&
|
|
329
|
+
(targets.forms.length > 0 || formPermissionGroups.length > 0);
|
|
321
330
|
const directConfigurationSteps =
|
|
322
331
|
buildDirectConfigurationReleaseSteps(
|
|
323
332
|
targets,
|
|
324
333
|
profileArg,
|
|
325
|
-
changeId
|
|
334
|
+
changeId,
|
|
335
|
+
{
|
|
336
|
+
// A FormRelease is a single immutable snapshot. Publishing form
|
|
337
|
+
// settings and permission groups as sibling steps from the same live
|
|
338
|
+
// parent lets the second descriptor replace the first and discard its
|
|
339
|
+
// schema. Stage both resource types in one bundle instead.
|
|
340
|
+
excludeTypes: stagesFormRelease ? ['formPermissionGroups'] : [],
|
|
341
|
+
}
|
|
326
342
|
);
|
|
327
343
|
if (runtimeMode === 'react-spa') {
|
|
328
344
|
if (targets.forms.length > 0) {
|
|
@@ -336,6 +352,23 @@ function buildWorkspaceReleaseSteps(
|
|
|
336
352
|
)
|
|
337
353
|
)
|
|
338
354
|
);
|
|
355
|
+
}
|
|
356
|
+
if (stagesFormRelease) {
|
|
357
|
+
const resourceTypes = [
|
|
358
|
+
...(targets.forms.length > 0 ? ['form-setting'] : []),
|
|
359
|
+
...(formPermissionGroups.length > 0
|
|
360
|
+
? ['form-permission-group']
|
|
361
|
+
: []),
|
|
362
|
+
];
|
|
363
|
+
const qualify = resourceTypes.length > 1;
|
|
364
|
+
const selectors = [
|
|
365
|
+
...targets.forms.map(code =>
|
|
366
|
+
qualify ? `form-setting:${code}` : code
|
|
367
|
+
),
|
|
368
|
+
...formPermissionGroups.map(code =>
|
|
369
|
+
qualify ? `form-permission-group:${code}` : code
|
|
370
|
+
),
|
|
371
|
+
];
|
|
339
372
|
steps.push(
|
|
340
373
|
createStep(
|
|
341
374
|
'form-stage',
|
|
@@ -343,9 +376,9 @@ function buildWorkspaceReleaseSteps(
|
|
|
343
376
|
[
|
|
344
377
|
'resource',
|
|
345
378
|
'publish',
|
|
346
|
-
'
|
|
379
|
+
resourceTypes.join(','),
|
|
347
380
|
'--only',
|
|
348
|
-
|
|
381
|
+
selectors.join(','),
|
|
349
382
|
],
|
|
350
383
|
profileArg,
|
|
351
384
|
changeId
|
|
@@ -378,7 +411,7 @@ function buildWorkspaceReleaseSteps(
|
|
|
378
411
|
);
|
|
379
412
|
}
|
|
380
413
|
if (
|
|
381
|
-
|
|
414
|
+
stagesFormRelease ||
|
|
382
415
|
targets.functions.length > 0 ||
|
|
383
416
|
targets.automations.length > 0 ||
|
|
384
417
|
targets.workflows.length > 0 ||
|
|
@@ -386,7 +419,7 @@ function buildWorkspaceReleaseSteps(
|
|
|
386
419
|
directConfigurationSteps.length > 0
|
|
387
420
|
) {
|
|
388
421
|
const hasStagedChildren =
|
|
389
|
-
|
|
422
|
+
stagesFormRelease ||
|
|
390
423
|
targets.functions.length > 0 ||
|
|
391
424
|
targets.automations.length > 0 ||
|
|
392
425
|
targets.workflows.length > 0 ||
|