@qawolf/ci-sdk 2.2.0 → 2.6.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/README.md +24 -0
- package/dist/index.cjs +396 -202
- package/dist/index.cjs.map +7 -1
- package/dist/index.d.ts +4 -557
- package/dist/index.js +371 -200
- package/dist/index.js.map +7 -1
- package/dist/lib/api/ci-greenlight-bug-data.d.ts +67 -0
- package/dist/lib/api/ci-greenlight.d.ts +76 -0
- package/dist/lib/api/generate-signed-url-for-run-inputs-executables.d.ts +4 -0
- package/dist/lib/api/generate-signed-url-for-team-storage.d.ts +4 -0
- package/dist/lib/api/index.d.ts +2 -0
- package/dist/lib/api/log.d.ts +6 -0
- package/dist/lib/api/signed-url.d.ts +11 -0
- package/dist/lib/api-types.d.ts +5 -0
- package/dist/lib/other.d.ts +5 -0
- package/dist/lib/sdk/defaults/fetch.d.ts +1 -0
- package/dist/lib/sdk/defaults/log.d.ts +2 -0
- package/dist/lib/sdk/defaults/serviceBase.d.ts +1 -0
- package/dist/lib/sdk/defaults/userAgent.d.ts +1 -0
- package/dist/lib/sdk/dependencies.d.ts +7 -0
- package/dist/lib/sdk/domain/attemptDeploy/deployConfig.d.ts +37 -0
- package/dist/lib/sdk/domain/attemptDeploy/deploySuccessWireResponse.d.ts +39 -0
- package/dist/lib/sdk/domain/attemptDeploy/handleSuccessResponse.d.ts +3 -0
- package/dist/lib/sdk/domain/attemptDeploy/index.d.ts +4 -0
- package/dist/lib/sdk/domain/attemptDeploy/mapDeploySuccessResponse.d.ts +3 -0
- package/dist/lib/sdk/domain/attemptDeploy/parseDeploySuccessWireResponse.d.ts +2 -0
- package/dist/lib/sdk/domain/attemptDeploy/types.d.ts +129 -0
- package/dist/lib/sdk/domain/generateSignedUrls/generate-signed-url-for-run-inputs-executables.d.ts +4 -0
- package/dist/lib/sdk/domain/generateSignedUrls/generate-signed-url-for-team-storage.d.ts +16 -0
- package/dist/lib/sdk/domain/generateSignedUrls/types.d.ts +28 -0
- package/dist/lib/sdk/domain/notifyTerminatedEphemeralEnvironment/index.d.ts +4 -0
- package/dist/lib/sdk/domain/notifyTerminatedEphemeralEnvironment/types.d.ts +48 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/buildCompletedRunResult.d.ts +8 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/consts.d.ts +7 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/index.d.ts +4 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/iterator.d.ts +43 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/logging.d.ts +27 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/mapIteratorAbortToGreenlightStatus.d.ts +7 -0
- package/dist/lib/sdk/domain/pollCiGreenlight/types.d.ts +156 -0
- package/dist/lib/sdk/index.d.ts +26 -0
- package/package.json +8 -7
- package/dist/index.d.cts +0 -557
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/* Built with @qawolf/platform-builder@1.2.2 */
|
|
2
|
+
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/index.ts
|
|
23
|
+
var index_exports = {};
|
|
24
|
+
__export(index_exports, {
|
|
25
|
+
makeQaWolfSdk: () => makeQaWolfSdk
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
5
28
|
|
|
6
29
|
// src/lib/other.ts
|
|
7
30
|
function sleep(ms) {
|
|
@@ -14,10 +37,7 @@ function pluralize(count) {
|
|
|
14
37
|
__name(pluralize, "pluralize");
|
|
15
38
|
var buildFetchWithTimeout = /* @__PURE__ */ __name((fetch, defaultTimeoutMs) => async (...args) => {
|
|
16
39
|
const signal = args[1]?.signal ?? AbortSignal.timeout(defaultTimeoutMs);
|
|
17
|
-
return fetch(args[0], {
|
|
18
|
-
...args[1],
|
|
19
|
-
signal
|
|
20
|
-
});
|
|
40
|
+
return fetch(args[0], { ...args[1], signal });
|
|
21
41
|
}, "buildFetchWithTimeout");
|
|
22
42
|
|
|
23
43
|
// src/lib/sdk/defaults/fetch.ts
|
|
@@ -41,13 +61,61 @@ var defaultServiceBase = "https://app.qawolf.com/";
|
|
|
41
61
|
|
|
42
62
|
// package.json
|
|
43
63
|
var package_default = {
|
|
44
|
-
|
|
64
|
+
name: "@qawolf/ci-sdk",
|
|
65
|
+
version: "2.6.0",
|
|
66
|
+
private: false,
|
|
67
|
+
description: "A simple SDK for interacting with QAWolf in CI scripts.",
|
|
68
|
+
keywords: [],
|
|
69
|
+
license: "MIT",
|
|
70
|
+
author: "Jules Sam. Randolph<jules@qawolf.com>",
|
|
71
|
+
files: [
|
|
72
|
+
"/dist",
|
|
73
|
+
"/README.md"
|
|
74
|
+
],
|
|
75
|
+
type: "module",
|
|
76
|
+
sideEffects: false,
|
|
77
|
+
exports: {
|
|
78
|
+
".": {
|
|
79
|
+
types: "./dist/index.d.ts",
|
|
80
|
+
require: "./dist/index.cjs",
|
|
81
|
+
import: "./dist/index.js",
|
|
82
|
+
default: "./dist/index.js"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
scripts: {
|
|
86
|
+
build: "platform-builder --config platformBuilder.config.ts --config platformBuilder.cjs.config.ts",
|
|
87
|
+
"lint:ci": "npm run lint:first-half; FIRST_HALF_EXIT=$?; npm run lint:second-half && exit $FIRST_HALF_EXIT",
|
|
88
|
+
"lint:dev": "npm run lint:first-half",
|
|
89
|
+
"lint:first-half": "eslint . --fix --quiet && oxfmt --write .",
|
|
90
|
+
"lint:second-half": "dpdm --exit-code circular:1 --no-tree --no-warning --transform --include='.*' --exclude='/(dist|node_modules)/' '**/*'",
|
|
91
|
+
prepublishOnly: "nx run ci-sdk:build",
|
|
92
|
+
test: 'NODE_OPTIONS="--experimental-vm-modules" NODE_NO_WARNINGS=1 jest',
|
|
93
|
+
"tsc:check": "tsc --noEmit"
|
|
94
|
+
},
|
|
95
|
+
dependencies: {
|
|
96
|
+
"@qawolf/ci-utils": "^1.1.2",
|
|
97
|
+
"@sinonjs/fake-timers": "^10.3.0",
|
|
98
|
+
tslib: "^2.6.2"
|
|
99
|
+
},
|
|
100
|
+
devDependencies: {
|
|
101
|
+
"@qawolf/platform-builder": "^1.2.2",
|
|
102
|
+
tsx: "^4.19.4",
|
|
103
|
+
typescript: "^5.9.3"
|
|
104
|
+
},
|
|
105
|
+
engines: {
|
|
106
|
+
node: ">=20"
|
|
107
|
+
}
|
|
108
|
+
};
|
|
45
109
|
|
|
46
110
|
// src/lib/sdk/defaults/userAgent.ts
|
|
47
111
|
var defaultUserAgent = `ci-sdk/${package_default.version}`;
|
|
48
112
|
|
|
49
113
|
// src/lib/api/log.ts
|
|
50
|
-
async function logFetchError({
|
|
114
|
+
async function logFetchError({
|
|
115
|
+
log,
|
|
116
|
+
methodName,
|
|
117
|
+
response
|
|
118
|
+
}) {
|
|
51
119
|
if (response.ok) return;
|
|
52
120
|
const { eventId, failureMessage } = await (async () => {
|
|
53
121
|
try {
|
|
@@ -72,7 +140,9 @@ async function logFetchError({ log, methodName, response }) {
|
|
|
72
140
|
const eventIdSuffix = eventId ? ` (Event ID: ${eventId})` : "";
|
|
73
141
|
const messageSuffix = failureMessage ? `: ${failureMessage}` : "";
|
|
74
142
|
const statusText = response.status >= 500 ? "Server Error" : response.statusText || "Unknown Error";
|
|
75
|
-
log.error(
|
|
143
|
+
log.error(
|
|
144
|
+
`\u274C [${methodName}] ${response.status} ${statusText}${eventIdSuffix}${messageSuffix}`
|
|
145
|
+
);
|
|
76
146
|
}
|
|
77
147
|
__name(logFetchError, "logFetchError");
|
|
78
148
|
|
|
@@ -82,6 +152,7 @@ async function handleSuccessResponse(data, log) {
|
|
|
82
152
|
const skippedTriggers = data.skippedTriggers ?? [];
|
|
83
153
|
const skippedDeployment = data.skippedDeployment;
|
|
84
154
|
const isPreviewDeployment = environment && !environment.isStatic;
|
|
155
|
+
if (data.warning) log.warn(`\u26A0\uFE0F ${data.warning}`);
|
|
85
156
|
if (environment) {
|
|
86
157
|
const logPrefix = environment.isStatic ? "Static environment" : "Preview environment";
|
|
87
158
|
log.info(`${logPrefix}: ${environment.alias} (id: ${environment.id})`);
|
|
@@ -89,13 +160,13 @@ async function handleSuccessResponse(data, log) {
|
|
|
89
160
|
if (results.length === 0) {
|
|
90
161
|
const skipMessages = [
|
|
91
162
|
...skippedTriggers.map((trigger) => trigger.message),
|
|
92
|
-
...skippedDeployment ? [
|
|
93
|
-
skippedDeployment.message
|
|
94
|
-
] : []
|
|
163
|
+
...skippedDeployment ? [skippedDeployment.message] : []
|
|
95
164
|
];
|
|
96
165
|
const skipDetail = skipMessages.length > 0 ? ` ${skipMessages.join(" ")}` : "";
|
|
97
166
|
if (isPreviewDeployment) {
|
|
98
|
-
log.info(
|
|
167
|
+
log.info(
|
|
168
|
+
`\u2705 Deployment notification was successful. No run was created for this deployment.${skipDetail}`
|
|
169
|
+
);
|
|
99
170
|
return {
|
|
100
171
|
environmentId: environment.id,
|
|
101
172
|
outcome: "success",
|
|
@@ -110,7 +181,9 @@ async function handleSuccessResponse(data, log) {
|
|
|
110
181
|
skippedTriggers
|
|
111
182
|
};
|
|
112
183
|
}
|
|
113
|
-
log.warn(
|
|
184
|
+
log.warn(
|
|
185
|
+
skippedDeployment ? `\u26A0\uFE0F No run was created for this deployment.${skipDetail}` : `\u26A0\uFE0F No trigger matched the request. Please make sure there is at least one active test in the QA Wolf environment, or contact support.`
|
|
186
|
+
);
|
|
114
187
|
return {
|
|
115
188
|
outcome: "skipped",
|
|
116
189
|
skippedDeployment
|
|
@@ -118,45 +191,43 @@ async function handleSuccessResponse(data, log) {
|
|
|
118
191
|
}
|
|
119
192
|
if (!environment) {
|
|
120
193
|
log.error(`\u{1F6AB} No environment matched the request. Please contact support.`);
|
|
121
|
-
return {
|
|
122
|
-
failReason: "no-environment",
|
|
123
|
-
outcome: "failed"
|
|
124
|
-
};
|
|
194
|
+
return { failReason: "no-environment", outcome: "failed" };
|
|
125
195
|
}
|
|
126
196
|
const unrecognizedResult = results.find((result) => "unrecognized" in result);
|
|
127
197
|
if (unrecognizedResult) {
|
|
128
|
-
log.error(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
};
|
|
198
|
+
log.error(
|
|
199
|
+
`\u{1F6AB} The deployment response contained an unrecognized result. Please upgrade @qawolf/ci-sdk.`
|
|
200
|
+
);
|
|
201
|
+
return { failReason: "unknown-result", outcome: "failed" };
|
|
133
202
|
}
|
|
134
203
|
const failedTrigger = results.find((result) => "failureReason" in result);
|
|
135
204
|
if (failedTrigger) {
|
|
136
|
-
log.error(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
};
|
|
205
|
+
log.error(
|
|
206
|
+
`\u{1F6AB} Run could not be created. Reason: "${failedTrigger.failureMessage ?? failedTrigger.failureReason}". Please contact support.`
|
|
207
|
+
);
|
|
208
|
+
return { failReason: "run-could-not-be-created", outcome: "failed" };
|
|
141
209
|
}
|
|
142
210
|
const duplicateSuite = results.find((result) => "duplicateSuiteId" in result);
|
|
143
211
|
if (duplicateSuite) {
|
|
144
|
-
log.info(
|
|
212
|
+
log.info(
|
|
213
|
+
`\u2705 Deployment notification was successful. Previous run ID: ${duplicateSuite.duplicateSuiteId} already exists for this deployment.`
|
|
214
|
+
);
|
|
145
215
|
return {
|
|
146
216
|
environmentId: environment.id,
|
|
147
217
|
outcome: "success",
|
|
148
218
|
runId: duplicateSuite.duplicateSuiteId
|
|
149
219
|
};
|
|
150
220
|
}
|
|
151
|
-
const successfulTrigger = results.find(
|
|
221
|
+
const successfulTrigger = results.find(
|
|
222
|
+
(result) => "createdSuiteId" in result
|
|
223
|
+
);
|
|
152
224
|
if (!successfulTrigger) {
|
|
153
225
|
log.error(`\u{1F6AB} Run could not be created. Please contact support.`);
|
|
154
|
-
return {
|
|
155
|
-
failReason: "run-could-not-be-created",
|
|
156
|
-
outcome: "failed"
|
|
157
|
-
};
|
|
226
|
+
return { failReason: "run-could-not-be-created", outcome: "failed" };
|
|
158
227
|
}
|
|
159
|
-
log.info(
|
|
228
|
+
log.info(
|
|
229
|
+
`\u2705 Deployment notification was successful. Run created with ID: ${successfulTrigger.createdSuiteId}`
|
|
230
|
+
);
|
|
160
231
|
return {
|
|
161
232
|
environmentId: environment.id,
|
|
162
233
|
outcome: "success",
|
|
@@ -167,29 +238,28 @@ __name(handleSuccessResponse, "handleSuccessResponse");
|
|
|
167
238
|
|
|
168
239
|
// src/lib/sdk/domain/attemptDeploy/mapDeploySuccessResponse.ts
|
|
169
240
|
function mapSuiteResult(result) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
241
|
+
switch (result.outcome) {
|
|
242
|
+
case "created":
|
|
243
|
+
return {
|
|
244
|
+
createdSuiteId: result.created_suite_id,
|
|
245
|
+
triggerId: result.trigger_id
|
|
246
|
+
};
|
|
247
|
+
case "failed":
|
|
248
|
+
return {
|
|
249
|
+
failureCode: result.failure_code,
|
|
250
|
+
failureMessage: result.failure_message,
|
|
251
|
+
failureReason: result.failure_reason,
|
|
252
|
+
triggerId: result.trigger_id
|
|
253
|
+
};
|
|
254
|
+
case "skipped":
|
|
255
|
+
return {
|
|
256
|
+
duplicateSuiteId: result.duplicate_suite_id,
|
|
257
|
+
skipReason: result.skip_reason,
|
|
258
|
+
triggerId: result.trigger_id
|
|
259
|
+
};
|
|
260
|
+
default:
|
|
261
|
+
return { triggerId: result.trigger_id, unrecognized: true };
|
|
188
262
|
}
|
|
189
|
-
return {
|
|
190
|
-
triggerId: result.trigger_id,
|
|
191
|
-
unrecognized: true
|
|
192
|
-
};
|
|
193
263
|
}
|
|
194
264
|
__name(mapSuiteResult, "mapSuiteResult");
|
|
195
265
|
function mapDeploySuccessResponse(wire) {
|
|
@@ -205,7 +275,8 @@ function mapDeploySuccessResponse(wire) {
|
|
|
205
275
|
message: trigger.message,
|
|
206
276
|
reason: trigger.reason,
|
|
207
277
|
triggerId: trigger.trigger_id
|
|
208
|
-
}))
|
|
278
|
+
})),
|
|
279
|
+
warning: wire.warning
|
|
209
280
|
};
|
|
210
281
|
}
|
|
211
282
|
__name(mapDeploySuccessResponse, "mapDeploySuccessResponse");
|
|
@@ -215,22 +286,32 @@ function isRecord(value) {
|
|
|
215
286
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
216
287
|
}
|
|
217
288
|
__name(isRecord, "isRecord");
|
|
289
|
+
function isOptionalString(value) {
|
|
290
|
+
return value === void 0 || typeof value === "string";
|
|
291
|
+
}
|
|
292
|
+
__name(isOptionalString, "isOptionalString");
|
|
218
293
|
function isWireSuiteResult(value) {
|
|
219
294
|
if (!isRecord(value)) return false;
|
|
220
295
|
if (typeof value.trigger_id !== "string") return false;
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
296
|
+
if (!isOptionalString(value.outcome)) return false;
|
|
297
|
+
switch (value.outcome) {
|
|
298
|
+
case "created":
|
|
299
|
+
return typeof value.created_suite_id === "string";
|
|
300
|
+
case "failed":
|
|
301
|
+
return typeof value.failure_reason === "string" && isOptionalString(value.failure_code) && isOptionalString(value.failure_message);
|
|
302
|
+
case "skipped":
|
|
303
|
+
return typeof value.duplicate_suite_id === "string" && typeof value.skip_reason === "string";
|
|
304
|
+
default:
|
|
305
|
+
return true;
|
|
225
306
|
}
|
|
226
|
-
return true;
|
|
227
307
|
}
|
|
228
308
|
__name(isWireSuiteResult, "isWireSuiteResult");
|
|
229
309
|
function isEnvironment(value) {
|
|
230
310
|
if (!isRecord(value)) return false;
|
|
231
311
|
if (typeof value.id !== "string") return false;
|
|
232
312
|
if (typeof value.isStatic !== "boolean") return false;
|
|
233
|
-
if (value.alias !== void 0 && typeof value.alias !== "string")
|
|
313
|
+
if (value.alias !== void 0 && typeof value.alias !== "string")
|
|
314
|
+
return false;
|
|
234
315
|
return true;
|
|
235
316
|
}
|
|
236
317
|
__name(isEnvironment, "isEnvironment");
|
|
@@ -246,10 +327,15 @@ function isSkippedTrigger(value) {
|
|
|
246
327
|
__name(isSkippedTrigger, "isSkippedTrigger");
|
|
247
328
|
function isDeploySuccessWireResponse(value) {
|
|
248
329
|
if (!isRecord(value)) return false;
|
|
249
|
-
if (value.environment !== void 0 && !isEnvironment(value.environment))
|
|
250
|
-
|
|
251
|
-
if (value.
|
|
252
|
-
|
|
330
|
+
if (value.environment !== void 0 && !isEnvironment(value.environment))
|
|
331
|
+
return false;
|
|
332
|
+
if (!Array.isArray(value.results) || !value.results.every(isWireSuiteResult))
|
|
333
|
+
return false;
|
|
334
|
+
if (value.skipped_deployment !== void 0 && !isSkippedDeployment(value.skipped_deployment))
|
|
335
|
+
return false;
|
|
336
|
+
if (value.skipped_triggers !== void 0 && (!Array.isArray(value.skipped_triggers) || !value.skipped_triggers.every(isSkippedTrigger)))
|
|
337
|
+
return false;
|
|
338
|
+
if (!isOptionalString(value.warning)) return false;
|
|
253
339
|
return true;
|
|
254
340
|
}
|
|
255
341
|
__name(isDeploySuccessWireResponse, "isDeploySuccessWireResponse");
|
|
@@ -264,35 +350,38 @@ async function attemptNotifyDeploy(deps, apiConfig, config) {
|
|
|
264
350
|
let response;
|
|
265
351
|
let bodyText;
|
|
266
352
|
try {
|
|
267
|
-
response = await localFetch(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
353
|
+
response = await localFetch(
|
|
354
|
+
new URL("/api/webhooks/deploy_success", apiConfig.serviceBase),
|
|
355
|
+
{
|
|
356
|
+
body: JSON.stringify({
|
|
357
|
+
branch: config.branch,
|
|
358
|
+
commit_url: config.commitUrl,
|
|
359
|
+
deduplication_key: config.deduplicationKey,
|
|
360
|
+
deployment_type: config.deploymentType,
|
|
361
|
+
deployment_url: config.deploymentUrl,
|
|
362
|
+
..."ephemeralEnvironment" in config ? {
|
|
363
|
+
ephemeral_environment: config.ephemeralEnvironment
|
|
364
|
+
} : "hostingService" in config && {
|
|
365
|
+
hosting_service: config.hostingService,
|
|
366
|
+
merge_request_number: config.hostingService === "GitLab" ? config.mergeRequestNumber : void 0,
|
|
367
|
+
pull_request_number: config.hostingService === "GitHub" ? config.pullRequestNumber : void 0,
|
|
368
|
+
repository: config.repository
|
|
369
|
+
},
|
|
370
|
+
sha: config.sha,
|
|
371
|
+
variables: config.variables,
|
|
372
|
+
workspaceId: config.workspaceId
|
|
373
|
+
}),
|
|
374
|
+
headers: {
|
|
375
|
+
Authorization: `Bearer ${apiConfig.apiKey}`,
|
|
376
|
+
"Content-Type": "application/json",
|
|
377
|
+
"User-Agent": apiConfig.userAgent
|
|
281
378
|
},
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"Content-Type": "application/json",
|
|
289
|
-
"User-Agent": apiConfig.userAgent
|
|
290
|
-
},
|
|
291
|
-
method: "POST",
|
|
292
|
-
// Override default timeout to 5 minutes. This gives extra room
|
|
293
|
-
// for both (1) waiting for reconciliation (2) creating the run.
|
|
294
|
-
signal: AbortSignal.timeout(5 * 60 * 1e3)
|
|
295
|
-
});
|
|
379
|
+
method: "POST",
|
|
380
|
+
// Override default timeout to 5 minutes. This gives extra room
|
|
381
|
+
// for both (1) waiting for reconciliation (2) creating the run.
|
|
382
|
+
signal: AbortSignal.timeout(5 * 60 * 1e3)
|
|
383
|
+
}
|
|
384
|
+
);
|
|
296
385
|
if (!response.ok) return handleErrorResponse(response, log);
|
|
297
386
|
bodyText = await response.text();
|
|
298
387
|
} catch {
|
|
@@ -311,7 +400,10 @@ async function attemptNotifyDeploy(deps, apiConfig, config) {
|
|
|
311
400
|
}
|
|
312
401
|
const wire = parseDeploySuccessWireResponse(rawBody);
|
|
313
402
|
if (wire === "invalid") {
|
|
314
|
-
return abortInvalidResponseBody(
|
|
403
|
+
return abortInvalidResponseBody(
|
|
404
|
+
log,
|
|
405
|
+
"the response body did not match the expected shape"
|
|
406
|
+
);
|
|
315
407
|
}
|
|
316
408
|
const data = mapDeploySuccessResponse(wire);
|
|
317
409
|
return handleSuccessResponse(data, log);
|
|
@@ -352,10 +444,17 @@ var signedUrlPaths = {
|
|
|
352
444
|
runInputsExecutables: "/api/v0/run-inputs-executables-signed-urls",
|
|
353
445
|
teamStorage: "/api/v0/team-storage-signed-url"
|
|
354
446
|
};
|
|
355
|
-
function buildSignedUrl({
|
|
447
|
+
function buildSignedUrl({
|
|
448
|
+
destinationFilePath,
|
|
449
|
+
endpoint,
|
|
450
|
+
serviceBase,
|
|
451
|
+
workspaceId
|
|
452
|
+
}) {
|
|
356
453
|
const url = new URL(signedUrlPaths[endpoint], serviceBase);
|
|
357
|
-
if (destinationFilePath !== void 0)
|
|
358
|
-
|
|
454
|
+
if (destinationFilePath !== void 0)
|
|
455
|
+
url.searchParams.set("file", destinationFilePath);
|
|
456
|
+
if (workspaceId !== void 0)
|
|
457
|
+
url.searchParams.set("workspaceId", workspaceId);
|
|
359
458
|
return url;
|
|
360
459
|
}
|
|
361
460
|
__name(buildSignedUrl, "buildSignedUrl");
|
|
@@ -363,19 +462,22 @@ __name(buildSignedUrl, "buildSignedUrl");
|
|
|
363
462
|
// src/lib/api/generate-signed-url-for-run-inputs-executables.ts
|
|
364
463
|
async function callGenerateSignedUrlForRunInputsExecutablesStorage({ apiKey, serviceBase, userAgent }, { destinationFilePath, workspaceId }, { fetch: localFetch, log }) {
|
|
365
464
|
try {
|
|
366
|
-
const response = await localFetch(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
465
|
+
const response = await localFetch(
|
|
466
|
+
buildSignedUrl({
|
|
467
|
+
destinationFilePath,
|
|
468
|
+
endpoint: "runInputsExecutables",
|
|
469
|
+
serviceBase,
|
|
470
|
+
workspaceId
|
|
471
|
+
}),
|
|
472
|
+
{
|
|
473
|
+
headers: {
|
|
474
|
+
Authorization: `Bearer ${apiKey}`,
|
|
475
|
+
"Content-Type": "application/json",
|
|
476
|
+
"User-Agent": userAgent
|
|
477
|
+
},
|
|
478
|
+
method: "GET"
|
|
479
|
+
}
|
|
480
|
+
);
|
|
379
481
|
if (response.status === 200) {
|
|
380
482
|
const json = await response.json();
|
|
381
483
|
return {
|
|
@@ -416,18 +518,28 @@ async function generateSignedUrlForRunInputsExecutablesStorage(deps, apiConfig,
|
|
|
416
518
|
success: false
|
|
417
519
|
};
|
|
418
520
|
}
|
|
419
|
-
const responseState = await callGenerateSignedUrlForRunInputsExecutablesStorage(
|
|
521
|
+
const responseState = await callGenerateSignedUrlForRunInputsExecutablesStorage(
|
|
522
|
+
apiConfig,
|
|
523
|
+
config,
|
|
524
|
+
deps
|
|
525
|
+
);
|
|
420
526
|
if (!responseState.success) {
|
|
421
527
|
let abortReason = "XXX-other-http-code";
|
|
422
528
|
if (responseState.httpStatus >= 500) {
|
|
423
529
|
abortReason = "5XX-server-error";
|
|
424
|
-
log.error(
|
|
530
|
+
log.error(
|
|
531
|
+
`\u{1F6AB} Unrecoverable error (status ${responseState.httpStatus}) when generating signed upload url: aborting.`
|
|
532
|
+
);
|
|
425
533
|
} else {
|
|
426
534
|
if (responseState.httpStatus === 400) abortReason = "400-invalid-request";
|
|
427
|
-
else if (responseState.httpStatus === 401)
|
|
535
|
+
else if (responseState.httpStatus === 401)
|
|
536
|
+
abortReason = "401-invalid-credentials";
|
|
428
537
|
else if (responseState.httpStatus === 403) abortReason = "403-forbidden";
|
|
429
|
-
else if (responseState.httpStatus === 0)
|
|
430
|
-
|
|
538
|
+
else if (responseState.httpStatus === 0)
|
|
539
|
+
abortReason = "client-network-error";
|
|
540
|
+
log.error(
|
|
541
|
+
`\u{1F6AB} Unrecoverable error (status ${responseState.httpStatus}) when generating signed upload url: ${responseState.errorMessage ? `${responseState.errorMessage}.` : ""} aborting.`
|
|
542
|
+
);
|
|
431
543
|
}
|
|
432
544
|
return {
|
|
433
545
|
abortReason,
|
|
@@ -448,19 +560,22 @@ __name(generateSignedUrlForRunInputsExecutablesStorage, "generateSignedUrlForRun
|
|
|
448
560
|
// src/lib/api/generate-signed-url-for-team-storage.ts
|
|
449
561
|
async function callGenerateSignedUrlForTempTeamStorage({ apiKey, serviceBase, userAgent }, { destinationFilePath, workspaceId }, { fetch: localFetch, log }) {
|
|
450
562
|
try {
|
|
451
|
-
const response = await localFetch(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
563
|
+
const response = await localFetch(
|
|
564
|
+
buildSignedUrl({
|
|
565
|
+
destinationFilePath,
|
|
566
|
+
endpoint: "teamStorage",
|
|
567
|
+
serviceBase,
|
|
568
|
+
workspaceId
|
|
569
|
+
}),
|
|
570
|
+
{
|
|
571
|
+
headers: {
|
|
572
|
+
Authorization: `Bearer ${apiKey}`,
|
|
573
|
+
"Content-Type": "application/json",
|
|
574
|
+
"User-Agent": userAgent
|
|
575
|
+
},
|
|
576
|
+
method: "GET"
|
|
577
|
+
}
|
|
578
|
+
);
|
|
464
579
|
if (response.status === 200) {
|
|
465
580
|
const json = await response.json();
|
|
466
581
|
return {
|
|
@@ -501,18 +616,28 @@ async function generateSignedUrlForTempTeamStorage(deps, apiConfig, config) {
|
|
|
501
616
|
success: false
|
|
502
617
|
};
|
|
503
618
|
}
|
|
504
|
-
const responseState = await callGenerateSignedUrlForTempTeamStorage(
|
|
619
|
+
const responseState = await callGenerateSignedUrlForTempTeamStorage(
|
|
620
|
+
apiConfig,
|
|
621
|
+
config,
|
|
622
|
+
deps
|
|
623
|
+
);
|
|
505
624
|
if (!responseState.success) {
|
|
506
625
|
let abortReason = "XXX-other-http-code";
|
|
507
626
|
if (responseState.httpStatus >= 500) {
|
|
508
627
|
abortReason = "5XX-server-error";
|
|
509
|
-
log.error(
|
|
628
|
+
log.error(
|
|
629
|
+
`\u{1F6AB} Unrecoverable error (status ${responseState.httpStatus}) when generating signed upload url: aborting.`
|
|
630
|
+
);
|
|
510
631
|
} else {
|
|
511
632
|
if (responseState.httpStatus === 400) abortReason = "400-invalid-request";
|
|
512
|
-
else if (responseState.httpStatus === 401)
|
|
633
|
+
else if (responseState.httpStatus === 401)
|
|
634
|
+
abortReason = "401-invalid-credentials";
|
|
513
635
|
else if (responseState.httpStatus === 403) abortReason = "403-forbidden";
|
|
514
|
-
else if (responseState.httpStatus === 0)
|
|
515
|
-
|
|
636
|
+
else if (responseState.httpStatus === 0)
|
|
637
|
+
abortReason = "client-network-error";
|
|
638
|
+
log.error(
|
|
639
|
+
`\u{1F6AB} Unrecoverable error (status ${responseState.httpStatus}) when generating signed upload url: ${responseState.errorMessage ? `${responseState.errorMessage}.` : ""} aborting.`
|
|
640
|
+
);
|
|
516
641
|
}
|
|
517
642
|
return {
|
|
518
643
|
abortReason,
|
|
@@ -534,21 +659,22 @@ __name(generateSignedUrlForTempTeamStorage, "generateSignedUrlForTempTeamStorage
|
|
|
534
659
|
var notifyTerminatedEphemeralEnvironment = /* @__PURE__ */ __name(async (deps, apiConfig, config) => {
|
|
535
660
|
const { fetch: localFetch, log } = deps;
|
|
536
661
|
try {
|
|
537
|
-
const response = await localFetch(
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
662
|
+
const response = await localFetch(
|
|
663
|
+
new URL("/api/webhooks/environment_terminated", apiConfig.serviceBase),
|
|
664
|
+
{
|
|
665
|
+
body: JSON.stringify(config),
|
|
666
|
+
headers: {
|
|
667
|
+
Authorization: `Bearer ${apiConfig.apiKey}`,
|
|
668
|
+
"Content-Type": "application/json",
|
|
669
|
+
"User-Agent": apiConfig.userAgent
|
|
670
|
+
},
|
|
671
|
+
method: "POST"
|
|
672
|
+
}
|
|
673
|
+
);
|
|
546
674
|
if (!response.ok) return handleErrorResponse2(response, log);
|
|
547
|
-
const { environmentId } = await response.json();
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
outcome: "success"
|
|
551
|
-
};
|
|
675
|
+
const { environmentId, warning } = await response.json();
|
|
676
|
+
if (warning) log.warn(`\u26A0\uFE0F ${warning}`);
|
|
677
|
+
return { environmentId, outcome: "success" };
|
|
552
678
|
} catch {
|
|
553
679
|
log.error(`\u{1F6AB} Network error from terminate_preview_environment, aborting.`);
|
|
554
680
|
return {
|
|
@@ -581,14 +707,9 @@ __name(handleErrorResponse2, "handleErrorResponse");
|
|
|
581
707
|
|
|
582
708
|
// src/lib/sdk/domain/pollCiGreenlight/buildCompletedRunResult.ts
|
|
583
709
|
function buildCompletedRunResult(status) {
|
|
584
|
-
if (status.greenlight)
|
|
585
|
-
greenlightStatus: status,
|
|
586
|
-
|
|
587
|
-
};
|
|
588
|
-
else return {
|
|
589
|
-
greenlightStatus: status,
|
|
590
|
-
outcome: "failed"
|
|
591
|
-
};
|
|
710
|
+
if (status.greenlight)
|
|
711
|
+
return { greenlightStatus: status, outcome: "success" };
|
|
712
|
+
else return { greenlightStatus: status, outcome: "failed" };
|
|
592
713
|
}
|
|
593
714
|
__name(buildCompletedRunResult, "buildCompletedRunResult");
|
|
594
715
|
|
|
@@ -597,20 +718,32 @@ var pollCiGreenlightDefaults = {
|
|
|
597
718
|
abortOnSuperseded: false,
|
|
598
719
|
maxRetries: 10,
|
|
599
720
|
pollTimeout: 120 * 60 * 1e3,
|
|
721
|
+
// 2 hours
|
|
600
722
|
retryInterval: 10 * 1e3,
|
|
723
|
+
// 10 seconds
|
|
601
724
|
runInProgressInterval: 30 * 1e3,
|
|
725
|
+
// 30 seconds
|
|
602
726
|
runUnderReviewInterval: 60 * 1e3
|
|
727
|
+
// 60 seconds
|
|
603
728
|
};
|
|
604
729
|
|
|
605
730
|
// src/lib/api/ci-greenlight.ts
|
|
606
|
-
async function fetchCiGreenlightStatus({ apiKey, serviceBase, userAgent }, {
|
|
731
|
+
async function fetchCiGreenlightStatus({ apiKey, serviceBase, userAgent }, {
|
|
732
|
+
runId
|
|
733
|
+
}, { fetch: localFetch, log }) {
|
|
607
734
|
try {
|
|
608
|
-
const resp = await localFetch(
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
735
|
+
const resp = await localFetch(
|
|
736
|
+
new URL(
|
|
737
|
+
`/api/v0/ci-greenlight/${encodeURIComponent(runId)}`,
|
|
738
|
+
serviceBase
|
|
739
|
+
),
|
|
740
|
+
{
|
|
741
|
+
headers: {
|
|
742
|
+
Authorization: `Bearer ${apiKey}`,
|
|
743
|
+
"User-Agent": userAgent
|
|
744
|
+
}
|
|
612
745
|
}
|
|
613
|
-
|
|
746
|
+
);
|
|
614
747
|
if (resp.ok) {
|
|
615
748
|
const greenlightStatus = await resp.json();
|
|
616
749
|
return {
|
|
@@ -660,14 +793,22 @@ __name(fetchCiGreenlightStatus, "fetchCiGreenlightStatus");
|
|
|
660
793
|
// src/lib/sdk/domain/pollCiGreenlight/iterator.ts
|
|
661
794
|
async function* makePollCiGreenlightStatusIterator(deps, apiConfig, { runId, ...pollConfig }) {
|
|
662
795
|
const { log } = deps;
|
|
663
|
-
const {
|
|
796
|
+
const {
|
|
797
|
+
maxRetries = pollCiGreenlightDefaults.maxRetries,
|
|
798
|
+
pollTimeout = pollCiGreenlightDefaults.pollTimeout,
|
|
799
|
+
retryInterval = pollCiGreenlightDefaults.retryInterval,
|
|
800
|
+
runInProgressInterval = pollCiGreenlightDefaults.runInProgressInterval,
|
|
801
|
+
runUnderReviewInterval = pollCiGreenlightDefaults.runUnderReviewInterval
|
|
802
|
+
} = pollConfig;
|
|
664
803
|
let retries = 0;
|
|
665
804
|
let previousStatus = void 0;
|
|
666
805
|
const startedAt = Date.now();
|
|
667
806
|
while (Date.now() - startedAt <= pollTimeout) {
|
|
668
|
-
const responseState = await fetchCiGreenlightStatus(
|
|
669
|
-
|
|
670
|
-
|
|
807
|
+
const responseState = await fetchCiGreenlightStatus(
|
|
808
|
+
apiConfig,
|
|
809
|
+
{ runId },
|
|
810
|
+
deps
|
|
811
|
+
);
|
|
671
812
|
const elapsedMs = Date.now() - startedAt;
|
|
672
813
|
if (!responseState.ok && !responseState.canRetry) {
|
|
673
814
|
yield {
|
|
@@ -714,7 +855,8 @@ async function* makePollCiGreenlightStatusIterator(deps, apiConfig, { runId, ...
|
|
|
714
855
|
}
|
|
715
856
|
const retryLabel = `${httpStatus ? ` (status ${httpStatus})` : ""}, will try again... (${retries}/${maxRetries})`;
|
|
716
857
|
if (errorType === "network") log.warn(`\u274C Network error${retryLabel}`);
|
|
717
|
-
else if (errorType === "not-found")
|
|
858
|
+
else if (errorType === "not-found")
|
|
859
|
+
log.info(`\u23F3 Run not found${retryLabel}`);
|
|
718
860
|
else if (errorType === "server") log.warn(`\u274C Server error${retryLabel}`);
|
|
719
861
|
await sleep(retryInterval);
|
|
720
862
|
continue;
|
|
@@ -738,7 +880,9 @@ async function* makePollCiGreenlightStatusIterator(deps, apiConfig, { runId, ...
|
|
|
738
880
|
abortReason: "run-canceled",
|
|
739
881
|
elapsedMs,
|
|
740
882
|
httpStatus: void 0,
|
|
741
|
-
isAborted: true
|
|
883
|
+
isAborted: true,
|
|
884
|
+
message: greenlightStatus.message,
|
|
885
|
+
reason: greenlightStatus.reason
|
|
742
886
|
};
|
|
743
887
|
return;
|
|
744
888
|
}
|
|
@@ -751,7 +895,9 @@ async function* makePollCiGreenlightStatusIterator(deps, apiConfig, { runId, ...
|
|
|
751
895
|
await sleep(runUnderReviewInterval);
|
|
752
896
|
break;
|
|
753
897
|
default:
|
|
754
|
-
throw Error(
|
|
898
|
+
throw Error(
|
|
899
|
+
`Unexpected run stage: ${greenlightStatus}`
|
|
900
|
+
);
|
|
755
901
|
}
|
|
756
902
|
}
|
|
757
903
|
yield {
|
|
@@ -768,12 +914,19 @@ __name(makePollCiGreenlightStatusIterator, "makePollCiGreenlightStatusIterator")
|
|
|
768
914
|
function buildSuccessLogMessage(status) {
|
|
769
915
|
const { nonBlockingBugsCount, relevantRunUrl } = status;
|
|
770
916
|
const urlInfo = `See ${relevantRunUrl}`;
|
|
771
|
-
return `\u2705 Run passed and no blocking bugs found${nonBlockingBugsCount > 0 ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(
|
|
917
|
+
return `\u2705 Run passed and no blocking bugs found${nonBlockingBugsCount > 0 ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(
|
|
918
|
+
nonBlockingBugsCount
|
|
919
|
+
)} found` : ""}.
|
|
772
920
|
${urlInfo}`;
|
|
773
921
|
}
|
|
774
922
|
__name(buildSuccessLogMessage, "buildSuccessLogMessage");
|
|
775
923
|
function buildFailedLogMessage(status) {
|
|
776
|
-
const {
|
|
924
|
+
const {
|
|
925
|
+
blockingBugsCount,
|
|
926
|
+
nonBlockingBugsCount,
|
|
927
|
+
relevantRunWithBugsUrl,
|
|
928
|
+
reproducedBugs
|
|
929
|
+
} = status;
|
|
777
930
|
const blockingBugUrls = reproducedBugs.filter((bug) => bug.isBlocking).map((bug) => bug.applicationUrl);
|
|
778
931
|
const nonBlockingBugUrls = reproducedBugs.filter((bug) => !bug.isBlocking).map((bug) => bug.applicationUrl);
|
|
779
932
|
const blockingBugList = blockingBugUrls.map((url) => `
|
|
@@ -783,7 +936,11 @@ function buildFailedLogMessage(status) {
|
|
|
783
936
|
const bugsListInText = `${blockingBugUrls.length > 0 ? `
|
|
784
937
|
BLOCKING BUGS:${blockingBugList}` : ""}${nonBlockingBugUrls.length > 0 ? `
|
|
785
938
|
NON BLOCKING BUGS:${nonBlockingBugList}` : ""}`;
|
|
786
|
-
return `\u274C Run failed and ${blockingBugsCount} blocking bug${pluralize(
|
|
939
|
+
return `\u274C Run failed and ${blockingBugsCount} blocking bug${pluralize(
|
|
940
|
+
blockingBugsCount
|
|
941
|
+
)} found${nonBlockingBugsCount ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(
|
|
942
|
+
nonBlockingBugsCount
|
|
943
|
+
)}` : ""}.
|
|
787
944
|
See ${relevantRunWithBugsUrl}
|
|
788
945
|
You may review the priority of certain bugs to mark these non-blocking and retry the job.
|
|
789
946
|
` + bugsListInText;
|
|
@@ -803,18 +960,17 @@ function buildSupersededContinueLogMessage(rootRunUrl, relevantRunUrl) {
|
|
|
803
960
|
return `Root run was superseded:${supersedingDetails}`;
|
|
804
961
|
}
|
|
805
962
|
__name(buildSupersededContinueLogMessage, "buildSupersededContinueLogMessage");
|
|
806
|
-
function buildRunStageLogMessage(
|
|
963
|
+
function buildRunStageLogMessage(status) {
|
|
964
|
+
const { relevantRunUrl, runStage } = status;
|
|
807
965
|
const urlInfo = `See ${relevantRunUrl}`;
|
|
808
966
|
switch (runStage) {
|
|
809
967
|
case "canceled":
|
|
810
|
-
return `\u{1F6AB} Run was canceled. Aborting... Please contact support.
|
|
968
|
+
return `\u{1F6AB} Run was canceled. ${status.message || "Aborting... Please contact support."}
|
|
811
969
|
${urlInfo}`;
|
|
812
970
|
case "initializing":
|
|
813
971
|
return `\u23F3 Run is in progress... ${urlInfo}`;
|
|
814
972
|
case "underReview":
|
|
815
973
|
return `\u{1F575}\uFE0F Run is under review... ${urlInfo}`;
|
|
816
|
-
case "completed":
|
|
817
|
-
throw Error("buildRunStageLogMessage should not be called for completed stage");
|
|
818
974
|
default:
|
|
819
975
|
throw Error(`Unexpected run stage: ${runStage}`);
|
|
820
976
|
}
|
|
@@ -827,21 +983,27 @@ function mapIteratorAbortToGreenlightStatus(iteration, pollTimeout, deps) {
|
|
|
827
983
|
const { abortReason, httpStatus } = iteration;
|
|
828
984
|
switch (abortReason) {
|
|
829
985
|
case "4XX-client-error":
|
|
830
|
-
log.error(
|
|
986
|
+
log.error(
|
|
987
|
+
`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`
|
|
988
|
+
);
|
|
831
989
|
return {
|
|
832
990
|
abortReason,
|
|
833
991
|
httpStatus,
|
|
834
992
|
outcome: "aborted"
|
|
835
993
|
};
|
|
836
994
|
case "5XX-server-error":
|
|
837
|
-
log.error(
|
|
995
|
+
log.error(
|
|
996
|
+
`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`
|
|
997
|
+
);
|
|
838
998
|
return {
|
|
839
999
|
abortReason,
|
|
840
1000
|
httpStatus,
|
|
841
1001
|
outcome: "aborted"
|
|
842
1002
|
};
|
|
843
1003
|
case "404-run-not-found":
|
|
844
|
-
log.error(
|
|
1004
|
+
log.error(
|
|
1005
|
+
`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`
|
|
1006
|
+
);
|
|
845
1007
|
return {
|
|
846
1008
|
abortReason,
|
|
847
1009
|
httpStatus,
|
|
@@ -862,14 +1024,18 @@ function mapIteratorAbortToGreenlightStatus(iteration, pollTimeout, deps) {
|
|
|
862
1024
|
outcome: "aborted"
|
|
863
1025
|
};
|
|
864
1026
|
case "run-canceled":
|
|
865
|
-
log.info(
|
|
1027
|
+
log.info(
|
|
1028
|
+
iteration.message ? `Run was canceled. ${iteration.message}` : `Run was canceled`
|
|
1029
|
+
);
|
|
866
1030
|
return {
|
|
867
1031
|
abortReason,
|
|
868
1032
|
httpStatus: void 0,
|
|
869
1033
|
outcome: "aborted"
|
|
870
1034
|
};
|
|
871
1035
|
case "XXX-other-http-code":
|
|
872
|
-
log.error(
|
|
1036
|
+
log.error(
|
|
1037
|
+
`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`
|
|
1038
|
+
);
|
|
873
1039
|
return {
|
|
874
1040
|
abortReason,
|
|
875
1041
|
httpStatus,
|
|
@@ -882,15 +1048,23 @@ function mapIteratorAbortToGreenlightStatus(iteration, pollTimeout, deps) {
|
|
|
882
1048
|
__name(mapIteratorAbortToGreenlightStatus, "mapIteratorAbortToGreenlightStatus");
|
|
883
1049
|
|
|
884
1050
|
// src/lib/sdk/domain/pollCiGreenlight/index.ts
|
|
885
|
-
async function pollCiGreenlightStatus(deps, apiConfig, {
|
|
1051
|
+
async function pollCiGreenlightStatus(deps, apiConfig, {
|
|
1052
|
+
onRunStageChanged = /* @__PURE__ */ __name(() => void 0, "onRunStageChanged"),
|
|
1053
|
+
runId,
|
|
1054
|
+
...pollConfig
|
|
1055
|
+
}) {
|
|
886
1056
|
const { log } = deps;
|
|
887
|
-
const {
|
|
1057
|
+
const {
|
|
1058
|
+
abortOnSuperseded = pollCiGreenlightDefaults.abortOnSuperseded,
|
|
1059
|
+
pollTimeout = pollCiGreenlightDefaults.pollTimeout
|
|
1060
|
+
} = pollConfig;
|
|
888
1061
|
const iterator = makePollCiGreenlightStatusIterator(deps, apiConfig, {
|
|
889
1062
|
runId,
|
|
890
1063
|
...pollConfig
|
|
891
1064
|
});
|
|
892
1065
|
for await (const lastPoll of iterator) {
|
|
893
|
-
if (lastPoll.isAborted)
|
|
1066
|
+
if (lastPoll.isAborted)
|
|
1067
|
+
return mapIteratorAbortToGreenlightStatus(lastPoll, pollTimeout, deps);
|
|
894
1068
|
const { previousStatus, stageChanged, status } = lastPoll;
|
|
895
1069
|
if (stageChanged) {
|
|
896
1070
|
try {
|
|
@@ -903,7 +1077,10 @@ async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /*
|
|
|
903
1077
|
const isSuperseded = rootRunId !== relevantRunId;
|
|
904
1078
|
const shouldAbortOnSuperseded = isSuperseded && abortOnSuperseded;
|
|
905
1079
|
if (shouldAbortOnSuperseded) {
|
|
906
|
-
const message = buildSupersededAbortLogMessage(
|
|
1080
|
+
const message = buildSupersededAbortLogMessage(
|
|
1081
|
+
rootRunUrl,
|
|
1082
|
+
relevantRunUrl
|
|
1083
|
+
);
|
|
907
1084
|
log.warn(message);
|
|
908
1085
|
return {
|
|
909
1086
|
abortReason: "superseded-run",
|
|
@@ -912,14 +1089,17 @@ async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /*
|
|
|
912
1089
|
};
|
|
913
1090
|
}
|
|
914
1091
|
if (isSuperseded) {
|
|
915
|
-
const message = buildSupersededContinueLogMessage(
|
|
1092
|
+
const message = buildSupersededContinueLogMessage(
|
|
1093
|
+
rootRunUrl,
|
|
1094
|
+
relevantRunUrl
|
|
1095
|
+
);
|
|
916
1096
|
log.info(message);
|
|
917
1097
|
}
|
|
918
1098
|
switch (runStage) {
|
|
919
1099
|
case "canceled":
|
|
920
1100
|
case "initializing":
|
|
921
1101
|
case "underReview": {
|
|
922
|
-
log.info(buildRunStageLogMessage(
|
|
1102
|
+
log.info(buildRunStageLogMessage(status));
|
|
923
1103
|
break;
|
|
924
1104
|
}
|
|
925
1105
|
case "completed": {
|
|
@@ -952,10 +1132,19 @@ async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /*
|
|
|
952
1132
|
__name(pollCiGreenlightStatus, "pollCiGreenlightStatus");
|
|
953
1133
|
|
|
954
1134
|
// src/lib/sdk/index.ts
|
|
955
|
-
function makeQaWolfSdk({
|
|
1135
|
+
function makeQaWolfSdk({
|
|
1136
|
+
apiKey,
|
|
1137
|
+
serviceBase = defaultServiceBase,
|
|
1138
|
+
userAgent = defaultUserAgent
|
|
1139
|
+
}, {
|
|
1140
|
+
fetch = defaultFetch,
|
|
1141
|
+
log = defaultLogDriver
|
|
1142
|
+
} = {}) {
|
|
956
1143
|
if (typeof fetch !== "function") {
|
|
957
|
-
throw Error(
|
|
958
|
-
|
|
1144
|
+
throw Error(
|
|
1145
|
+
`QA Wolf CI-SDK requires fetch to be defined. Make sure you are using NodeJS 18+, OR pass a fetch polyfill to the makeQaWolfSdk function.
|
|
1146
|
+
We recommend 'undici' package for that purpose. See the Requirement section of our README for more guidance.`
|
|
1147
|
+
);
|
|
959
1148
|
}
|
|
960
1149
|
const deps = {
|
|
961
1150
|
// Versions of fetch may have different default timeouts. For consistency, we explicitly set it to 2 minutes here.
|
|
@@ -964,22 +1153,27 @@ We recommend 'undici' package for that purpose. See the Requirement section of o
|
|
|
964
1153
|
fetch: buildFetchWithTimeout(fetch, 12e4),
|
|
965
1154
|
log
|
|
966
1155
|
};
|
|
967
|
-
const apiConfig = {
|
|
968
|
-
apiKey,
|
|
969
|
-
serviceBase,
|
|
970
|
-
userAgent
|
|
971
|
-
};
|
|
1156
|
+
const apiConfig = { apiKey, serviceBase, userAgent };
|
|
972
1157
|
return {
|
|
973
1158
|
attemptNotifyDeploy: attemptNotifyDeploy.bind(null, deps, apiConfig),
|
|
974
|
-
generateSignedUrlForRunInputsExecutablesStorage: generateSignedUrlForRunInputsExecutablesStorage.bind(
|
|
1159
|
+
generateSignedUrlForRunInputsExecutablesStorage: generateSignedUrlForRunInputsExecutablesStorage.bind(
|
|
1160
|
+
null,
|
|
1161
|
+
deps,
|
|
1162
|
+
apiConfig
|
|
1163
|
+
),
|
|
975
1164
|
generateSignedUrlForTempTeamStorage: generateSignedUrlForTempTeamStorage.bind(null, deps, apiConfig),
|
|
976
|
-
makePollCiGreenlightStatusIterator: makePollCiGreenlightStatusIterator.bind(
|
|
1165
|
+
makePollCiGreenlightStatusIterator: makePollCiGreenlightStatusIterator.bind(
|
|
1166
|
+
null,
|
|
1167
|
+
deps,
|
|
1168
|
+
apiConfig
|
|
1169
|
+
),
|
|
977
1170
|
notifyTerminatedEphemeralEnvironment: notifyTerminatedEphemeralEnvironment.bind(null, deps, apiConfig),
|
|
978
1171
|
pollCiGreenlightStatus: pollCiGreenlightStatus.bind(null, deps, apiConfig)
|
|
979
1172
|
};
|
|
980
1173
|
}
|
|
981
1174
|
__name(makeQaWolfSdk, "makeQaWolfSdk");
|
|
982
|
-
|
|
983
|
-
exports
|
|
1175
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1176
|
+
0 && (module.exports = {
|
|
1177
|
+
makeQaWolfSdk
|
|
1178
|
+
});
|
|
984
1179
|
//# sourceMappingURL=index.cjs.map
|
|
985
|
-
//# sourceMappingURL=index.cjs.map
|