@qawolf/ci-sdk 1.1.0 → 1.2.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 +126 -0
- package/dist/index.cjs +278 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -2
- package/dist/index.d.ts +67 -2
- package/dist/index.js +278 -149
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -36,49 +36,7 @@ var defaultServiceBase = "https://app.qawolf.com/";
|
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
38
|
var package_default = {
|
|
39
|
-
|
|
40
|
-
version: "1.1.0",
|
|
41
|
-
private: false,
|
|
42
|
-
description: "A simple SDK for interacting with QAWolf in CI scripts.",
|
|
43
|
-
keywords: [],
|
|
44
|
-
license: "MIT",
|
|
45
|
-
author: "Jules Sam. Randolph<jules@qawolf.com>",
|
|
46
|
-
sideEffects: false,
|
|
47
|
-
type: "module",
|
|
48
|
-
exports: {
|
|
49
|
-
".": {
|
|
50
|
-
types: "./dist/index.d.ts",
|
|
51
|
-
require: "./dist/index.cjs",
|
|
52
|
-
import: "./dist/index.js",
|
|
53
|
-
default: "./dist/index.js"
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
files: [
|
|
57
|
-
"/dist",
|
|
58
|
-
"/README.md"
|
|
59
|
-
],
|
|
60
|
-
scripts: {
|
|
61
|
-
build: "tsup src/index.ts --format esm,cjs --dts --clean --splitting --treeshake --sourcemap --outDir dist --target es2022",
|
|
62
|
-
lint: "dpdm --exit-code circular:1 --no-tree --no-warning --transform --include='.*' --exclude='/(dist|node_modules)/' '**/*' && eslint . --ext cjs,cts,js,jsx,mjs,ts,tsx --quiet && prettier --check .",
|
|
63
|
-
"lint:fix": "eslint . --ext cjs,cts,js,jsx,mjs,ts,tsx --fix --quiet && prettier --log-level=warn --write .",
|
|
64
|
-
"lint:warnings": "eslint . --ext cjs,cts,js,jsx,mjs,ts,tsx",
|
|
65
|
-
prepublishOnly: "nx run ci-sdk:build",
|
|
66
|
-
test: 'NODE_OPTIONS="--experimental-vm-modules" NODE_NO_WARNINGS=1 jest',
|
|
67
|
-
"tsc:check": "tsc --noEmit"
|
|
68
|
-
},
|
|
69
|
-
dependencies: {
|
|
70
|
-
"@qawolf/ci-utils": "^1.0.0",
|
|
71
|
-
"@sinonjs/fake-timers": "^10.3.0",
|
|
72
|
-
slugify: "^1.6.6",
|
|
73
|
-
tslib: "^2.6.2"
|
|
74
|
-
},
|
|
75
|
-
devDependencies: {
|
|
76
|
-
tsup: "8.3.5"
|
|
77
|
-
},
|
|
78
|
-
engines: {
|
|
79
|
-
node: ">=20"
|
|
80
|
-
}
|
|
81
|
-
};
|
|
39
|
+
version: "1.2.0"};
|
|
82
40
|
|
|
83
41
|
// src/lib/sdk/defaults/userAgent.ts
|
|
84
42
|
var defaultUserAgent = `ci-sdk/${package_default.version}`;
|
|
@@ -101,8 +59,8 @@ async function logFetchError({ log, methodName, response }) {
|
|
|
101
59
|
};
|
|
102
60
|
} catch {
|
|
103
61
|
return {
|
|
104
|
-
eventId:
|
|
105
|
-
failureMessage:
|
|
62
|
+
eventId: void 0,
|
|
63
|
+
failureMessage: void 0
|
|
106
64
|
};
|
|
107
65
|
}
|
|
108
66
|
})();
|
|
@@ -149,7 +107,7 @@ async function attemptNotifyDeploy(deps, apiConfig, config) {
|
|
|
149
107
|
log.error(`\u{1F6AB} Network error from deploy_success, aborting.`);
|
|
150
108
|
return {
|
|
151
109
|
abortReason: "network-error",
|
|
152
|
-
httpStatus:
|
|
110
|
+
httpStatus: void 0,
|
|
153
111
|
outcome: "aborted"
|
|
154
112
|
};
|
|
155
113
|
}
|
|
@@ -158,7 +116,7 @@ __name(attemptNotifyDeploy, "attemptNotifyDeploy");
|
|
|
158
116
|
async function handleErrorResponse(response, log) {
|
|
159
117
|
const status = response.status;
|
|
160
118
|
let abortReason;
|
|
161
|
-
if (status ===
|
|
119
|
+
if (status === void 0) abortReason = "network-error";
|
|
162
120
|
else if (status === 401) abortReason = "401-unauthorized";
|
|
163
121
|
else if (status === 403) abortReason = "403-forbidden";
|
|
164
122
|
else if (status >= 500) abortReason = "5XX-server-error";
|
|
@@ -188,10 +146,10 @@ async function handleSuccessResponse(data, log) {
|
|
|
188
146
|
return {
|
|
189
147
|
environmentId: environment.id,
|
|
190
148
|
outcome: "success",
|
|
191
|
-
runId:
|
|
149
|
+
runId: void 0
|
|
192
150
|
};
|
|
193
151
|
}
|
|
194
|
-
log.error(`\u{1F6AB} No trigger matched the request. Please contact support.`);
|
|
152
|
+
log.error(`\u{1F6AB} No trigger matched the request. Please make sure there is at least one active test in the QA Wolf environment, or contact support.`);
|
|
195
153
|
return {
|
|
196
154
|
failReason: "no-matched-trigger",
|
|
197
155
|
outcome: "failed"
|
|
@@ -398,6 +356,29 @@ async function generateSignedUrlForTempTeamStorage(deps, apiConfig, config) {
|
|
|
398
356
|
}
|
|
399
357
|
__name(generateSignedUrlForTempTeamStorage, "generateSignedUrlForTempTeamStorage");
|
|
400
358
|
|
|
359
|
+
// src/lib/sdk/domain/pollCiGreenlight/buildCompletedRunResult.ts
|
|
360
|
+
function buildCompletedRunResult(status) {
|
|
361
|
+
if (status.greenlight) return {
|
|
362
|
+
greenlightStatus: status,
|
|
363
|
+
outcome: "success"
|
|
364
|
+
};
|
|
365
|
+
else return {
|
|
366
|
+
greenlightStatus: status,
|
|
367
|
+
outcome: "failed"
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
__name(buildCompletedRunResult, "buildCompletedRunResult");
|
|
371
|
+
|
|
372
|
+
// src/lib/sdk/domain/pollCiGreenlight/consts.ts
|
|
373
|
+
var pollCiGreenlightDefaults = {
|
|
374
|
+
abortOnSuperseded: false,
|
|
375
|
+
maxRetries: 10,
|
|
376
|
+
pollTimeout: 120 * 60 * 1e3,
|
|
377
|
+
retryInterval: 10 * 1e3,
|
|
378
|
+
runInProgressInterval: 30 * 1e3,
|
|
379
|
+
runUnderReviewInterval: 60 * 1e3
|
|
380
|
+
};
|
|
381
|
+
|
|
401
382
|
// src/lib/api/ci-greenlight.ts
|
|
402
383
|
async function fetchCiGreenlightStatus({ apiKey, serviceBase, userAgent }, { runId }, { fetch: localFetch, log }) {
|
|
403
384
|
try {
|
|
@@ -453,56 +434,61 @@ async function fetchCiGreenlightStatus({ apiKey, serviceBase, userAgent }, { run
|
|
|
453
434
|
}
|
|
454
435
|
__name(fetchCiGreenlightStatus, "fetchCiGreenlightStatus");
|
|
455
436
|
|
|
456
|
-
// src/lib/sdk/domain/
|
|
457
|
-
|
|
458
|
-
abortOnSuperseded: false,
|
|
459
|
-
maxRetries: 10,
|
|
460
|
-
pollTimeout: 120 * 60 * 1e3,
|
|
461
|
-
retryInterval: 10 * 1e3,
|
|
462
|
-
runInProgressInterval: 30 * 1e3,
|
|
463
|
-
runUnderReviewInterval: 60 * 1e3
|
|
464
|
-
};
|
|
465
|
-
async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /* @__PURE__ */ __name(() => undefined, "onRunStageChanged"), runId, ...pollConfig }) {
|
|
466
|
-
let retries = 0;
|
|
437
|
+
// src/lib/sdk/domain/pollCiGreenlight/iterator.ts
|
|
438
|
+
async function* makePollCiGreenlightStatusIterator(deps, apiConfig, { runId, ...pollConfig }) {
|
|
467
439
|
const { log } = deps;
|
|
468
|
-
const {
|
|
469
|
-
let
|
|
440
|
+
const { maxRetries = pollCiGreenlightDefaults.maxRetries, pollTimeout = pollCiGreenlightDefaults.pollTimeout, retryInterval = pollCiGreenlightDefaults.retryInterval, runInProgressInterval = pollCiGreenlightDefaults.runInProgressInterval, runUnderReviewInterval = pollCiGreenlightDefaults.runUnderReviewInterval } = pollConfig;
|
|
441
|
+
let retries = 0;
|
|
442
|
+
let previousStatus = void 0;
|
|
470
443
|
const startedAt = Date.now();
|
|
471
|
-
|
|
472
|
-
while (!(hasTimedOut = Date.now() - startedAt > pollTimeout)) {
|
|
444
|
+
while (Date.now() - startedAt <= pollTimeout) {
|
|
473
445
|
const responseState = await fetchCiGreenlightStatus(apiConfig, {
|
|
474
446
|
runId
|
|
475
447
|
}, deps);
|
|
448
|
+
const elapsedMs = Date.now() - startedAt;
|
|
476
449
|
if (!responseState.ok && !responseState.canRetry) {
|
|
477
|
-
|
|
478
|
-
return {
|
|
450
|
+
yield {
|
|
479
451
|
abortReason: "4XX-client-error",
|
|
452
|
+
elapsedMs,
|
|
480
453
|
httpStatus: responseState.httpStatus,
|
|
481
|
-
|
|
454
|
+
isAborted: true
|
|
482
455
|
};
|
|
456
|
+
return;
|
|
483
457
|
}
|
|
484
458
|
if (!responseState.ok) {
|
|
485
459
|
retries += 1;
|
|
460
|
+
const { errorType, httpStatus } = responseState;
|
|
486
461
|
if (retries > maxRetries) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
462
|
+
switch (errorType) {
|
|
463
|
+
case "network":
|
|
464
|
+
yield {
|
|
465
|
+
abortReason: "network-error",
|
|
466
|
+
elapsedMs,
|
|
467
|
+
httpStatus: void 0,
|
|
468
|
+
isAborted: true
|
|
469
|
+
};
|
|
470
|
+
break;
|
|
471
|
+
case "not-found":
|
|
472
|
+
yield {
|
|
473
|
+
abortReason: "404-run-not-found",
|
|
474
|
+
elapsedMs,
|
|
475
|
+
httpStatus: httpStatus ?? 404,
|
|
476
|
+
isAborted: true
|
|
477
|
+
};
|
|
478
|
+
break;
|
|
479
|
+
case "server":
|
|
480
|
+
yield {
|
|
481
|
+
abortReason: "5XX-server-error",
|
|
482
|
+
elapsedMs,
|
|
483
|
+
httpStatus: httpStatus ?? 500,
|
|
484
|
+
isAborted: true
|
|
485
|
+
};
|
|
486
|
+
break;
|
|
487
|
+
default:
|
|
488
|
+
throw Error(`Unexpected error type: ${errorType}`);
|
|
494
489
|
}
|
|
495
|
-
|
|
496
|
-
if (responseState.errorType === "not-found") abortReason = "404-run-not-found";
|
|
497
|
-
else if (responseState.errorType === "server") abortReason = "5XX-server-error";
|
|
498
|
-
else ;
|
|
499
|
-
return {
|
|
500
|
-
abortReason,
|
|
501
|
-
httpStatus: responseState.httpStatus,
|
|
502
|
-
outcome: "aborted"
|
|
503
|
-
};
|
|
490
|
+
return;
|
|
504
491
|
}
|
|
505
|
-
const { errorType, httpStatus } = responseState;
|
|
506
492
|
const retryLabel = `${httpStatus ? ` (status ${httpStatus})` : ""}, will try again... (${retries}/${maxRetries})`;
|
|
507
493
|
if (errorType === "network") log.warn(`\u274C Network error${retryLabel}`);
|
|
508
494
|
else if (errorType === "not-found") log.info(`\u23F3 Run not found${retryLabel}`);
|
|
@@ -512,89 +498,231 @@ async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /*
|
|
|
512
498
|
}
|
|
513
499
|
retries = 0;
|
|
514
500
|
const { greenlightStatus } = responseState;
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
abortReason: "superseded-run",
|
|
534
|
-
httpStatus: undefined,
|
|
535
|
-
outcome: "aborted"
|
|
501
|
+
const stageChanged = !previousStatus || previousStatus.runStage !== greenlightStatus.runStage;
|
|
502
|
+
const isFailedTerminalStage = greenlightStatus.runStage === "canceled" || greenlightStatus.runStage === "completed" && greenlightStatus.greenlight === false;
|
|
503
|
+
yield {
|
|
504
|
+
elapsedMs,
|
|
505
|
+
isAborted: false,
|
|
506
|
+
isFailedTerminalStage,
|
|
507
|
+
previousStatus,
|
|
508
|
+
stageChanged,
|
|
509
|
+
status: greenlightStatus
|
|
510
|
+
};
|
|
511
|
+
previousStatus = greenlightStatus;
|
|
512
|
+
switch (greenlightStatus.runStage) {
|
|
513
|
+
case "canceled": {
|
|
514
|
+
yield {
|
|
515
|
+
abortReason: "run-canceled",
|
|
516
|
+
elapsedMs,
|
|
517
|
+
httpStatus: void 0,
|
|
518
|
+
isAborted: true
|
|
536
519
|
};
|
|
520
|
+
return;
|
|
537
521
|
}
|
|
538
|
-
|
|
522
|
+
case "completed":
|
|
523
|
+
return;
|
|
524
|
+
case "initializing":
|
|
525
|
+
await sleep(runInProgressInterval);
|
|
526
|
+
break;
|
|
527
|
+
case "underReview":
|
|
528
|
+
await sleep(runUnderReviewInterval);
|
|
529
|
+
break;
|
|
530
|
+
default:
|
|
531
|
+
throw Error(`Unexpected run stage: ${greenlightStatus}`);
|
|
539
532
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
533
|
+
}
|
|
534
|
+
yield {
|
|
535
|
+
abortReason: "poll-timed-out",
|
|
536
|
+
elapsedMs: Date.now() - startedAt,
|
|
537
|
+
httpStatus: void 0,
|
|
538
|
+
isAborted: true
|
|
539
|
+
};
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
__name(makePollCiGreenlightStatusIterator, "makePollCiGreenlightStatusIterator");
|
|
543
|
+
|
|
544
|
+
// src/lib/sdk/domain/pollCiGreenlight/logging.ts
|
|
545
|
+
function buildSuccessLogMessage(status) {
|
|
546
|
+
const { nonBlockingBugsCount, relevantRunUrl } = status;
|
|
547
|
+
const urlInfo = `See ${relevantRunUrl}`;
|
|
548
|
+
return `\u2705 Run passed and no blocking bugs found${nonBlockingBugsCount > 0 ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(nonBlockingBugsCount)} found` : ""}.
|
|
549
|
+
${urlInfo}`;
|
|
550
|
+
}
|
|
551
|
+
__name(buildSuccessLogMessage, "buildSuccessLogMessage");
|
|
552
|
+
function buildFailedLogMessage(status) {
|
|
553
|
+
const { blockingBugsCount, blockingBugUrls = [], nonBlockingBugsCount, nonBlockingBugUrls = [], relevantRunWithBugsUrl } = status;
|
|
554
|
+
const blockingBugList = blockingBugUrls.map((url) => `
|
|
543
555
|
\u2022 ${url}`).join("");
|
|
544
|
-
|
|
556
|
+
const nonBlockingBugList = nonBlockingBugUrls.map((url) => `
|
|
545
557
|
\u2022 ${url}`).join("");
|
|
546
|
-
|
|
558
|
+
const bugsListInText = `${blockingBugUrls.length > 0 ? `
|
|
547
559
|
BLOCKING BUGS:${blockingBugList}` : ""}${nonBlockingBugUrls.length > 0 ? `
|
|
548
560
|
NON BLOCKING BUGS:${nonBlockingBugList}` : ""}`;
|
|
549
|
-
|
|
550
|
-
log.info(`\u2705 Run passed and no blocking bugs found${nonBlockingBugsCount > 0 ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(nonBlockingBugsCount)} found` : ""}.
|
|
551
|
-
${urlInfo}`);
|
|
552
|
-
return {
|
|
553
|
-
greenlightStatus,
|
|
554
|
-
outcome: "success"
|
|
555
|
-
};
|
|
556
|
-
} else {
|
|
557
|
-
log.warn(`\u274C Run failed and ${blockingBugsCount} blocking bug${pluralize(blockingBugsCount)} found${nonBlockingBugsCount ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(nonBlockingBugsCount)}` : ""}.
|
|
561
|
+
return `\u274C Run failed and ${blockingBugsCount} blocking bug${pluralize(blockingBugsCount)} found${nonBlockingBugsCount ? ` and ${nonBlockingBugsCount} non-blocking bug${pluralize(nonBlockingBugsCount)}` : ""}.
|
|
558
562
|
See ${relevantRunWithBugsUrl}
|
|
559
563
|
You may review the priority of certain bugs to mark these non-blocking and retry the job.
|
|
560
|
-
` + bugsListInText
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
564
|
+
` + bugsListInText;
|
|
565
|
+
}
|
|
566
|
+
__name(buildFailedLogMessage, "buildFailedLogMessage");
|
|
567
|
+
function buildSupersededAbortLogMessage(rootRunUrl, relevantRunUrl) {
|
|
568
|
+
const supersedingDetails = `
|
|
569
|
+
- Root: ${rootRunUrl}
|
|
570
|
+
- Superseding: ${relevantRunUrl}`;
|
|
571
|
+
return `\u274C Aborting due to superseded run (option 'abortOnSuperseded' is enabled).${supersedingDetails}`;
|
|
572
|
+
}
|
|
573
|
+
__name(buildSupersededAbortLogMessage, "buildSupersededAbortLogMessage");
|
|
574
|
+
function buildSupersededContinueLogMessage(rootRunUrl, relevantRunUrl) {
|
|
575
|
+
const supersedingDetails = `
|
|
576
|
+
- Root: ${rootRunUrl}
|
|
577
|
+
- Superseding: ${relevantRunUrl}`;
|
|
578
|
+
return `Root run was superseded:${supersedingDetails}`;
|
|
579
|
+
}
|
|
580
|
+
__name(buildSupersededContinueLogMessage, "buildSupersededContinueLogMessage");
|
|
581
|
+
function buildRunStageLogMessage(runStage, relevantRunUrl) {
|
|
582
|
+
const urlInfo = `See ${relevantRunUrl}`;
|
|
583
|
+
switch (runStage) {
|
|
584
|
+
case "canceled":
|
|
585
|
+
return `\u{1F6AB} Run was canceled. Aborting... Please contact support.
|
|
586
|
+
${urlInfo}`;
|
|
587
|
+
case "initializing":
|
|
588
|
+
return `\u23F3 Run is in progress... ${urlInfo}`;
|
|
589
|
+
case "underReview":
|
|
590
|
+
return `\u{1F575}\uFE0F Run is under review... ${urlInfo}`;
|
|
591
|
+
case "completed":
|
|
592
|
+
throw Error("buildRunStageLogMessage should not be called for completed stage");
|
|
593
|
+
default:
|
|
594
|
+
throw Error(`Unexpected run stage: ${runStage}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
__name(buildRunStageLogMessage, "buildRunStageLogMessage");
|
|
598
|
+
|
|
599
|
+
// src/lib/sdk/domain/pollCiGreenlight/mapIteratorAbortToGreenlightStatus.ts
|
|
600
|
+
function mapIteratorAbortToGreenlightStatus(iteration, pollTimeout, deps) {
|
|
601
|
+
const { log } = deps;
|
|
602
|
+
const { abortReason, httpStatus } = iteration;
|
|
603
|
+
switch (abortReason) {
|
|
604
|
+
case "4XX-client-error":
|
|
605
|
+
log.error(`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`);
|
|
606
|
+
return {
|
|
607
|
+
abortReason,
|
|
608
|
+
httpStatus,
|
|
609
|
+
outcome: "aborted"
|
|
610
|
+
};
|
|
611
|
+
case "5XX-server-error":
|
|
612
|
+
log.error(`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`);
|
|
613
|
+
return {
|
|
614
|
+
abortReason,
|
|
615
|
+
httpStatus,
|
|
616
|
+
outcome: "aborted"
|
|
617
|
+
};
|
|
618
|
+
case "404-run-not-found":
|
|
619
|
+
log.error(`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`);
|
|
620
|
+
return {
|
|
621
|
+
abortReason,
|
|
622
|
+
httpStatus,
|
|
623
|
+
outcome: "aborted"
|
|
624
|
+
};
|
|
625
|
+
case "network-error":
|
|
626
|
+
log.error(`\u{1F6AB} Unrecoverable network error from CI greenlight, aborting.`);
|
|
627
|
+
return {
|
|
628
|
+
abortReason,
|
|
629
|
+
httpStatus: void 0,
|
|
630
|
+
outcome: "aborted"
|
|
631
|
+
};
|
|
632
|
+
case "poll-timed-out":
|
|
633
|
+
log.warn(`\u274C Poll timed out after ${pollTimeout / 1e3}s`);
|
|
570
634
|
return {
|
|
571
|
-
abortReason
|
|
572
|
-
httpStatus:
|
|
635
|
+
abortReason,
|
|
636
|
+
httpStatus: void 0,
|
|
573
637
|
outcome: "aborted"
|
|
574
638
|
};
|
|
639
|
+
case "run-canceled":
|
|
640
|
+
log.info(`Run was canceled`);
|
|
641
|
+
return {
|
|
642
|
+
abortReason,
|
|
643
|
+
httpStatus: void 0,
|
|
644
|
+
outcome: "aborted"
|
|
645
|
+
};
|
|
646
|
+
case "XXX-other-http-code":
|
|
647
|
+
log.error(`\u{1F6AB} Unrecoverable error (status ${httpStatus}) from CI greenlight, aborting.`);
|
|
648
|
+
return {
|
|
649
|
+
abortReason,
|
|
650
|
+
httpStatus,
|
|
651
|
+
outcome: "aborted"
|
|
652
|
+
};
|
|
653
|
+
default:
|
|
654
|
+
throw Error(`Unexpected abort reason: ${abortReason}`);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
__name(mapIteratorAbortToGreenlightStatus, "mapIteratorAbortToGreenlightStatus");
|
|
658
|
+
|
|
659
|
+
// src/lib/sdk/domain/pollCiGreenlight/index.ts
|
|
660
|
+
async function pollCiGreenlightStatus(deps, apiConfig, { onRunStageChanged = /* @__PURE__ */ __name(() => void 0, "onRunStageChanged"), runId, ...pollConfig }) {
|
|
661
|
+
const { log } = deps;
|
|
662
|
+
const { abortOnSuperseded = pollCiGreenlightDefaults.abortOnSuperseded, pollTimeout = pollCiGreenlightDefaults.pollTimeout } = pollConfig;
|
|
663
|
+
const iterator = makePollCiGreenlightStatusIterator(deps, apiConfig, {
|
|
664
|
+
runId,
|
|
665
|
+
...pollConfig
|
|
666
|
+
});
|
|
667
|
+
for await (const lastPoll of iterator) {
|
|
668
|
+
if (lastPoll.isAborted) return mapIteratorAbortToGreenlightStatus(lastPoll, pollTimeout, deps);
|
|
669
|
+
const { previousStatus, stageChanged, status } = lastPoll;
|
|
670
|
+
if (stageChanged) {
|
|
671
|
+
try {
|
|
672
|
+
await onRunStageChanged(status, previousStatus);
|
|
673
|
+
} catch (e) {
|
|
674
|
+
log.error(`Error in onRunStageChanged callback`, e);
|
|
675
|
+
}
|
|
575
676
|
}
|
|
576
|
-
|
|
577
|
-
|
|
677
|
+
const { relevantRunId, relevantRunUrl, rootRunId, rootRunUrl, runStage } = status;
|
|
678
|
+
const isSuperseded = rootRunId !== relevantRunId;
|
|
679
|
+
const shouldAbortOnSuperseded = isSuperseded && abortOnSuperseded;
|
|
680
|
+
if (shouldAbortOnSuperseded) {
|
|
681
|
+
const message = buildSupersededAbortLogMessage(rootRunUrl, relevantRunUrl);
|
|
682
|
+
log.warn(message);
|
|
578
683
|
return {
|
|
579
|
-
abortReason: "
|
|
580
|
-
httpStatus:
|
|
684
|
+
abortReason: "superseded-run",
|
|
685
|
+
httpStatus: void 0,
|
|
581
686
|
outcome: "aborted"
|
|
582
687
|
};
|
|
583
688
|
}
|
|
584
|
-
if (
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
689
|
+
if (isSuperseded) {
|
|
690
|
+
const message = buildSupersededContinueLogMessage(rootRunUrl, relevantRunUrl);
|
|
691
|
+
log.info(message);
|
|
692
|
+
}
|
|
693
|
+
switch (runStage) {
|
|
694
|
+
case "canceled":
|
|
695
|
+
case "initializing":
|
|
696
|
+
case "underReview": {
|
|
697
|
+
log.info(buildRunStageLogMessage(runStage, relevantRunUrl));
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
case "completed": {
|
|
701
|
+
const result = buildCompletedRunResult(status);
|
|
702
|
+
switch (result.outcome) {
|
|
703
|
+
case "aborted": {
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
case "failed": {
|
|
707
|
+
const message = buildFailedLogMessage(status);
|
|
708
|
+
log.warn(message);
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
case "success": {
|
|
712
|
+
const message = buildSuccessLogMessage(status);
|
|
713
|
+
log.info(message);
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
default:
|
|
717
|
+
throw Error(`Unexpected outcome: ${result}`);
|
|
718
|
+
}
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
default:
|
|
722
|
+
throw Error(`Unexpected run stage: ${runStage}`);
|
|
723
|
+
}
|
|
591
724
|
}
|
|
592
|
-
|
|
593
|
-
return {
|
|
594
|
-
abortReason: "poll-timed-out",
|
|
595
|
-
httpStatus: undefined,
|
|
596
|
-
outcome: "aborted"
|
|
597
|
-
};
|
|
725
|
+
throw Error("Iterator ended unexpectedly");
|
|
598
726
|
}
|
|
599
727
|
__name(pollCiGreenlightStatus, "pollCiGreenlightStatus");
|
|
600
728
|
|
|
@@ -620,6 +748,7 @@ We recommend 'undici' package for that purpose. See the Requirement section of o
|
|
|
620
748
|
attemptNotifyDeploy: attemptNotifyDeploy.bind(null, deps, apiConfig),
|
|
621
749
|
generateSignedUrlForRunInputsExecutablesStorage: generateSignedUrlForRunInputsExecutablesStorage.bind(null, deps, apiConfig),
|
|
622
750
|
generateSignedUrlForTempTeamStorage: generateSignedUrlForTempTeamStorage.bind(null, deps, apiConfig),
|
|
751
|
+
makePollCiGreenlightStatusIterator: makePollCiGreenlightStatusIterator.bind(null, deps, apiConfig),
|
|
623
752
|
pollCiGreenlightStatus: pollCiGreenlightStatus.bind(null, deps, apiConfig)
|
|
624
753
|
};
|
|
625
754
|
}
|