@treeseed/sdk 0.10.20 → 0.10.22
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/dist/operations/services/deploy.d.ts +2 -2
- package/dist/operations/services/deploy.js +54 -80
- package/dist/operations/services/railway-api.js +54 -7
- package/dist/reconcile/builtin-adapters.js +2 -1
- package/dist/workflow/operations.d.ts +6 -6
- package/dist/workflow/operations.js +7 -2
- package/package.json +1 -1
|
@@ -1005,7 +1005,7 @@ export declare function destroyCloudflareResources(tenantRoot: any, options?: {}
|
|
|
1005
1005
|
};
|
|
1006
1006
|
operations: {
|
|
1007
1007
|
worker: {
|
|
1008
|
-
status:
|
|
1008
|
+
status: any;
|
|
1009
1009
|
name: any;
|
|
1010
1010
|
};
|
|
1011
1011
|
formGuard: {
|
|
@@ -1013,7 +1013,7 @@ export declare function destroyCloudflareResources(tenantRoot: any, options?: {}
|
|
|
1013
1013
|
id: any;
|
|
1014
1014
|
preview?: undefined;
|
|
1015
1015
|
} | {
|
|
1016
|
-
status:
|
|
1016
|
+
status: any;
|
|
1017
1017
|
id: any;
|
|
1018
1018
|
preview: boolean;
|
|
1019
1019
|
};
|
|
@@ -1083,6 +1083,7 @@ function shouldManageCloudflareWebCacheRules(deployConfig, target) {
|
|
|
1083
1083
|
}
|
|
1084
1084
|
function cloudflareApiRequest(path, { method = "GET", body, env, allowFailure = false } = {}) {
|
|
1085
1085
|
const requestScript = `import { readFileSync } from 'node:fs';
|
|
1086
|
+
import { request } from 'node:https';
|
|
1086
1087
|
const input = JSON.parse(readFileSync(0, 'utf8') || '{}');
|
|
1087
1088
|
function errorMessage(error) {
|
|
1088
1089
|
const parts = [];
|
|
@@ -1099,15 +1100,32 @@ function errorMessage(error) {
|
|
|
1099
1100
|
return [...new Set(parts.filter(Boolean))].join('; ') || String(error);
|
|
1100
1101
|
}
|
|
1101
1102
|
try {
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1103
|
+
const body = input.body ? JSON.stringify(input.body) : undefined;
|
|
1104
|
+
const response = await new Promise((resolve, reject) => {
|
|
1105
|
+
const req = request(input.url, {
|
|
1106
|
+
method: input.method,
|
|
1107
|
+
headers: {
|
|
1108
|
+
authorization: 'Bearer ' + input.token,
|
|
1109
|
+
'content-type': 'application/json',
|
|
1110
|
+
},
|
|
1111
|
+
timeout: input.timeoutMs ?? 12000,
|
|
1112
|
+
}, (res) => {
|
|
1113
|
+
const chunks = [];
|
|
1114
|
+
res.setEncoding('utf8');
|
|
1115
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
1116
|
+
res.on('end', () => resolve({
|
|
1117
|
+
ok: typeof res.statusCode === 'number' && res.statusCode >= 200 && res.statusCode < 300,
|
|
1118
|
+
text: chunks.join(''),
|
|
1119
|
+
}));
|
|
1120
|
+
});
|
|
1121
|
+
req.on('timeout', () => {
|
|
1122
|
+
req.destroy(new Error('Cloudflare API request timed out'));
|
|
1123
|
+
});
|
|
1124
|
+
req.on('error', reject);
|
|
1125
|
+
if (body) req.write(body);
|
|
1126
|
+
req.end();
|
|
1109
1127
|
});
|
|
1110
|
-
const rawBody =
|
|
1128
|
+
const rawBody = response.text;
|
|
1111
1129
|
let payload;
|
|
1112
1130
|
try {
|
|
1113
1131
|
payload = rawBody ? JSON.parse(rawBody) : {};
|
|
@@ -1126,6 +1144,7 @@ try {
|
|
|
1126
1144
|
url: `https://api.cloudflare.com/client/v4${path}`,
|
|
1127
1145
|
method,
|
|
1128
1146
|
body,
|
|
1147
|
+
timeoutMs: 12e3,
|
|
1129
1148
|
token: env?.CLOUDFLARE_API_TOKEN ?? process.env.CLOUDFLARE_API_TOKEN ?? ""
|
|
1130
1149
|
});
|
|
1131
1150
|
const isTransient = (text) => /fetch failed|timed out|etimedout|econnreset|enetunreach|temporarily unavailable|aborted/iu.test(text || "");
|
|
@@ -1679,22 +1698,10 @@ function deleteKvNamespace(tenantRoot, namespaceId, { env, dryRun, preview = fal
|
|
|
1679
1698
|
if (dryRun) {
|
|
1680
1699
|
return { status: "planned", id: namespaceId, preview };
|
|
1681
1700
|
}
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
}
|
|
1686
|
-
const result = runWrangler(args, {
|
|
1687
|
-
cwd: tenantRoot,
|
|
1688
|
-
allowFailure: true,
|
|
1689
|
-
capture: true,
|
|
1690
|
-
env
|
|
1691
|
-
});
|
|
1692
|
-
const output = `${result.stdout ?? ""}
|
|
1693
|
-
${result.stderr ?? ""}`;
|
|
1694
|
-
if (result.status !== 0 && !looksLikeMissingResource(output)) {
|
|
1695
|
-
throw new Error(output.trim() || `Failed to delete KV namespace ${namespaceId}.`);
|
|
1696
|
-
}
|
|
1697
|
-
return { status: result.status === 0 ? "deleted" : "missing", id: namespaceId, preview };
|
|
1701
|
+
const accountId = env?.CLOUDFLARE_ACCOUNT_ID ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? "";
|
|
1702
|
+
const path = accountId ? `/accounts/${encodeURIComponent(accountId)}/storage/kv/namespaces/${encodeURIComponent(namespaceId)}` : null;
|
|
1703
|
+
const deleted = deleteCloudflareApiResource(path, { env, dryRun: false, name: namespaceId, type: "kv-namespace" });
|
|
1704
|
+
return { status: deleted.status, id: namespaceId, preview };
|
|
1698
1705
|
}
|
|
1699
1706
|
function deleteD1Database(tenantRoot, databaseName, { env, dryRun }) {
|
|
1700
1707
|
if (!databaseName) {
|
|
@@ -1703,18 +1710,12 @@ function deleteD1Database(tenantRoot, databaseName, { env, dryRun }) {
|
|
|
1703
1710
|
if (dryRun) {
|
|
1704
1711
|
return { status: "planned", name: databaseName };
|
|
1705
1712
|
}
|
|
1706
|
-
const
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
}
|
|
1712
|
-
const output = `${result.stdout ?? ""}
|
|
1713
|
-
${result.stderr ?? ""}`;
|
|
1714
|
-
if (result.status !== 0 && !looksLikeMissingResource(output)) {
|
|
1715
|
-
throw new Error(output.trim() || `Failed to delete D1 database ${databaseName}.`);
|
|
1716
|
-
}
|
|
1717
|
-
return { status: result.status === 0 ? "deleted" : "missing", name: databaseName };
|
|
1713
|
+
const accountId = env?.CLOUDFLARE_ACCOUNT_ID ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? "";
|
|
1714
|
+
const database = accountId ? listD1Databases(tenantRoot, env).find((entry) => entry?.name === databaseName) : null;
|
|
1715
|
+
const databaseId = database?.uuid ?? database?.id ?? null;
|
|
1716
|
+
const path = accountId && databaseId ? `/accounts/${encodeURIComponent(accountId)}/d1/database/${encodeURIComponent(databaseId)}` : null;
|
|
1717
|
+
const deleted = deleteCloudflareApiResource(path, { env, dryRun: false, name: databaseName, type: "d1-database" });
|
|
1718
|
+
return { status: deleted.status, name: databaseName, id: databaseId };
|
|
1718
1719
|
}
|
|
1719
1720
|
function deleteWorker(tenantRoot, workerName, { env, dryRun, force = false }) {
|
|
1720
1721
|
if (!workerName) {
|
|
@@ -1723,23 +1724,10 @@ function deleteWorker(tenantRoot, workerName, { env, dryRun, force = false }) {
|
|
|
1723
1724
|
if (dryRun) {
|
|
1724
1725
|
return { status: "planned", name: workerName };
|
|
1725
1726
|
}
|
|
1726
|
-
const
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
}
|
|
1730
|
-
const result = runWrangler(args, {
|
|
1731
|
-
cwd: tenantRoot,
|
|
1732
|
-
allowFailure: true,
|
|
1733
|
-
capture: true,
|
|
1734
|
-
env,
|
|
1735
|
-
input: "y\n"
|
|
1736
|
-
});
|
|
1737
|
-
const output = `${result.stdout ?? ""}
|
|
1738
|
-
${result.stderr ?? ""}`;
|
|
1739
|
-
if (result.status !== 0 && !looksLikeMissingResource(output)) {
|
|
1740
|
-
throw new Error(output.trim() || `Failed to delete Worker ${workerName}.`);
|
|
1741
|
-
}
|
|
1742
|
-
return { status: result.status === 0 ? "deleted" : "missing", name: workerName };
|
|
1727
|
+
const accountId = env?.CLOUDFLARE_ACCOUNT_ID ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? "";
|
|
1728
|
+
const path = accountId ? `/accounts/${encodeURIComponent(accountId)}/workers/services/${encodeURIComponent(workerName)}` : null;
|
|
1729
|
+
const deleted = deleteCloudflareApiResource(path, { env, dryRun: false, name: workerName, type: "worker" });
|
|
1730
|
+
return { status: deleted.status, name: workerName };
|
|
1743
1731
|
}
|
|
1744
1732
|
function resourceOperation(provider, type, name, status, extra = {}) {
|
|
1745
1733
|
return {
|
|
@@ -1768,7 +1756,7 @@ function formatCloudflareErrors(payload) {
|
|
|
1768
1756
|
}
|
|
1769
1757
|
function deleteQueueByName(tenantRoot, queue, { env, dryRun }) {
|
|
1770
1758
|
const name = queueName(queue) ?? queue?.name ?? null;
|
|
1771
|
-
|
|
1759
|
+
let id = queueId(queue);
|
|
1772
1760
|
if (!name) {
|
|
1773
1761
|
return resourceOperation("cloudflare", "queue", name, "missing");
|
|
1774
1762
|
}
|
|
@@ -1776,6 +1764,10 @@ function deleteQueueByName(tenantRoot, queue, { env, dryRun }) {
|
|
|
1776
1764
|
return resourceOperation("cloudflare", "queue", name, "planned", { id });
|
|
1777
1765
|
}
|
|
1778
1766
|
const accountId = env?.CLOUDFLARE_ACCOUNT_ID ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? "";
|
|
1767
|
+
if (!id && accountId) {
|
|
1768
|
+
const live = listQueues(tenantRoot, env).find((entry) => queueName(entry) === name);
|
|
1769
|
+
id = queueId(live);
|
|
1770
|
+
}
|
|
1779
1771
|
const path = id ? `/accounts/${encodeURIComponent(accountId)}/queues/${encodeURIComponent(id)}` : null;
|
|
1780
1772
|
if (path) {
|
|
1781
1773
|
const deleted = deleteCloudflareApiResource(path, { env, dryRun: false, name, type: "queue" });
|
|
@@ -1783,19 +1775,10 @@ function deleteQueueByName(tenantRoot, queue, { env, dryRun }) {
|
|
|
1783
1775
|
return { ...deleted, id };
|
|
1784
1776
|
}
|
|
1785
1777
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
allowFailure: true,
|
|
1789
|
-
capture: true,
|
|
1790
|
-
env,
|
|
1791
|
-
input: "y\n"
|
|
1792
|
-
});
|
|
1793
|
-
const output = `${result.stdout ?? ""}
|
|
1794
|
-
${result.stderr ?? ""}`;
|
|
1795
|
-
if (result.status !== 0 && !looksLikeMissingResource(output)) {
|
|
1796
|
-
throw new Error(output.trim() || `Failed to delete queue ${name}.`);
|
|
1778
|
+
if (accountId) {
|
|
1779
|
+
return resourceOperation("cloudflare", "queue", name, "missing", { id });
|
|
1797
1780
|
}
|
|
1798
|
-
|
|
1781
|
+
throw new Error(`Failed to delete queue ${name}: CLOUDFLARE_ACCOUNT_ID is not configured.`);
|
|
1799
1782
|
}
|
|
1800
1783
|
function isLegacyTreeseedQueueName(name, scope) {
|
|
1801
1784
|
if (!name || !scope) {
|
|
@@ -1827,19 +1810,10 @@ function deleteR2Bucket(tenantRoot, bucketName, { env, dryRun, deleteData }) {
|
|
|
1827
1810
|
return resourceOperation("cloudflare", "r2-bucket", bucketName, "planned");
|
|
1828
1811
|
}
|
|
1829
1812
|
const drained = drainR2Bucket(bucketName, { env });
|
|
1830
|
-
const
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
env,
|
|
1835
|
-
input: "y\n"
|
|
1836
|
-
});
|
|
1837
|
-
const output = `${result.stdout ?? ""}
|
|
1838
|
-
${result.stderr ?? ""}`;
|
|
1839
|
-
if (result.status !== 0 && !looksLikeMissingResource(output)) {
|
|
1840
|
-
throw new Error(output.trim() || `Failed to delete R2 bucket ${bucketName}.`);
|
|
1841
|
-
}
|
|
1842
|
-
return resourceOperation("cloudflare", "r2-bucket", bucketName, result.status === 0 ? "deleted" : "missing", drained);
|
|
1813
|
+
const accountId = env?.CLOUDFLARE_ACCOUNT_ID ?? process.env.CLOUDFLARE_ACCOUNT_ID ?? "";
|
|
1814
|
+
const path = accountId ? `/accounts/${encodeURIComponent(accountId)}/r2/buckets/${encodeURIComponent(bucketName)}` : null;
|
|
1815
|
+
const deleted = deleteCloudflareApiResource(path, { env, dryRun: false, name: bucketName, type: "r2-bucket" });
|
|
1816
|
+
return resourceOperation("cloudflare", "r2-bucket", bucketName, deleted.status, drained);
|
|
1843
1817
|
}
|
|
1844
1818
|
function r2ObjectKey(entry) {
|
|
1845
1819
|
return typeof entry?.key === "string" ? entry.key : typeof entry?.name === "string" ? entry.name : "";
|
|
@@ -2408,7 +2382,7 @@ async function destroyTreeseedEnvironmentResources(tenantRoot, options = {}) {
|
|
|
2408
2382
|
const force = options.force ?? false;
|
|
2409
2383
|
const kvNamespaces = dryRun ? [] : listKvNamespaces(tenantRoot, env);
|
|
2410
2384
|
const d1Databases = dryRun ? [] : listD1Databases(tenantRoot, env);
|
|
2411
|
-
const queues = listQueues(tenantRoot, env);
|
|
2385
|
+
const queues = dryRun ? [] : listQueues(tenantRoot, env);
|
|
2412
2386
|
const buckets = dryRun ? [] : listR2Buckets(tenantRoot, env);
|
|
2413
2387
|
const pagesProjects = dryRun ? [] : listPagesProjects(tenantRoot, env);
|
|
2414
2388
|
state.kvNamespaces.FORM_GUARD_KV.id = resolveExistingKvIdByName(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { request as httpsRequest } from "node:https";
|
|
1
2
|
const DEFAULT_RAILWAY_API_URL = "https://backboard.railway.com/graphql/v2";
|
|
2
3
|
const DEFAULT_RAILWAY_WORKSPACE = "knowledge-coop";
|
|
3
4
|
const RAILWAY_POSTGRES_TEMPLATE_ID = "b55da7dc-09be-4140-bc65-1284d15d349c";
|
|
@@ -295,7 +296,7 @@ async function railwayGraphqlRequest({
|
|
|
295
296
|
const controller = new AbortController();
|
|
296
297
|
let timer = null;
|
|
297
298
|
try {
|
|
298
|
-
const response = await Promise.race([
|
|
299
|
+
const response = fetchImpl === fetch ? await railwayGraphqlHttpsRequest(apiUrl || resolveRailwayApiUrl(env), token, { query, variables }, timeoutMs) : await Promise.race([
|
|
299
300
|
fetchImpl(apiUrl || resolveRailwayApiUrl(env), {
|
|
300
301
|
method: "POST",
|
|
301
302
|
headers: {
|
|
@@ -304,7 +305,12 @@ async function railwayGraphqlRequest({
|
|
|
304
305
|
},
|
|
305
306
|
body: JSON.stringify({ query, variables }),
|
|
306
307
|
signal: controller.signal
|
|
307
|
-
})
|
|
308
|
+
}).then(async (fetchResponse) => ({
|
|
309
|
+
ok: fetchResponse.ok,
|
|
310
|
+
status: fetchResponse.status,
|
|
311
|
+
payload: await fetchResponse.json().catch(() => ({})),
|
|
312
|
+
retryAfter: fetchResponse.headers.get("retry-after")
|
|
313
|
+
})),
|
|
308
314
|
new Promise((_, reject) => {
|
|
309
315
|
timer = setTimeout(() => {
|
|
310
316
|
controller.abort();
|
|
@@ -312,11 +318,11 @@ async function railwayGraphqlRequest({
|
|
|
312
318
|
}, timeoutMs);
|
|
313
319
|
})
|
|
314
320
|
]);
|
|
315
|
-
const payload =
|
|
321
|
+
const payload = response.payload;
|
|
316
322
|
if (!response.ok || Array.isArray(payload.errors) && payload.errors.length > 0) {
|
|
317
323
|
const message = normalizeRailwayErrorMessage(payload, response.status);
|
|
318
324
|
const hasGraphqlErrors = Array.isArray(payload.errors) && payload.errors.length > 0;
|
|
319
|
-
const retryAfterMs = parseRetryAfterMs(response.
|
|
325
|
+
const retryAfterMs = parseRetryAfterMs(response.retryAfter);
|
|
320
326
|
const shouldRetry = isRetryableRailwayStatus(response.status) || /rate limit|too many requests/iu.test(message);
|
|
321
327
|
const error = new Error(message);
|
|
322
328
|
if (shouldRetry || hasGraphqlErrors && /rate limit|too many requests/iu.test(message)) {
|
|
@@ -340,6 +346,47 @@ async function railwayGraphqlRequest({
|
|
|
340
346
|
}
|
|
341
347
|
}
|
|
342
348
|
}
|
|
349
|
+
async function railwayGraphqlHttpsRequest(url, token, body, timeoutMs) {
|
|
350
|
+
const rawBody = JSON.stringify(body);
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
const req = httpsRequest(url, {
|
|
353
|
+
method: "POST",
|
|
354
|
+
headers: {
|
|
355
|
+
authorization: `Bearer ${token}`,
|
|
356
|
+
"content-type": "application/json",
|
|
357
|
+
"content-length": Buffer.byteLength(rawBody)
|
|
358
|
+
},
|
|
359
|
+
timeout: timeoutMs
|
|
360
|
+
}, (res) => {
|
|
361
|
+
const chunks = [];
|
|
362
|
+
res.setEncoding("utf8");
|
|
363
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
364
|
+
res.on("end", () => {
|
|
365
|
+
const text = chunks.join("");
|
|
366
|
+
let payload = {};
|
|
367
|
+
try {
|
|
368
|
+
payload = text ? JSON.parse(text) : {};
|
|
369
|
+
} catch {
|
|
370
|
+
payload = {};
|
|
371
|
+
}
|
|
372
|
+
const status = res.statusCode ?? 0;
|
|
373
|
+
const retryAfterHeader = res.headers["retry-after"];
|
|
374
|
+
resolve({
|
|
375
|
+
ok: status >= 200 && status < 300,
|
|
376
|
+
status,
|
|
377
|
+
payload,
|
|
378
|
+
retryAfter: Array.isArray(retryAfterHeader) ? retryAfterHeader[0] ?? null : retryAfterHeader ?? null
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
req.on("timeout", () => {
|
|
383
|
+
req.destroy(markRailwayTransientError(new Error(`Railway API request timed out after ${timeoutMs}ms.`)));
|
|
384
|
+
});
|
|
385
|
+
req.on("error", reject);
|
|
386
|
+
req.write(rawBody);
|
|
387
|
+
req.end();
|
|
388
|
+
});
|
|
389
|
+
}
|
|
343
390
|
async function getRailwayAuthProfile({
|
|
344
391
|
env = process.env,
|
|
345
392
|
fetchImpl = fetch
|
|
@@ -839,13 +886,13 @@ async function ensureRailwayServiceInstanceConfiguration({
|
|
|
839
886
|
runtimeMode,
|
|
840
887
|
env = process.env,
|
|
841
888
|
fetchImpl = fetch,
|
|
842
|
-
settleAttempts =
|
|
889
|
+
settleAttempts = 60,
|
|
843
890
|
settleDelayMs = 5e3
|
|
844
891
|
}) {
|
|
845
892
|
let current = await getRailwayServiceInstance({ serviceId, environmentId, env, fetchImpl });
|
|
846
893
|
if (!current.id) {
|
|
847
|
-
for (let attempt = 0; attempt <
|
|
848
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
894
|
+
for (let attempt = 0; attempt < settleAttempts && !current.id; attempt += 1) {
|
|
895
|
+
await new Promise((resolve) => setTimeout(resolve, settleDelayMs));
|
|
849
896
|
current = await getRailwayServiceInstance({ serviceId, environmentId, env, fetchImpl });
|
|
850
897
|
}
|
|
851
898
|
}
|
|
@@ -2133,7 +2133,8 @@ async function verifyRailwayUnit(input) {
|
|
|
2133
2133
|
const topology = await resolveRailwayTopologyForScope(input, scope, {
|
|
2134
2134
|
serviceKeys: [serviceKey],
|
|
2135
2135
|
includeInstances: true,
|
|
2136
|
-
includeVariables: true
|
|
2136
|
+
includeVariables: true,
|
|
2137
|
+
refresh: true
|
|
2137
2138
|
});
|
|
2138
2139
|
const entry = topology.services.get(serviceKey) ?? null;
|
|
2139
2140
|
const service = entry?.configuredService ?? null;
|
|
@@ -408,7 +408,7 @@ export declare function workflowSave(helpers: WorkflowOperationHelpers, input: T
|
|
|
408
408
|
};
|
|
409
409
|
ciMode: "hosted" | "off";
|
|
410
410
|
verifyMode: "action-first" | "local-only" | import("../workflow.ts").TreeseedWorkflowVerifyMode;
|
|
411
|
-
workflowGates: Record<string, unknown>
|
|
411
|
+
workflowGates: (Record<string, unknown> | {
|
|
412
412
|
name: string;
|
|
413
413
|
repository: string | null;
|
|
414
414
|
workflow: string;
|
|
@@ -423,7 +423,7 @@ export declare function workflowSave(helpers: WorkflowOperationHelpers, input: T
|
|
|
423
423
|
updatedAt: null;
|
|
424
424
|
timeoutSeconds: number | null;
|
|
425
425
|
cached: boolean;
|
|
426
|
-
}[];
|
|
426
|
+
})[];
|
|
427
427
|
releaseCandidate: ReleaseCandidateReport | null;
|
|
428
428
|
hostingAudit: import("../workflow-support.ts").TreeseedHostingAuditReport | null;
|
|
429
429
|
} & {
|
|
@@ -551,7 +551,7 @@ export declare function workflowClose(helpers: WorkflowOperationHelpers, input:
|
|
|
551
551
|
};
|
|
552
552
|
ciMode: "hosted" | "off";
|
|
553
553
|
verifyMode: "action-first" | "local-only" | import("../workflow.ts").TreeseedWorkflowVerifyMode;
|
|
554
|
-
workflowGates: Record<string, unknown>
|
|
554
|
+
workflowGates: (Record<string, unknown> | {
|
|
555
555
|
name: string;
|
|
556
556
|
repository: string | null;
|
|
557
557
|
workflow: string;
|
|
@@ -566,7 +566,7 @@ export declare function workflowClose(helpers: WorkflowOperationHelpers, input:
|
|
|
566
566
|
updatedAt: null;
|
|
567
567
|
timeoutSeconds: number | null;
|
|
568
568
|
cached: boolean;
|
|
569
|
-
}[];
|
|
569
|
+
})[];
|
|
570
570
|
releaseCandidate: ReleaseCandidateReport | null;
|
|
571
571
|
hostingAudit: import("../workflow-support.ts").TreeseedHostingAuditReport | null;
|
|
572
572
|
} & {
|
|
@@ -735,7 +735,7 @@ export declare function workflowStage(helpers: WorkflowOperationHelpers, input:
|
|
|
735
735
|
};
|
|
736
736
|
ciMode: "hosted" | "off";
|
|
737
737
|
verifyMode: "action-first" | "local-only" | import("../workflow.ts").TreeseedWorkflowVerifyMode;
|
|
738
|
-
workflowGates: Record<string, unknown>
|
|
738
|
+
workflowGates: (Record<string, unknown> | {
|
|
739
739
|
name: string;
|
|
740
740
|
repository: string | null;
|
|
741
741
|
workflow: string;
|
|
@@ -750,7 +750,7 @@ export declare function workflowStage(helpers: WorkflowOperationHelpers, input:
|
|
|
750
750
|
updatedAt: null;
|
|
751
751
|
timeoutSeconds: number | null;
|
|
752
752
|
cached: boolean;
|
|
753
|
-
}[];
|
|
753
|
+
})[];
|
|
754
754
|
releaseCandidate: ReleaseCandidateReport | null;
|
|
755
755
|
hostingAudit: import("../workflow-support.ts").TreeseedHostingAuditReport | null;
|
|
756
756
|
} & {
|
|
@@ -3134,7 +3134,7 @@ async function workflowSave(helpers, input) {
|
|
|
3134
3134
|
const saveWorkflowGates = shouldUseHostedSaveCi(effectiveInput, branch) ? await executeJournalStep(root, workflowRun.runId, "hosted-ci", async () => {
|
|
3135
3135
|
if (branch === STAGING_BRANCH) {
|
|
3136
3136
|
const workflowGates = saveResult?.workflowGates ?? [];
|
|
3137
|
-
if (
|
|
3137
|
+
if (effectiveInput.verifyDeployedResources !== true || scope === "local" || !savedRootRepo.commitSha) {
|
|
3138
3138
|
return { workflowGates };
|
|
3139
3139
|
}
|
|
3140
3140
|
helpers.write("[save][workflow] Dispatching hosted market deploy gate for deployed resource verification.");
|
|
@@ -3163,7 +3163,12 @@ async function workflowSave(helpers, input) {
|
|
|
3163
3163
|
runId: workflowRun.runId,
|
|
3164
3164
|
onProgress: (line, stream) => helpers.write(line, stream)
|
|
3165
3165
|
});
|
|
3166
|
-
return {
|
|
3166
|
+
return {
|
|
3167
|
+
workflowGates: [
|
|
3168
|
+
...workflowGates.filter((gate) => !(gate.repository === repository && gate.workflow === "deploy.yml")),
|
|
3169
|
+
...dispatchedGates
|
|
3170
|
+
]
|
|
3171
|
+
};
|
|
3167
3172
|
}
|
|
3168
3173
|
helpers.write("[save][workflow] Waiting for hosted save workflow gates.");
|
|
3169
3174
|
return waitForWorkflowGates("save", [
|