@capuchoo/cli 0.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 +351 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +61 -0
- package/dist/base-command.js.map +1 -0
- package/dist/commands/auth/login.d.ts +19 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +74 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +22 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +9 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +77 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/channel/list.d.ts +9 -0
- package/dist/commands/channel/list.d.ts.map +1 -0
- package/dist/commands/channel/list.js +47 -0
- package/dist/commands/channel/list.js.map +1 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.d.ts.map +1 -0
- package/dist/commands/config/list.js +116 -0
- package/dist/commands/config/list.js.map +1 -0
- package/dist/commands/config/set.d.ts +11 -0
- package/dist/commands/config/set.d.ts.map +1 -0
- package/dist/commands/config/set.js +44 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/deploy/native.d.ts +23 -0
- package/dist/commands/deploy/native.d.ts.map +1 -0
- package/dist/commands/deploy/native.js +39 -0
- package/dist/commands/deploy/native.js.map +1 -0
- package/dist/commands/deploy/ota.d.ts +20 -0
- package/dist/commands/deploy/ota.d.ts.map +1 -0
- package/dist/commands/deploy/ota.js +20 -0
- package/dist/commands/deploy/ota.js.map +1 -0
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +232 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/version/bump.d.ts +13 -0
- package/dist/commands/version/bump.d.ts.map +1 -0
- package/dist/commands/version/bump.js +52 -0
- package/dist/commands/version/bump.js.map +1 -0
- package/dist/commands/version/sync.d.ts +12 -0
- package/dist/commands/version/sync.d.ts.map +1 -0
- package/dist/commands/version/sync.js +81 -0
- package/dist/commands/version/sync.js.map +1 -0
- package/dist/deploy/execute.d.ts +48 -0
- package/dist/deploy/execute.d.ts.map +1 -0
- package/dist/deploy/execute.js +280 -0
- package/dist/deploy/execute.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/android.d.ts +37 -0
- package/dist/pipeline/android.d.ts.map +1 -0
- package/dist/pipeline/android.js +96 -0
- package/dist/pipeline/android.js.map +1 -0
- package/dist/pipeline/build.d.ts +69 -0
- package/dist/pipeline/build.d.ts.map +1 -0
- package/dist/pipeline/build.js +138 -0
- package/dist/pipeline/build.js.map +1 -0
- package/dist/pipeline/deploy.d.ts +74 -0
- package/dist/pipeline/deploy.d.ts.map +1 -0
- package/dist/pipeline/deploy.js +198 -0
- package/dist/pipeline/deploy.js.map +1 -0
- package/dist/pipeline/flavour.d.ts +66 -0
- package/dist/pipeline/flavour.d.ts.map +1 -0
- package/dist/pipeline/flavour.js +120 -0
- package/dist/pipeline/flavour.js.map +1 -0
- package/dist/pipeline/native-config.d.ts +43 -0
- package/dist/pipeline/native-config.d.ts.map +1 -0
- package/dist/pipeline/native-config.js +127 -0
- package/dist/pipeline/native-config.js.map +1 -0
- package/dist/pipeline/toolchain.d.ts +80 -0
- package/dist/pipeline/toolchain.d.ts.map +1 -0
- package/dist/pipeline/toolchain.js +146 -0
- package/dist/pipeline/toolchain.js.map +1 -0
- package/dist/pipeline/zip.d.ts +22 -0
- package/dist/pipeline/zip.d.ts.map +1 -0
- package/dist/pipeline/zip.js +188 -0
- package/dist/pipeline/zip.js.map +1 -0
- package/dist/services/cloud.d.ts +58 -0
- package/dist/services/cloud.d.ts.map +1 -0
- package/dist/services/cloud.js +89 -0
- package/dist/services/cloud.js.map +1 -0
- package/dist/utils/config.d.ts +52 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +144 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/exec.d.ts +44 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +136 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/http.d.ts +37 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +137 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/reporter.d.ts +48 -0
- package/dist/utils/reporter.d.ts.map +1 -0
- package/dist/utils/reporter.js +108 -0
- package/dist/utils/reporter.js.map +1 -0
- package/oclif.manifest.json +568 -0
- package/package.json +81 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { openAsBlob } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* HTTP for the CLI.
|
|
6
|
+
*
|
|
7
|
+
* Node 22 has `fetch`, `FormData` and `openAsBlob`, which between them cover
|
|
8
|
+
* everything the CLI was using `axios` and `form-data` for. `openAsBlob` in
|
|
9
|
+
* particular reads lazily, so a 60 MB APK is streamed rather than buffered -
|
|
10
|
+
* the previous `fs.createReadStream` plus `maxBodyLength: Infinity` combination
|
|
11
|
+
* worked, but only because the limit was disabled.
|
|
12
|
+
*/
|
|
13
|
+
export class HttpError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
body;
|
|
16
|
+
constructor(message, status, body) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "HttpError";
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.body = body;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function readBody(response) {
|
|
24
|
+
const text = await response.text();
|
|
25
|
+
if (!text)
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(text);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return text;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Extracts a useful message from whatever shape the server returned. */
|
|
35
|
+
function messageFrom(body, fallback) {
|
|
36
|
+
if (typeof body === "string" && body.length > 0)
|
|
37
|
+
return body;
|
|
38
|
+
if (body && typeof body === "object") {
|
|
39
|
+
const record = body;
|
|
40
|
+
for (const key of ["message", "error", "detail"]) {
|
|
41
|
+
const value = record[key];
|
|
42
|
+
if (typeof value === "string" && value.length > 0)
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return fallback;
|
|
47
|
+
}
|
|
48
|
+
async function request(method, url, options) {
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 30_000);
|
|
51
|
+
try {
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
method,
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
56
|
+
...(options.body === undefined ? {} : { "Content-Type": "application/json" }),
|
|
57
|
+
},
|
|
58
|
+
// The key is omitted entirely rather than set to undefined: a GET with a
|
|
59
|
+
// body is invalid, and some runtimes reject it outright.
|
|
60
|
+
...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
|
|
61
|
+
signal: controller.signal,
|
|
62
|
+
});
|
|
63
|
+
const body = await readBody(response);
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new HttpError(messageFrom(body, `${method} ${url} responded ${response.status}`), response.status, body);
|
|
66
|
+
}
|
|
67
|
+
return body;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof HttpError)
|
|
71
|
+
throw error;
|
|
72
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
73
|
+
throw new Error(`${url} did not respond within the timeout`);
|
|
74
|
+
}
|
|
75
|
+
// A DNS or TLS failure surfaces as an opaque "fetch failed"; say which host.
|
|
76
|
+
if (error instanceof TypeError) {
|
|
77
|
+
throw new Error(`Could not reach ${new URL(url).host}: ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function get(pathname, options) {
|
|
86
|
+
return request("GET", `${options.endpoint}${pathname}`, options);
|
|
87
|
+
}
|
|
88
|
+
export function post(pathname, body, options) {
|
|
89
|
+
return request("POST", `${options.endpoint}${pathname}`, { ...options, body });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Uploads a build artefact as multipart form data.
|
|
93
|
+
*
|
|
94
|
+
* The upload timeout is separate and generous: a release APK on a slow
|
|
95
|
+
* connection legitimately takes minutes, and the 30 second default used for API
|
|
96
|
+
* calls would abort it.
|
|
97
|
+
*/
|
|
98
|
+
export async function uploadArtifact(pathname, filePath, fields, options) {
|
|
99
|
+
if (!fs.existsSync(filePath)) {
|
|
100
|
+
throw new Error(`Nothing to upload: ${filePath} does not exist`);
|
|
101
|
+
}
|
|
102
|
+
const form = new FormData();
|
|
103
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
104
|
+
form.append(key, value);
|
|
105
|
+
}
|
|
106
|
+
const blob = await openAsBlob(filePath);
|
|
107
|
+
form.append(options.fileField ?? "bundle", blob, path.basename(filePath));
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 15 * 60 * 1000);
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(`${options.endpoint}${pathname}`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
// Content-Type is intentionally omitted: fetch sets it along with the
|
|
114
|
+
// multipart boundary, and providing it by hand breaks the boundary.
|
|
115
|
+
headers: { Authorization: `Bearer ${options.apiKey}` },
|
|
116
|
+
body: form,
|
|
117
|
+
signal: controller.signal,
|
|
118
|
+
});
|
|
119
|
+
const body = await readBody(response);
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
throw new HttpError(messageFrom(body, `Upload rejected with ${response.status}`), response.status, body);
|
|
122
|
+
}
|
|
123
|
+
return { status: response.status, body };
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error instanceof HttpError)
|
|
127
|
+
throw error;
|
|
128
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
129
|
+
throw new Error("The upload timed out");
|
|
130
|
+
}
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;GAQG;AAEH,MAAM,OAAO,SAAU,SAAQ,KAAK;IACzB,MAAM,CAAS;IACf,IAAI,CAAU;IAEvB,YAAY,OAAe,EAAE,MAAc,EAAE,IAAa;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAQD,KAAK,UAAU,QAAQ,CAAC,QAAkB;IACxC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,SAAS,WAAW,CAAC,IAAa,EAAE,QAAgB;IAClD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,IAA+B,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC;QAClE,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,MAAyC,EACzC,GAAW,EACX,OAAyC;IAEzC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IAEhF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM;YACN,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM,EAAE;gBACzC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;aAC9E;YACD,yEAAyE;YACzE,yDAAyD;YACzD,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7E,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,SAAS,CACjB,WAAW,CAAC,IAAI,EAAE,GAAG,MAAM,IAAI,GAAG,cAAc,QAAQ,CAAC,MAAM,EAAE,CAAC,EAClE,QAAQ,CAAC,MAAM,EACf,IAAI,CACL,CAAC;QACJ,CAAC;QAED,OAAO,IAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,SAAS;YAAE,MAAM,KAAK,CAAC;QAC5C,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,qCAAqC,CAAC,CAAC;QAC/D,CAAC;QACD,6EAA6E;QAC7E,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,GAAG,CAAI,QAAgB,EAAE,OAAoB;IAC3D,OAAO,OAAO,CAAI,KAAK,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,IAAI,CAAI,QAAgB,EAAE,IAAa,EAAE,OAAoB;IAC3E,OAAO,OAAO,CAAI,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,QAAQ,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AACpF,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,QAAgB,EAChB,MAA8B,EAC9B,OAAiE;IAEjE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,iBAAiB,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE1E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAExF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,QAAQ,EAAE,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,sEAAsE;YACtE,oEAAoE;YACpE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM,EAAE,EAAE;YACtD,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEtC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,SAAS,CACjB,WAAW,CAAC,IAAI,EAAE,wBAAwB,QAAQ,CAAC,MAAM,EAAE,CAAC,EAC5D,QAAQ,CAAC,MAAM,EACf,IAAI,CACL,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,SAAS;YAAE,MAAM,KAAK,CAAC;QAC5C,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress reporting for the deploy pipeline.
|
|
3
|
+
*
|
|
4
|
+
* The previous implementation drove a `cli-progress` MultiBar *and* an `ora`
|
|
5
|
+
* spinner at the same time. Both write ANSI cursor-movement codes to the same
|
|
6
|
+
* terminal, so they overwrote each other and the output was unreadable. It also
|
|
7
|
+
* hard-coded `totalSteps = 9` while skipping steps conditionally, so the
|
|
8
|
+
* numbers were wrong whenever a flag was passed, and `fail()` printed the
|
|
9
|
+
* *previous* step's text as the failure.
|
|
10
|
+
*
|
|
11
|
+
* This reporter is told the steps it will actually run, up front, and owns a
|
|
12
|
+
* single spinner.
|
|
13
|
+
*/
|
|
14
|
+
export interface Step {
|
|
15
|
+
/** Stable identifier, used in JSON output. */
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class Reporter {
|
|
20
|
+
private spinner;
|
|
21
|
+
private steps;
|
|
22
|
+
private index;
|
|
23
|
+
private readonly quiet;
|
|
24
|
+
private startedAt;
|
|
25
|
+
constructor(options?: {
|
|
26
|
+
quiet?: boolean;
|
|
27
|
+
});
|
|
28
|
+
/** Declares the steps that will run. Skipped work is never listed. */
|
|
29
|
+
plan(steps: Step[]): void;
|
|
30
|
+
get total(): number;
|
|
31
|
+
/** Advances to the next planned step. */
|
|
32
|
+
begin(id: string, detail?: string): void;
|
|
33
|
+
/** Replaces the current step's text without advancing. */
|
|
34
|
+
update(detail: string): void;
|
|
35
|
+
/** Records a note under the current step. */
|
|
36
|
+
note(message: string): void;
|
|
37
|
+
/** Marks the current step done. */
|
|
38
|
+
private settle;
|
|
39
|
+
/** Marks the current step as skipped, with the reason. */
|
|
40
|
+
skip(reason: string): void;
|
|
41
|
+
/** Warns without failing. */
|
|
42
|
+
warn(message: string): void;
|
|
43
|
+
/** Completes the run. */
|
|
44
|
+
finish(message: string): void;
|
|
45
|
+
/** Fails the run, attributing the failure to the step that actually failed. */
|
|
46
|
+
fail(message: string): void;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/utils/reporter.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,IAAI;IACnB,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,SAAS,CAAK;gBAEV,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;IAM7C,sEAAsE;IACtE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;IAMzB,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,yCAAyC;IACzC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBxC,0DAA0D;IAC1D,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B,6CAA6C;IAC7C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAc3B,mCAAmC;IACnC,OAAO,CAAC,MAAM;IAMd,0DAA0D;IAC1D,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAY1B,6BAA6B;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAY3B,yBAAyB;IACzB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ7B,+EAA+E;IAC/E,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAW5B"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora, {} from "ora";
|
|
3
|
+
export class Reporter {
|
|
4
|
+
spinner = null;
|
|
5
|
+
steps = [];
|
|
6
|
+
index = -1;
|
|
7
|
+
quiet;
|
|
8
|
+
startedAt = 0;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
// JSON mode and non-interactive terminals get plain lines instead of a
|
|
11
|
+
// spinner, so CI logs stay readable and machine output stays parseable.
|
|
12
|
+
this.quiet = options.quiet ?? false;
|
|
13
|
+
}
|
|
14
|
+
/** Declares the steps that will run. Skipped work is never listed. */
|
|
15
|
+
plan(steps) {
|
|
16
|
+
this.steps = steps;
|
|
17
|
+
this.index = -1;
|
|
18
|
+
this.startedAt = Date.now();
|
|
19
|
+
}
|
|
20
|
+
get total() {
|
|
21
|
+
return this.steps.length;
|
|
22
|
+
}
|
|
23
|
+
/** Advances to the next planned step. */
|
|
24
|
+
begin(id, detail) {
|
|
25
|
+
this.settle();
|
|
26
|
+
const found = this.steps.findIndex((step) => step.id === id);
|
|
27
|
+
this.index = found >= 0 ? found : this.index + 1;
|
|
28
|
+
const step = this.steps[this.index];
|
|
29
|
+
const label = detail ?? step?.label ?? id;
|
|
30
|
+
const text = `${chalk.dim(`[${this.index + 1}/${this.total}]`)} ${label}`;
|
|
31
|
+
if (this.quiet) {
|
|
32
|
+
process.stderr.write(`${text}\n`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.spinner = ora({ text, stream: process.stderr }).start();
|
|
36
|
+
}
|
|
37
|
+
/** Replaces the current step's text without advancing. */
|
|
38
|
+
update(detail) {
|
|
39
|
+
if (!this.spinner)
|
|
40
|
+
return;
|
|
41
|
+
this.spinner.text = `${chalk.dim(`[${this.index + 1}/${this.total}]`)} ${detail}`;
|
|
42
|
+
}
|
|
43
|
+
/** Records a note under the current step. */
|
|
44
|
+
note(message) {
|
|
45
|
+
const line = ` ${chalk.dim("-")} ${chalk.dim(message)}`;
|
|
46
|
+
if (this.spinner) {
|
|
47
|
+
this.spinner.stopAndPersist({
|
|
48
|
+
symbol: chalk.green("✓"),
|
|
49
|
+
text: this.spinner.text,
|
|
50
|
+
});
|
|
51
|
+
process.stderr.write(`${line}\n`);
|
|
52
|
+
this.spinner = null;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
process.stderr.write(`${line}\n`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Marks the current step done. */
|
|
59
|
+
settle() {
|
|
60
|
+
if (!this.spinner)
|
|
61
|
+
return;
|
|
62
|
+
this.spinner.succeed();
|
|
63
|
+
this.spinner = null;
|
|
64
|
+
}
|
|
65
|
+
/** Marks the current step as skipped, with the reason. */
|
|
66
|
+
skip(reason) {
|
|
67
|
+
if (this.spinner) {
|
|
68
|
+
this.spinner.stopAndPersist({
|
|
69
|
+
symbol: chalk.yellow("-"),
|
|
70
|
+
text: `${this.spinner.text} ${chalk.dim(`(skipped: ${reason})`)}`,
|
|
71
|
+
});
|
|
72
|
+
this.spinner = null;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
process.stderr.write(`${chalk.yellow("-")} skipped: ${reason}\n`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Warns without failing. */
|
|
79
|
+
warn(message) {
|
|
80
|
+
const line = `${chalk.yellow("!")} ${message}`;
|
|
81
|
+
if (this.spinner) {
|
|
82
|
+
const text = this.spinner.text;
|
|
83
|
+
this.spinner.stop();
|
|
84
|
+
process.stderr.write(`${line}\n`);
|
|
85
|
+
this.spinner = ora({ text, stream: process.stderr }).start();
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
process.stderr.write(`${line}\n`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Completes the run. */
|
|
92
|
+
finish(message) {
|
|
93
|
+
this.settle();
|
|
94
|
+
const seconds = ((Date.now() - this.startedAt) / 1000).toFixed(1);
|
|
95
|
+
process.stderr.write(`\n${chalk.green("✓")} ${chalk.bold(message)} ${chalk.dim(`(${seconds}s)`)}\n`);
|
|
96
|
+
}
|
|
97
|
+
/** Fails the run, attributing the failure to the step that actually failed. */
|
|
98
|
+
fail(message) {
|
|
99
|
+
const step = this.steps[this.index];
|
|
100
|
+
const where = step ? ` during ${step.label}` : "";
|
|
101
|
+
if (this.spinner) {
|
|
102
|
+
this.spinner.fail(this.spinner.text);
|
|
103
|
+
this.spinner = null;
|
|
104
|
+
}
|
|
105
|
+
process.stderr.write(`\n${chalk.red("✗")} ${chalk.bold(message)}${chalk.dim(where)}\n`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/utils/reporter.ts"],"names":[],"mappings":"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"}
|