openxiangda 1.0.240 → 1.0.242
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 +180 -22
- package/lib/delivery-v2-executor.js +4 -0
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -3698,6 +3698,29 @@ function deploymentQueueDetails(error) {
|
|
|
3698
3698
|
return value;
|
|
3699
3699
|
}
|
|
3700
3700
|
|
|
3701
|
+
function deploymentQueueWaitDecision(statusInput) {
|
|
3702
|
+
const status = String(statusInput || '').trim().toLowerCase();
|
|
3703
|
+
return {
|
|
3704
|
+
status,
|
|
3705
|
+
wait: status === 'running',
|
|
3706
|
+
evidencePending: status === 'deployed',
|
|
3707
|
+
};
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3710
|
+
function deploymentEvidencePendingError(deployment = {}) {
|
|
3711
|
+
const deploymentId = String(deployment.deploymentId || deployment.id || '').trim();
|
|
3712
|
+
const error = new Error(
|
|
3713
|
+
`APP_DEPLOYMENT_EVIDENCE_PENDING: 目标环境部署 ${deploymentId || '-'} 已完成激活,当前为 deployed,待提交测试证据;请先执行 openxiangda release test --deployment ${deploymentId || '<id>'} --evidence-json <JSON|file>`
|
|
3714
|
+
);
|
|
3715
|
+
error.code = 'APP_DEPLOYMENT_EVIDENCE_PENDING';
|
|
3716
|
+
error.data = {
|
|
3717
|
+
deploymentId: deploymentId || null,
|
|
3718
|
+
status: 'deployed',
|
|
3719
|
+
nextAction: 'release test',
|
|
3720
|
+
};
|
|
3721
|
+
return error;
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3701
3724
|
async function createApplicationDeploymentWhenAvailable(
|
|
3702
3725
|
config,
|
|
3703
3726
|
target,
|
|
@@ -3718,9 +3741,17 @@ async function createApplicationDeploymentWhenAvailable(
|
|
|
3718
3741
|
);
|
|
3719
3742
|
} catch (error) {
|
|
3720
3743
|
const queue = deploymentQueueDetails(error);
|
|
3721
|
-
if (!queue
|
|
3744
|
+
if (!queue) throw error;
|
|
3722
3745
|
const deploymentId = String(queue.deploymentId || '').trim();
|
|
3723
3746
|
if (!deploymentId) throw error;
|
|
3747
|
+
const queuedState = deploymentQueueWaitDecision(queue.status);
|
|
3748
|
+
if (queuedState.evidencePending) {
|
|
3749
|
+
throw deploymentEvidencePendingError({
|
|
3750
|
+
...queue,
|
|
3751
|
+
deploymentId,
|
|
3752
|
+
});
|
|
3753
|
+
}
|
|
3754
|
+
if (Date.now() >= deadline || waitSeconds === 0) throw error;
|
|
3724
3755
|
const delaySeconds = Math.min(
|
|
3725
3756
|
Math.max(Number(queue.retryAfterSeconds || 5), 1),
|
|
3726
3757
|
30
|
|
@@ -3742,7 +3773,14 @@ async function createApplicationDeploymentWhenAvailable(
|
|
|
3742
3773
|
} catch {
|
|
3743
3774
|
break;
|
|
3744
3775
|
}
|
|
3745
|
-
|
|
3776
|
+
const activeState = deploymentQueueWaitDecision(active?.status);
|
|
3777
|
+
if (activeState.evidencePending) {
|
|
3778
|
+
throw deploymentEvidencePendingError({
|
|
3779
|
+
...active,
|
|
3780
|
+
deploymentId,
|
|
3781
|
+
});
|
|
3782
|
+
}
|
|
3783
|
+
if (!activeState.wait) break;
|
|
3746
3784
|
}
|
|
3747
3785
|
if (Date.now() >= deadline) {
|
|
3748
3786
|
fail(
|
|
@@ -4004,11 +4042,40 @@ async function completeManagedDeployment(
|
|
|
4004
4042
|
evidence: deployment.evidenceSummary || evidenceInput || null,
|
|
4005
4043
|
};
|
|
4006
4044
|
}
|
|
4007
|
-
if (deployment.status
|
|
4045
|
+
if (!['deployed', 'failed'].includes(deployment.status)) {
|
|
4008
4046
|
fail(
|
|
4009
4047
|
`DEPLOYMENT_NOT_READY_FOR_COMPLETION: deployment ${deployment.id} 当前状态为 ${deployment.status}`
|
|
4010
4048
|
);
|
|
4011
4049
|
}
|
|
4050
|
+
const reconciled = await requestWithAuth(
|
|
4051
|
+
config,
|
|
4052
|
+
target.profileName,
|
|
4053
|
+
applicationDeploymentApiPath(
|
|
4054
|
+
logicalAppCode,
|
|
4055
|
+
deployment.id,
|
|
4056
|
+
'reconcile'
|
|
4057
|
+
),
|
|
4058
|
+
{
|
|
4059
|
+
method: 'POST',
|
|
4060
|
+
body: {
|
|
4061
|
+
reason: 'bind final active AppRelease lineage before test evidence',
|
|
4062
|
+
},
|
|
4063
|
+
}
|
|
4064
|
+
);
|
|
4065
|
+
if (reconciled.status === 'succeeded') {
|
|
4066
|
+
rememberTargetDeployment(target, reconciled);
|
|
4067
|
+
return {
|
|
4068
|
+
deployment: reconciled,
|
|
4069
|
+
evidence: reconciled.evidenceSummary || evidenceInput || null,
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
if (reconciled.status !== 'deployed') {
|
|
4073
|
+
fail(
|
|
4074
|
+
`DEPLOYMENT_RECONCILIATION_NOT_CONFIRMED: deployment ${deployment.id} 恢复后状态为 ${reconciled.status}`
|
|
4075
|
+
);
|
|
4076
|
+
}
|
|
4077
|
+
deployment = reconciled;
|
|
4078
|
+
rememberTargetDeployment(target, deployment);
|
|
4012
4079
|
const evidence = buildBoundDeploymentEvidence(
|
|
4013
4080
|
evidenceInput,
|
|
4014
4081
|
target,
|
|
@@ -4627,26 +4694,14 @@ async function runApplicationEnvironmentReleaseCommand(
|
|
|
4627
4694
|
const candidate = deployment.candidateId
|
|
4628
4695
|
? readCandidate(deployment.candidateId)
|
|
4629
4696
|
: null;
|
|
4630
|
-
|
|
4631
|
-
|
|
4697
|
+
return await completeManagedDeployment(
|
|
4698
|
+
config,
|
|
4632
4699
|
target,
|
|
4700
|
+
logicalApp.code,
|
|
4633
4701
|
deployment,
|
|
4634
|
-
candidate
|
|
4635
|
-
|
|
4636
|
-
const completed = await requestWithAuth(
|
|
4637
|
-
config,
|
|
4638
|
-
target.profileName,
|
|
4639
|
-
applicationDeploymentApiPath(logicalApp.code, deploymentId, 'complete'),
|
|
4640
|
-
{
|
|
4641
|
-
method: 'POST',
|
|
4642
|
-
body: {
|
|
4643
|
-
evidenceSummary: evidence,
|
|
4644
|
-
evidenceHash: sha256Canonical(evidence),
|
|
4645
|
-
},
|
|
4646
|
-
}
|
|
4702
|
+
candidate,
|
|
4703
|
+
readJsonInput(flags['evidence-json'], 'evidence-json')
|
|
4647
4704
|
);
|
|
4648
|
-
rememberTargetDeployment(target, completed);
|
|
4649
|
-
return { deployment: completed, evidence };
|
|
4650
4705
|
}
|
|
4651
4706
|
|
|
4652
4707
|
if (subcommand === 'rollback') {
|
|
@@ -14524,6 +14579,20 @@ async function resource(args) {
|
|
|
14524
14579
|
const publishLease = await telemetry.runPhase('lease', async () =>
|
|
14525
14580
|
resolvePublishLeaseForWrite(config, target, flags)
|
|
14526
14581
|
);
|
|
14582
|
+
const deliveryV2BackendManifestIntent =
|
|
14583
|
+
resolveDeliveryV2BackendManifestReplacementIntent({
|
|
14584
|
+
flags,
|
|
14585
|
+
typeFilters,
|
|
14586
|
+
codeFilters,
|
|
14587
|
+
manifest,
|
|
14588
|
+
});
|
|
14589
|
+
const publishLeaseFlags = deliveryV2BackendManifestIntent
|
|
14590
|
+
? {
|
|
14591
|
+
...flags,
|
|
14592
|
+
reason: deliveryV2BackendManifestIntent.reason,
|
|
14593
|
+
'replace-reason': deliveryV2BackendManifestIntent.reason,
|
|
14594
|
+
}
|
|
14595
|
+
: flags;
|
|
14527
14596
|
const changeBaselinePreflight = await telemetry.runPhase(
|
|
14528
14597
|
'preflight',
|
|
14529
14598
|
{
|
|
@@ -14553,10 +14622,12 @@ async function resource(args) {
|
|
|
14553
14622
|
pruneCandidates,
|
|
14554
14623
|
publishLeaseId: publishLease?.leaseId,
|
|
14555
14624
|
publishLease,
|
|
14556
|
-
publishLeaseFlags
|
|
14625
|
+
publishLeaseFlags,
|
|
14557
14626
|
scopedFiles,
|
|
14558
14627
|
baseRef: flags.since || 'HEAD',
|
|
14559
|
-
replaceManifest:
|
|
14628
|
+
replaceManifest:
|
|
14629
|
+
Boolean(flags['replace-manifest']) ||
|
|
14630
|
+
Boolean(deliveryV2BackendManifestIntent),
|
|
14560
14631
|
changeId:
|
|
14561
14632
|
flags.change || getStoredChangeBaseline(target)?.changeId || null,
|
|
14562
14633
|
stagedFormBindingOverlays,
|
|
@@ -14572,6 +14643,10 @@ async function resource(args) {
|
|
|
14572
14643
|
Boolean(typeFilters?.has('workflows')),
|
|
14573
14644
|
})
|
|
14574
14645
|
);
|
|
14646
|
+
if (deliveryV2BackendManifestIntent) {
|
|
14647
|
+
result.deliveryV2BackendManifestReplacement =
|
|
14648
|
+
deliveryV2BackendManifestIntent;
|
|
14649
|
+
}
|
|
14575
14650
|
if (changeBaselinePreflight) {
|
|
14576
14651
|
result.changeBaselinePreflight = changeBaselinePreflight;
|
|
14577
14652
|
}
|
|
@@ -28265,6 +28340,86 @@ function shouldReplaceResourceManifestItem(item, resourceKey, code, options = {}
|
|
|
28265
28340
|
return options.replaceManifest === true;
|
|
28266
28341
|
}
|
|
28267
28342
|
|
|
28343
|
+
function resolveDeliveryV2BackendManifestReplacementIntent({
|
|
28344
|
+
flags = {},
|
|
28345
|
+
typeFilters = null,
|
|
28346
|
+
codeFilters = null,
|
|
28347
|
+
manifest = {},
|
|
28348
|
+
deliveryContext = activeDeliveryV2Context,
|
|
28349
|
+
} = {}) {
|
|
28350
|
+
if (!deliveryContext || !flags['stage-only']) return null;
|
|
28351
|
+
const selectedTypes = Array.from(typeFilters || []);
|
|
28352
|
+
if (
|
|
28353
|
+
selectedTypes.length === 0 ||
|
|
28354
|
+
selectedTypes.some(
|
|
28355
|
+
type => !['functions', 'automations'].includes(type)
|
|
28356
|
+
)
|
|
28357
|
+
) {
|
|
28358
|
+
return null;
|
|
28359
|
+
}
|
|
28360
|
+
if (!Array.isArray(codeFilters) || codeFilters.length === 0) {
|
|
28361
|
+
const error = new Error(
|
|
28362
|
+
'DELIVERY_BACKEND_SCOPE_MISMATCH: Delivery V2 Backend stage 缺少冻结的精确 selector'
|
|
28363
|
+
);
|
|
28364
|
+
error.code = 'DELIVERY_BACKEND_SCOPE_MISMATCH';
|
|
28365
|
+
error.retryable = false;
|
|
28366
|
+
throw error;
|
|
28367
|
+
}
|
|
28368
|
+
const expectedSelectors = unique([
|
|
28369
|
+
...(deliveryContext.targets?.functions || []).map(
|
|
28370
|
+
code => `Function:${String(code)}`
|
|
28371
|
+
),
|
|
28372
|
+
...(deliveryContext.targets?.automations || []).map(
|
|
28373
|
+
code => `Automation:${String(code)}`
|
|
28374
|
+
),
|
|
28375
|
+
]).sort();
|
|
28376
|
+
const actualSelectors = unique([
|
|
28377
|
+
...(manifest.functions || []).map(
|
|
28378
|
+
item => `Function:${getResourceItemCode(item)}`
|
|
28379
|
+
),
|
|
28380
|
+
...(manifest.automations || []).map(
|
|
28381
|
+
item => `Automation:${getResourceItemCode(item)}`
|
|
28382
|
+
),
|
|
28383
|
+
])
|
|
28384
|
+
.filter(selector => !selector.endsWith(':'))
|
|
28385
|
+
.sort();
|
|
28386
|
+
if (
|
|
28387
|
+
expectedSelectors.length === 0 ||
|
|
28388
|
+
JSON.stringify(actualSelectors) !== JSON.stringify(expectedSelectors)
|
|
28389
|
+
) {
|
|
28390
|
+
const error = new Error(
|
|
28391
|
+
`DELIVERY_BACKEND_SCOPE_MISMATCH: Delivery V2 Backend stage 与 ReleaseRun 冻结范围不一致;expected=[${expectedSelectors.join(
|
|
28392
|
+
','
|
|
28393
|
+
)}] actual=[${actualSelectors.join(',')}]`
|
|
28394
|
+
);
|
|
28395
|
+
error.code = 'DELIVERY_BACKEND_SCOPE_MISMATCH';
|
|
28396
|
+
error.retryable = false;
|
|
28397
|
+
error.expectedSelectors = expectedSelectors;
|
|
28398
|
+
error.actualSelectors = actualSelectors;
|
|
28399
|
+
throw error;
|
|
28400
|
+
}
|
|
28401
|
+
const runId = String(deliveryContext.runId || '').trim();
|
|
28402
|
+
const packageDigest = String(deliveryContext.packageDigest || '').trim();
|
|
28403
|
+
if (!runId || !/^[a-f0-9]{64}$/.test(packageDigest)) {
|
|
28404
|
+
const error = new Error(
|
|
28405
|
+
'DELIVERY_CONTROL_INVALID: Delivery V2 Backend stage 缺少 ReleaseRun/packageDigest 权威上下文'
|
|
28406
|
+
);
|
|
28407
|
+
error.code = 'DELIVERY_CONTROL_INVALID';
|
|
28408
|
+
error.retryable = false;
|
|
28409
|
+
throw error;
|
|
28410
|
+
}
|
|
28411
|
+
return {
|
|
28412
|
+
mode: 'manifest_replacement',
|
|
28413
|
+
authority: 'delivery_v2_sealed_package',
|
|
28414
|
+
runId,
|
|
28415
|
+
packageDigest,
|
|
28416
|
+
selectors: actualSelectors,
|
|
28417
|
+
reason:
|
|
28418
|
+
`Delivery V2 ReleaseRun ${runId} sealed package ${packageDigest} ` +
|
|
28419
|
+
'authoritative backend manifest and binding contract replacement',
|
|
28420
|
+
};
|
|
28421
|
+
}
|
|
28422
|
+
|
|
28268
28423
|
function buildAutomationSourcePatchSources(existingDefinition, desiredDefinition) {
|
|
28269
28424
|
const existing = existingDefinition || {};
|
|
28270
28425
|
const desired = desiredDefinition || {};
|
|
@@ -29989,8 +30144,11 @@ function buildWorkspacePublishEnv(
|
|
|
29989
30144
|
module.exports = {
|
|
29990
30145
|
buildResourceManifestSddTargets,
|
|
29991
30146
|
buildScopeGrantSourceSyncDecision,
|
|
30147
|
+
deploymentEvidencePendingError,
|
|
30148
|
+
deploymentQueueWaitDecision,
|
|
29992
30149
|
main,
|
|
29993
30150
|
resolveReleaseCommandScopedFiles,
|
|
30151
|
+
resolveDeliveryV2BackendManifestReplacementIntent,
|
|
29994
30152
|
resolveDataViewSourceFormCodes,
|
|
29995
30153
|
satisfiedFormCodesFromContext,
|
|
29996
30154
|
stagedDataViewFormReleaseDependencies,
|
|
@@ -882,6 +882,10 @@ function compactStepResult(stepId, result, context = {}) {
|
|
|
882
882
|
if (bindingContracts) {
|
|
883
883
|
compact.backendBindingContracts = bindingContracts;
|
|
884
884
|
}
|
|
885
|
+
if (result.deliveryV2BackendManifestReplacement) {
|
|
886
|
+
compact.backendManifestReplacement =
|
|
887
|
+
result.deliveryV2BackendManifestReplacement;
|
|
888
|
+
}
|
|
885
889
|
}
|
|
886
890
|
return compact;
|
|
887
891
|
}
|