run402 4.72.1 → 4.73.1
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/gitvault-surface.json +1 -1
- package/lib/deploy-v2.mjs +13 -79
- package/lib/gitvault-scaffold.mjs +23 -8
- package/lib/init.mjs +48 -0
- package/lib/org.mjs +21 -5
- package/lib/projects.mjs +3 -15
- package/lib/up.mjs +29 -6
- package/package.json +1 -1
- package/sdk/dist/actions.d.ts +27 -1
- package/sdk/dist/actions.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +85 -1
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +57 -0
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.d.ts +6 -0
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +38 -43
- package/sdk/dist/namespaces/gitvault.js.map +1 -1
- package/sdk/dist/namespaces/org.d.ts +8 -0
- package/sdk/dist/namespaces/org.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.js +14 -0
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +87 -2
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/client-detect.d.ts +10 -0
- package/sdk/dist/node/client-detect.d.ts.map +1 -0
- package/sdk/dist/node/client-detect.js +10 -0
- package/sdk/dist/node/client-detect.js.map +1 -0
- package/sdk/dist/node/deploy-manifest.js +6 -8
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
|
@@ -546,6 +546,80 @@ function deriveSliceKinds(spec) {
|
|
|
546
546
|
set.add("asset");
|
|
547
547
|
return [...set].sort((a, b) => (a === "release" ? -1 : 1));
|
|
548
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Decide and (when warranted) run the rehearsal for a cloud apply. Returns
|
|
551
|
+
* the `DeployResult.rehearsal` block plus, after a passed rehearsal, the
|
|
552
|
+
* bound `requiredPlan` the commit must carry. Throws `REHEARSAL_FAILED`
|
|
553
|
+
* (with the report attached) when the rehearsal fails — nothing has been
|
|
554
|
+
* committed at that point.
|
|
555
|
+
*/
|
|
556
|
+
async function rehearseBeforeCommit(client, plan, planId, project, opts, emit) {
|
|
557
|
+
const skip = (reason) => {
|
|
558
|
+
emit({ type: "rehearsal.skipped", reason });
|
|
559
|
+
return { block: { status: "skipped", reason } };
|
|
560
|
+
};
|
|
561
|
+
if (opts.noRehearse)
|
|
562
|
+
return skip("disabled");
|
|
563
|
+
if (opts.requiredPlan)
|
|
564
|
+
return skip("reviewed_plan");
|
|
565
|
+
const envelope = plan.rehearsal;
|
|
566
|
+
if (!envelope || !envelope.available) {
|
|
567
|
+
const reason = envelope?.reason ?? "no_migrations";
|
|
568
|
+
return skip(reason === "no_live_release" ? "no_live_release" : "no_migrations");
|
|
569
|
+
}
|
|
570
|
+
emit({ type: "rehearsal.started", planId });
|
|
571
|
+
let rehearsed;
|
|
572
|
+
try {
|
|
573
|
+
rehearsed = await client.request(`/apply/v1/plans/${encodeURIComponent(planId)}/rehearse`, {
|
|
574
|
+
method: "POST",
|
|
575
|
+
body: {},
|
|
576
|
+
authMeta: { method: "deploy.rehearse", capability: "project.deploy", target: { project_id: project } },
|
|
577
|
+
context: "rehearsing deploy plan",
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
catch (err) {
|
|
581
|
+
throw translateDeployError(err, "rehearsal", planId, null);
|
|
582
|
+
}
|
|
583
|
+
const report = rehearsed.report;
|
|
584
|
+
emit({
|
|
585
|
+
type: "rehearsal.finished",
|
|
586
|
+
planId,
|
|
587
|
+
status: report.status,
|
|
588
|
+
operationId: report.operation_id,
|
|
589
|
+
branchProjectId: report.branch_project_id,
|
|
590
|
+
durationMs: report.duration_ms,
|
|
591
|
+
});
|
|
592
|
+
if (report.status !== "passed") {
|
|
593
|
+
throw new Run402DeployError(`Rehearsal failed on a contained branch; nothing was committed. ${describeRehearsalFailure(report)}`, {
|
|
594
|
+
code: "REHEARSAL_FAILED",
|
|
595
|
+
phase: "rehearsal",
|
|
596
|
+
retryable: false,
|
|
597
|
+
context: "rehearsing deploy plan",
|
|
598
|
+
planId,
|
|
599
|
+
operationId: report.operation_id,
|
|
600
|
+
body: { rehearsal: report, next_actions: report.next_actions },
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
const bound = report.next_actions.find((a) => a.type === "commit_plan")?.body?.required_plan;
|
|
604
|
+
return {
|
|
605
|
+
block: {
|
|
606
|
+
status: "passed",
|
|
607
|
+
report,
|
|
608
|
+
operation_id: report.operation_id,
|
|
609
|
+
branch_project_id: report.branch_project_id,
|
|
610
|
+
},
|
|
611
|
+
...(bound ? { requiredPlan: { planId: bound.plan_id, planFingerprint: bound.plan_fingerprint } } : {}),
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function describeRehearsalFailure(report) {
|
|
615
|
+
const failedMigration = report.migrations.find((m) => m.status === "failed");
|
|
616
|
+
if (failedMigration)
|
|
617
|
+
return `Migration ${failedMigration.id} failed${failedMigration.error ? `: ${failedMigration.error}` : ""}.`;
|
|
618
|
+
const failedCheck = report.checks.find((c) => c.status === "failed");
|
|
619
|
+
if (failedCheck)
|
|
620
|
+
return `Check ${failedCheck.name} failed${failedCheck.error ? `: ${failedCheck.error}` : ""}.`;
|
|
621
|
+
return report.error?.message ? `${report.error.message}.` : "";
|
|
622
|
+
}
|
|
549
623
|
async function applyOnce(client, spec, opts, emit) {
|
|
550
624
|
const allowWarningCodes = normalizeAllowWarningCodes(opts.allowWarningCodes);
|
|
551
625
|
const target = opts.target === "core" ? "core" : "cloud";
|
|
@@ -601,6 +675,15 @@ async function applyOnce(client, spec, opts, emit) {
|
|
|
601
675
|
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
602
676
|
});
|
|
603
677
|
const { planId, operationId } = requirePersistedPlan(plan, "applying deploy");
|
|
678
|
+
// first-deploy-agent-dx: rehearsal is apply's decision, from the plan
|
|
679
|
+
// envelope. A migration-bearing plan against a project with a live release
|
|
680
|
+
// is rehearsed on a contained branch and committed only on a passing
|
|
681
|
+
// report; a first deploy (`reason: "no_live_release"`) has nothing to
|
|
682
|
+
// protect and commits directly. A passed rehearsal binds the commit to the
|
|
683
|
+
// report's `required_plan` — unbound commits of rehearsed plans are
|
|
684
|
+
// refused by the gateway.
|
|
685
|
+
const rehearsal = await rehearseBeforeCommit(client, plan, planId, spec.project, opts, emit);
|
|
686
|
+
const requiredPlan = rehearsal.requiredPlan ?? opts.requiredPlan;
|
|
604
687
|
// gitvault §6.5 — the handshake. Content is uploaded, so the artifacts this
|
|
605
688
|
// release ships are fixed; `authorize` verifies snapshot correspondence,
|
|
606
689
|
// mints the activation token, and hands back the commit block. It throws
|
|
@@ -613,8 +696,9 @@ async function applyOnce(client, spec, opts, emit) {
|
|
|
613
696
|
apply_plan_sha256: plan.gitvault?.apply_plan_sha256 ?? null,
|
|
614
697
|
})
|
|
615
698
|
: undefined;
|
|
616
|
-
const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project,
|
|
699
|
+
const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project, requiredPlan, gitvaultCommit), "applying deploy");
|
|
617
700
|
const result = await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
701
|
+
result.rehearsal = rehearsal.block;
|
|
618
702
|
// v1.48 unified-apply: thread the plan response's `asset_entries[]` back
|
|
619
703
|
// into DeployResult.assets so callers reading `result.assets.byKey[key]`
|
|
620
704
|
// get the gateway-authoritative `AssetRef` envelope (URLs, SRI, etag).
|