openxiangda 1.0.241 → 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.
Files changed (2) hide show
  1. package/lib/cli.js +77 -20
  2. 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 || Date.now() >= deadline || waitSeconds === 0) throw error;
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
- if (!['running', 'deployed'].includes(active?.status)) break;
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 !== 'deployed') {
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
- const evidence = buildBoundDeploymentEvidence(
4631
- readJsonInput(flags['evidence-json'], 'evidence-json'),
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') {
@@ -30089,6 +30144,8 @@ function buildWorkspacePublishEnv(
30089
30144
  module.exports = {
30090
30145
  buildResourceManifestSddTargets,
30091
30146
  buildScopeGrantSourceSyncDecision,
30147
+ deploymentEvidencePendingError,
30148
+ deploymentQueueWaitDecision,
30092
30149
  main,
30093
30150
  resolveReleaseCommandScopedFiles,
30094
30151
  resolveDeliveryV2BackendManifestReplacementIntent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.241",
3
+ "version": "1.0.242",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {