svcloud 0.1.0-alpha.3

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.
@@ -0,0 +1,68 @@
1
+ /**
2
+ * One poller shared by `init` (watching the provision it just started) and
3
+ * `runs` (watching one on request), so a run reads identically no matter
4
+ * which command is looking at it. Step labels are printed exactly as the
5
+ * server writes them (`RunStepDetail.label`, from `serialize.ts`'s
6
+ * `STEP_LABELS`) — re-wording them here would be the same mistake `status`
7
+ * is explicitly told not to make with health copy.
8
+ *
9
+ * Prints a step's line once, the moment it reaches a terminal status —
10
+ * never a redraw, since stdout may be a pipe.
11
+ */
12
+ import type { RunDetail, RunStepStatus } from "@sv/cloud-contracts";
13
+
14
+ const TERMINAL_STEP_STATUSES: ReadonlySet<RunStepStatus> = new Set(["succeeded", "failed", "skipped"]);
15
+ const RUNNING_RUN_STATUSES: ReadonlySet<RunDetail["status"]> = new Set(["queued", "running"]);
16
+
17
+ function stepLine(status: RunStepStatus): string {
18
+ return status === "succeeded" ? "done" : status;
19
+ }
20
+
21
+ function printNewSteps(run: RunDetail, printed: Map<string, RunStepStatus>): void {
22
+ for (const step of run.steps) {
23
+ if (printed.get(step.key) === step.status) continue;
24
+ if (TERMINAL_STEP_STATUSES.has(step.status)) {
25
+ console.log(` ${step.label}: ${stepLine(step.status)}`);
26
+ }
27
+ printed.set(step.key, step.status);
28
+ }
29
+ }
30
+
31
+ function sleep(ms: number): Promise<void> {
32
+ return new Promise((resolve) => setTimeout(resolve, ms));
33
+ }
34
+
35
+ export interface PollOptions {
36
+ intervalMs?: number;
37
+ timeoutMs?: number;
38
+ /** Printed once if the timeout is hit, e.g. `svcloud runs my-app`. */
39
+ resumeHint: string;
40
+ /** Suppress step-line printing (for `--json`, which prints the final RunDetail instead). */
41
+ quiet?: boolean;
42
+ }
43
+
44
+ /** Resolves once the run reaches a terminal status, or the timeout is hit (whichever first). */
45
+ export async function pollRun(fetchRun: () => Promise<RunDetail>, opts: PollOptions): Promise<RunDetail> {
46
+ const interval = opts.intervalMs ?? 2000;
47
+ const timeout = opts.timeoutMs ?? 5 * 60 * 1000;
48
+ const start = Date.now();
49
+ const printed = new Map<string, RunStepStatus>();
50
+
51
+ let run = await fetchRun();
52
+ if (!opts.quiet) printNewSteps(run, printed);
53
+
54
+ while (RUNNING_RUN_STATUSES.has(run.status)) {
55
+ if (Date.now() - start > timeout) {
56
+ if (!opts.quiet) {
57
+ console.error(
58
+ `Still going after ${Math.round(timeout / 1000)}s. Check back with \`${opts.resumeHint}\`.`,
59
+ );
60
+ }
61
+ return run;
62
+ }
63
+ await sleep(interval);
64
+ run = await fetchRun();
65
+ if (!opts.quiet) printNewSteps(run, printed);
66
+ }
67
+ return run;
68
+ }