@nanobpm/nano-workforce 0.178.5 → 0.179.0
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/CHANGELOG.md +6 -0
- package/app/deliveryGraphDeploy.test.ts +7 -7
- package/app/deliveryGraphDispatch.test.ts +6 -6
- package/app/deliveryGraphDispatch.ts +7 -4
- package/app/deliveryRunner.test.ts +49 -15
- package/app/deliveryRunner.ts +52 -23
- package/app/feature.ts +7 -4
- package/app/plan.ts +6 -3
- package/app/repoEnvelope.ts +75 -4
- package/e2e/delivery-graph-dispatch.e2e.ts +3 -3
- package/e2e/delivery-graph.e2e.ts +3 -3
- package/openapi.yaml +87 -13
- package/operations/dispatchDeliveryGraph.test.ts +136 -10
- package/operations/dispatchDeliveryGraph.ts +49 -1
- package/operations/listStagedProposals.test.ts +1 -1
- package/package.json +1 -1
- package/pages/delivery-graphs/delivery-graphs.css +27 -0
- package/pages/delivery-graphs/staged.mount.js +93 -14
- package/test/delivery-graphs-staged-confirm.test.ts +63 -5
|
@@ -91,13 +91,15 @@ function harness() {
|
|
|
91
91
|
};
|
|
92
92
|
const click = (el: { dispatchEvent: (ev: unknown) => boolean }) =>
|
|
93
93
|
el.dispatchEvent(new domWindow.Event("click", { bubbles: true, cancelable: true }));
|
|
94
|
+
const fire = (el: { dispatchEvent: (ev: unknown) => boolean }, type: string) =>
|
|
95
|
+
el.dispatchEvent(new domWindow.Event(type, { bubbles: true, cancelable: true }));
|
|
94
96
|
|
|
95
|
-
return { host, calls, teardown, flush, click };
|
|
97
|
+
return { host, calls, teardown, flush, click, fire };
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
const posts = (calls: FetchCall[], url: string) => calls.filter((c) => c.method === "POST" && c.url === url);
|
|
99
101
|
|
|
100
|
-
test("#569: Dispatch dispatches via the in-DOM confirmation even when native window.confirm is suppressed", async () => {
|
|
102
|
+
test("#569/#729: Dispatch dispatches via the in-DOM confirmation with the repo envelope even when native window.confirm is suppressed", async () => {
|
|
101
103
|
const h = harness();
|
|
102
104
|
try {
|
|
103
105
|
await h.flush();
|
|
@@ -105,7 +107,8 @@ test("#569: Dispatch dispatches via the in-DOM confirmation even when native win
|
|
|
105
107
|
assert(dispatchBtn, "the mount must render a Dispatch button for the staged proposal");
|
|
106
108
|
|
|
107
109
|
// Click Dispatch — with a suppressed native confirm, the PRE-FIX mount POSTs nothing; the fixed
|
|
108
|
-
// mount instead reveals an in-DOM "Confirm dispatch" step
|
|
110
|
+
// mount instead reveals an in-DOM "Confirm dispatch" step (with the #729 envelope fields) and has
|
|
111
|
+
// NOT yet POSTed.
|
|
109
112
|
h.click(dispatchBtn);
|
|
110
113
|
await h.flush();
|
|
111
114
|
assertEquals(posts(h.calls, DISPATCH_URL).length, 0, "Dispatch must not POST before the operator confirms in-DOM");
|
|
@@ -113,12 +116,67 @@ test("#569: Dispatch dispatches via the in-DOM confirmation even when native win
|
|
|
113
116
|
assert(confirmBtn, "clicking Dispatch must reveal an in-DOM Confirm-dispatch control (#569), not call window.confirm");
|
|
114
117
|
assert(!h.host.querySelector("[data-dispatch]"), "the plain Dispatch button is replaced by the inline confirmation while it is open");
|
|
115
118
|
|
|
116
|
-
//
|
|
119
|
+
// The operator supplies the repository-isolation envelope the door now requires (#729): a staged
|
|
120
|
+
// proposal carries no repo metadata, so the cockpit collects it here.
|
|
121
|
+
const repoInput = h.host.querySelector("[data-dispatch-repository]");
|
|
122
|
+
const baseInput = h.host.querySelector("[data-dispatch-base]");
|
|
123
|
+
assert(repoInput && baseInput, "the Dispatch confirmation must expose repository + base-branch fields (#729)");
|
|
124
|
+
repoInput.value = "acme/widgets";
|
|
125
|
+
baseInput.value = "main";
|
|
126
|
+
|
|
127
|
+
// Confirm — the digest AND the envelope are POSTed to the dispatch door, with no reliance on a native modal.
|
|
117
128
|
h.click(confirmBtn);
|
|
118
129
|
await h.flush();
|
|
119
130
|
const dispatched = posts(h.calls, DISPATCH_URL);
|
|
120
131
|
assertEquals(dispatched.length, 1, "confirming in-DOM must POST exactly once to the dispatch door");
|
|
121
|
-
assertEquals(
|
|
132
|
+
assertEquals(
|
|
133
|
+
JSON.parse(dispatched[0].body),
|
|
134
|
+
{ digest: PROPOSAL.digest, repository: "acme/widgets", baseBranch: "main" },
|
|
135
|
+
"the dispatch POST carries the staged digest and the operator-supplied repo envelope",
|
|
136
|
+
);
|
|
137
|
+
} finally {
|
|
138
|
+
h.teardown();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("#729: Dispatch checkout-less posts `repoless: true` (no repo envelope) instead of repository/baseBranch", async () => {
|
|
143
|
+
const h = harness();
|
|
144
|
+
try {
|
|
145
|
+
await h.flush();
|
|
146
|
+
h.click(h.host.querySelector("[data-dispatch]"));
|
|
147
|
+
await h.flush();
|
|
148
|
+
const box = h.host.querySelector("[data-dispatch-repoless]");
|
|
149
|
+
assert(box, "the Dispatch confirmation must expose a checkout-less (repoless) opt-out (#729)");
|
|
150
|
+
box.checked = true;
|
|
151
|
+
h.fire(box, "change");
|
|
152
|
+
await h.flush();
|
|
153
|
+
|
|
154
|
+
h.click(h.host.querySelector("[data-dispatch-confirm]"));
|
|
155
|
+
await h.flush();
|
|
156
|
+
const dispatched = posts(h.calls, DISPATCH_URL);
|
|
157
|
+
assertEquals(dispatched.length, 1, "confirming a checkout-less dispatch must POST exactly once");
|
|
158
|
+
assertEquals(
|
|
159
|
+
JSON.parse(dispatched[0].body),
|
|
160
|
+
{ digest: PROPOSAL.digest, repoless: true },
|
|
161
|
+
"a checkout-less dispatch posts `repoless: true` and omits repository/baseBranch (mutually exclusive, #729)",
|
|
162
|
+
);
|
|
163
|
+
} finally {
|
|
164
|
+
h.teardown();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("#729: confirming a dispatch with neither the repo envelope nor checkout-less does NOT POST (keeps the confirmation open)", async () => {
|
|
169
|
+
const h = harness();
|
|
170
|
+
try {
|
|
171
|
+
await h.flush();
|
|
172
|
+
h.click(h.host.querySelector("[data-dispatch]"));
|
|
173
|
+
await h.flush();
|
|
174
|
+
// Confirm with blank repository/baseBranch and checkout-less unticked — the door would 400, so the
|
|
175
|
+
// mount guards client-side: no POST, and the confirmation stays open so the operator can fix it.
|
|
176
|
+
h.click(h.host.querySelector("[data-dispatch-confirm]"));
|
|
177
|
+
await h.flush();
|
|
178
|
+
assertEquals(posts(h.calls, DISPATCH_URL).length, 0, "an incomplete envelope must not POST to the dispatch door (#729)");
|
|
179
|
+
assert(h.host.querySelector("[data-dispatch-confirm]"), "the confirmation stays open so the operator can supply the envelope");
|
|
122
180
|
} finally {
|
|
123
181
|
h.teardown();
|
|
124
182
|
}
|