@tinybirdco/sdk 0.0.12 → 0.0.13
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/api/build.d.ts +3 -1
- package/dist/api/build.d.ts.map +1 -1
- package/dist/api/build.js +2 -0
- package/dist/api/build.js.map +1 -1
- package/dist/cli/index.js +99 -41
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +88 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +150 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/output.test.d.ts +5 -0
- package/dist/cli/output.test.d.ts.map +1 -0
- package/dist/cli/output.test.js +119 -0
- package/dist/cli/output.test.js.map +1 -0
- package/package.json +1 -1
- package/src/api/build.ts +5 -1
- package/src/cli/index.ts +103 -58
- package/src/cli/output.test.ts +144 -0
- package/src/cli/output.ts +173 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.test.d.ts","sourceRoot":"","sources":["../../src/cli/output.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CLI output utilities
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
5
|
+
import { formatDuration, showResourceChange, showBuildErrors, showBuildSuccess, showBuildFailure, showNoChanges, } from "./output.js";
|
|
6
|
+
describe("output utilities", () => {
|
|
7
|
+
let consoleLogSpy;
|
|
8
|
+
let consoleErrorSpy;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
11
|
+
consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
consoleLogSpy.mockRestore();
|
|
15
|
+
consoleErrorSpy.mockRestore();
|
|
16
|
+
});
|
|
17
|
+
describe("formatDuration", () => {
|
|
18
|
+
it("formats milliseconds for durations under 1 second", () => {
|
|
19
|
+
expect(formatDuration(500)).toBe("500ms");
|
|
20
|
+
expect(formatDuration(0)).toBe("0ms");
|
|
21
|
+
expect(formatDuration(999)).toBe("999ms");
|
|
22
|
+
});
|
|
23
|
+
it("formats seconds for durations 1 second or more", () => {
|
|
24
|
+
expect(formatDuration(1000)).toBe("1.0s");
|
|
25
|
+
expect(formatDuration(1500)).toBe("1.5s");
|
|
26
|
+
expect(formatDuration(2345)).toBe("2.3s");
|
|
27
|
+
expect(formatDuration(10000)).toBe("10.0s");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe("showResourceChange", () => {
|
|
31
|
+
it("shows created resource", () => {
|
|
32
|
+
showResourceChange("events.datasource", "created");
|
|
33
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ events.datasource created");
|
|
34
|
+
});
|
|
35
|
+
it("shows changed resource", () => {
|
|
36
|
+
showResourceChange("top_pages.pipe", "changed");
|
|
37
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ top_pages.pipe changed");
|
|
38
|
+
});
|
|
39
|
+
it("shows deleted resource", () => {
|
|
40
|
+
showResourceChange("old_data.datasource", "deleted");
|
|
41
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ old_data.datasource deleted");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe("showBuildErrors", () => {
|
|
45
|
+
it("shows errors with filename", () => {
|
|
46
|
+
showBuildErrors([
|
|
47
|
+
{ filename: "events.datasource", error: "Invalid column type" },
|
|
48
|
+
]);
|
|
49
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("events.datasource");
|
|
50
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Invalid column type");
|
|
51
|
+
});
|
|
52
|
+
it("shows errors without filename", () => {
|
|
53
|
+
showBuildErrors([{ error: "General build error" }]);
|
|
54
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("General build error");
|
|
55
|
+
});
|
|
56
|
+
it("shows multiple errors", () => {
|
|
57
|
+
showBuildErrors([
|
|
58
|
+
{ filename: "a.datasource", error: "Error A" },
|
|
59
|
+
{ filename: "b.pipe", error: "Error B" },
|
|
60
|
+
]);
|
|
61
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("a.datasource");
|
|
62
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Error A");
|
|
63
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("b.pipe");
|
|
64
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Error B");
|
|
65
|
+
});
|
|
66
|
+
it("handles multi-line errors", () => {
|
|
67
|
+
showBuildErrors([
|
|
68
|
+
{ filename: "test.pipe", error: "Line 1\nLine 2\nLine 3" },
|
|
69
|
+
]);
|
|
70
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("test.pipe");
|
|
71
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 1");
|
|
72
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 2");
|
|
73
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 3");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe("showBuildSuccess", () => {
|
|
77
|
+
it("shows build success with duration in ms", () => {
|
|
78
|
+
showBuildSuccess(500);
|
|
79
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
80
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
81
|
+
expect(call).toContain("✓");
|
|
82
|
+
expect(call).toContain("Build completed in 500ms");
|
|
83
|
+
});
|
|
84
|
+
it("shows build success with duration in seconds", () => {
|
|
85
|
+
showBuildSuccess(2500);
|
|
86
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
87
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
88
|
+
expect(call).toContain("Build completed in 2.5s");
|
|
89
|
+
});
|
|
90
|
+
it("shows rebuild success when isRebuild is true", () => {
|
|
91
|
+
showBuildSuccess(1000, true);
|
|
92
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
93
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
94
|
+
expect(call).toContain("Rebuild completed in 1.0s");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("showBuildFailure", () => {
|
|
98
|
+
it("shows build failure", () => {
|
|
99
|
+
showBuildFailure();
|
|
100
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
101
|
+
const call = consoleErrorSpy.mock.calls[0][0];
|
|
102
|
+
expect(call).toContain("✗");
|
|
103
|
+
expect(call).toContain("Build failed");
|
|
104
|
+
});
|
|
105
|
+
it("shows rebuild failure when isRebuild is true", () => {
|
|
106
|
+
showBuildFailure(true);
|
|
107
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
108
|
+
const call = consoleErrorSpy.mock.calls[0][0];
|
|
109
|
+
expect(call).toContain("Rebuild failed");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe("showNoChanges", () => {
|
|
113
|
+
it("shows no changes message", () => {
|
|
114
|
+
showNoChanges();
|
|
115
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("No changes. Build skipped.");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=output.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../src/cli/output.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/api/build.ts
CHANGED
|
@@ -83,8 +83,10 @@ export interface BuildApiResult {
|
|
|
83
83
|
success: boolean;
|
|
84
84
|
/** Result status from API */
|
|
85
85
|
result: "success" | "failed" | "no_changes";
|
|
86
|
-
/** Error message if failed */
|
|
86
|
+
/** Error message if failed (formatted for display) */
|
|
87
87
|
error?: string;
|
|
88
|
+
/** Detailed errors array from the API */
|
|
89
|
+
errors?: BuildError[];
|
|
88
90
|
/** Number of datasources deployed */
|
|
89
91
|
datasourceCount: number;
|
|
90
92
|
/** Number of pipes deployed */
|
|
@@ -233,6 +235,7 @@ export async function buildToTinybird(
|
|
|
233
235
|
success: false,
|
|
234
236
|
result: "failed",
|
|
235
237
|
error: formatErrors(),
|
|
238
|
+
errors: body.errors,
|
|
236
239
|
datasourceCount: resources.datasources.length,
|
|
237
240
|
pipeCount: resources.pipes.length,
|
|
238
241
|
connectionCount: resources.connections?.length ?? 0,
|
|
@@ -245,6 +248,7 @@ export async function buildToTinybird(
|
|
|
245
248
|
success: false,
|
|
246
249
|
result: "failed",
|
|
247
250
|
error: formatErrors(),
|
|
251
|
+
errors: body.errors,
|
|
248
252
|
datasourceCount: resources.datasources.length,
|
|
249
253
|
pipeCount: resources.pipes.length,
|
|
250
254
|
connectionCount: resources.connections?.length ?? 0,
|
package/src/cli/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
hasTinybirdSdkDependency,
|
|
32
32
|
} from "./utils/package-manager.js";
|
|
33
33
|
import type { DevMode } from "./config.js";
|
|
34
|
+
import { output } from "./output.js";
|
|
34
35
|
|
|
35
36
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
36
37
|
const packageJson = JSON.parse(
|
|
@@ -38,13 +39,6 @@ const packageJson = JSON.parse(
|
|
|
38
39
|
) as { version: string };
|
|
39
40
|
const VERSION = packageJson.version;
|
|
40
41
|
|
|
41
|
-
/**
|
|
42
|
-
* Format timestamp for console output
|
|
43
|
-
*/
|
|
44
|
-
function formatTime(): string {
|
|
45
|
-
return new Date().toLocaleTimeString("en-US", { hour12: false });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
42
|
/**
|
|
49
43
|
* Create and configure the CLI
|
|
50
44
|
*/
|
|
@@ -193,24 +187,24 @@ function createCli(): Command {
|
|
|
193
187
|
}
|
|
194
188
|
|
|
195
189
|
const modeLabel = devModeOverride === "local" ? " (local)" : "";
|
|
196
|
-
|
|
190
|
+
output.highlight(`Building${modeLabel}...`);
|
|
197
191
|
|
|
198
192
|
const result = await runBuild({
|
|
199
193
|
dryRun: options.dryRun,
|
|
200
194
|
devModeOverride,
|
|
201
195
|
});
|
|
202
196
|
|
|
203
|
-
if (!result.success) {
|
|
204
|
-
console.error(`Error: ${result.error}`);
|
|
205
|
-
process.exit(1);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
197
|
const { build, deploy } = result;
|
|
209
198
|
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
199
|
+
if (!result.success) {
|
|
200
|
+
// Show detailed errors if available
|
|
201
|
+
if (deploy?.errors && deploy.errors.length > 0) {
|
|
202
|
+
output.showBuildErrors(deploy.errors);
|
|
203
|
+
} else if (result.error) {
|
|
204
|
+
output.error(result.error);
|
|
205
|
+
}
|
|
206
|
+
output.showBuildFailure();
|
|
207
|
+
process.exit(1);
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
if (options.dryRun) {
|
|
@@ -230,15 +224,40 @@ function createCli(): Command {
|
|
|
230
224
|
console.log(pipe.content);
|
|
231
225
|
});
|
|
232
226
|
}
|
|
227
|
+
output.showBuildSuccess(result.durationMs);
|
|
233
228
|
} else if (deploy) {
|
|
234
229
|
if (deploy.result === "no_changes") {
|
|
235
|
-
|
|
230
|
+
output.showNoChanges();
|
|
236
231
|
} else {
|
|
237
|
-
|
|
232
|
+
// Show datasource changes
|
|
233
|
+
if (deploy.datasources) {
|
|
234
|
+
for (const name of deploy.datasources.created) {
|
|
235
|
+
output.showResourceChange(`${name}.datasource`, "created");
|
|
236
|
+
}
|
|
237
|
+
for (const name of deploy.datasources.changed) {
|
|
238
|
+
output.showResourceChange(`${name}.datasource`, "changed");
|
|
239
|
+
}
|
|
240
|
+
for (const name of deploy.datasources.deleted) {
|
|
241
|
+
output.showResourceChange(`${name}.datasource`, "deleted");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Show pipe changes
|
|
246
|
+
if (deploy.pipes) {
|
|
247
|
+
for (const name of deploy.pipes.created) {
|
|
248
|
+
output.showResourceChange(`${name}.pipe`, "created");
|
|
249
|
+
}
|
|
250
|
+
for (const name of deploy.pipes.changed) {
|
|
251
|
+
output.showResourceChange(`${name}.pipe`, "changed");
|
|
252
|
+
}
|
|
253
|
+
for (const name of deploy.pipes.deleted) {
|
|
254
|
+
output.showResourceChange(`${name}.pipe`, "deleted");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
output.showBuildSuccess(result.durationMs);
|
|
238
259
|
}
|
|
239
260
|
}
|
|
240
|
-
|
|
241
|
-
console.log(`\n[${formatTime()}] Done in ${result.durationMs}ms`);
|
|
242
261
|
});
|
|
243
262
|
|
|
244
263
|
// Deploy command
|
|
@@ -253,24 +272,24 @@ function createCli(): Command {
|
|
|
253
272
|
process.env.TINYBIRD_DEBUG = "1";
|
|
254
273
|
}
|
|
255
274
|
|
|
256
|
-
|
|
275
|
+
output.highlight("Deploying to main workspace...");
|
|
257
276
|
|
|
258
277
|
const result = await runDeploy({
|
|
259
278
|
dryRun: options.dryRun,
|
|
260
279
|
check: options.check,
|
|
261
280
|
});
|
|
262
281
|
|
|
263
|
-
if (!result.success) {
|
|
264
|
-
console.error(`Error: ${result.error}`);
|
|
265
|
-
process.exit(1);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
282
|
const { build, deploy } = result;
|
|
269
283
|
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
284
|
+
if (!result.success) {
|
|
285
|
+
// Show detailed errors if available
|
|
286
|
+
if (deploy?.errors && deploy.errors.length > 0) {
|
|
287
|
+
output.showBuildErrors(deploy.errors);
|
|
288
|
+
} else if (result.error) {
|
|
289
|
+
output.error(result.error);
|
|
290
|
+
}
|
|
291
|
+
output.showBuildFailure();
|
|
292
|
+
process.exit(1);
|
|
274
293
|
}
|
|
275
294
|
|
|
276
295
|
if (options.dryRun) {
|
|
@@ -290,17 +309,43 @@ function createCli(): Command {
|
|
|
290
309
|
console.log(pipe.content);
|
|
291
310
|
});
|
|
292
311
|
}
|
|
312
|
+
output.showBuildSuccess(result.durationMs);
|
|
293
313
|
} else if (options.check) {
|
|
294
314
|
console.log("\n[Check] Resources validated with Tinybird API");
|
|
315
|
+
output.showBuildSuccess(result.durationMs);
|
|
295
316
|
} else if (deploy) {
|
|
296
317
|
if (deploy.result === "no_changes") {
|
|
297
|
-
|
|
318
|
+
output.showNoChanges();
|
|
298
319
|
} else {
|
|
299
|
-
|
|
320
|
+
// Show datasource changes
|
|
321
|
+
if (deploy.datasources) {
|
|
322
|
+
for (const name of deploy.datasources.created) {
|
|
323
|
+
output.showResourceChange(`${name}.datasource`, "created");
|
|
324
|
+
}
|
|
325
|
+
for (const name of deploy.datasources.changed) {
|
|
326
|
+
output.showResourceChange(`${name}.datasource`, "changed");
|
|
327
|
+
}
|
|
328
|
+
for (const name of deploy.datasources.deleted) {
|
|
329
|
+
output.showResourceChange(`${name}.datasource`, "deleted");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Show pipe changes
|
|
334
|
+
if (deploy.pipes) {
|
|
335
|
+
for (const name of deploy.pipes.created) {
|
|
336
|
+
output.showResourceChange(`${name}.pipe`, "created");
|
|
337
|
+
}
|
|
338
|
+
for (const name of deploy.pipes.changed) {
|
|
339
|
+
output.showResourceChange(`${name}.pipe`, "changed");
|
|
340
|
+
}
|
|
341
|
+
for (const name of deploy.pipes.deleted) {
|
|
342
|
+
output.showResourceChange(`${name}.pipe`, "deleted");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
output.showBuildSuccess(result.durationMs);
|
|
300
347
|
}
|
|
301
348
|
}
|
|
302
|
-
|
|
303
|
-
console.log(`\n[${formatTime()}] Done in ${result.durationMs}ms`);
|
|
304
349
|
});
|
|
305
350
|
|
|
306
351
|
// Dev command
|
|
@@ -318,9 +363,6 @@ function createCli(): Command {
|
|
|
318
363
|
devModeOverride = "branch";
|
|
319
364
|
}
|
|
320
365
|
|
|
321
|
-
console.log(`tinybird dev v${VERSION}`);
|
|
322
|
-
console.log("Loading config from tinybird.json...\n");
|
|
323
|
-
|
|
324
366
|
try {
|
|
325
367
|
const controller = await runDev({
|
|
326
368
|
devModeOverride,
|
|
@@ -367,11 +409,18 @@ function createCli(): Command {
|
|
|
367
409
|
}
|
|
368
410
|
},
|
|
369
411
|
onBuildStart: () => {
|
|
370
|
-
|
|
412
|
+
output.highlight("Building...");
|
|
371
413
|
},
|
|
372
414
|
onBuildComplete: (result) => {
|
|
373
415
|
if (!result.success) {
|
|
374
|
-
|
|
416
|
+
// Show detailed errors if available
|
|
417
|
+
const { deploy } = result;
|
|
418
|
+
if (deploy?.errors && deploy.errors.length > 0) {
|
|
419
|
+
output.showBuildErrors(deploy.errors);
|
|
420
|
+
} else if (result.error) {
|
|
421
|
+
output.error(result.error);
|
|
422
|
+
}
|
|
423
|
+
output.showBuildFailure(true);
|
|
375
424
|
return;
|
|
376
425
|
}
|
|
377
426
|
|
|
@@ -379,56 +428,52 @@ function createCli(): Command {
|
|
|
379
428
|
|
|
380
429
|
if (deploy) {
|
|
381
430
|
if (deploy.result === "no_changes") {
|
|
382
|
-
|
|
431
|
+
output.showNoChanges();
|
|
383
432
|
} else {
|
|
384
|
-
console.log(
|
|
385
|
-
`[${formatTime()}] Built in ${result.durationMs}ms`
|
|
386
|
-
);
|
|
387
|
-
|
|
388
433
|
// Show datasource changes
|
|
389
434
|
if (deploy.datasources) {
|
|
390
435
|
for (const name of deploy.datasources.created) {
|
|
391
|
-
|
|
436
|
+
output.showResourceChange(`${name}.datasource`, "created");
|
|
392
437
|
}
|
|
393
438
|
for (const name of deploy.datasources.changed) {
|
|
394
|
-
|
|
439
|
+
output.showResourceChange(`${name}.datasource`, "changed");
|
|
395
440
|
}
|
|
396
441
|
for (const name of deploy.datasources.deleted) {
|
|
397
|
-
|
|
442
|
+
output.showResourceChange(`${name}.datasource`, "deleted");
|
|
398
443
|
}
|
|
399
444
|
}
|
|
400
445
|
|
|
401
446
|
// Show pipe changes
|
|
402
447
|
if (deploy.pipes) {
|
|
403
448
|
for (const name of deploy.pipes.created) {
|
|
404
|
-
|
|
449
|
+
output.showResourceChange(`${name}.pipe`, "created");
|
|
405
450
|
}
|
|
406
451
|
for (const name of deploy.pipes.changed) {
|
|
407
|
-
|
|
452
|
+
output.showResourceChange(`${name}.pipe`, "changed");
|
|
408
453
|
}
|
|
409
454
|
for (const name of deploy.pipes.deleted) {
|
|
410
|
-
|
|
455
|
+
output.showResourceChange(`${name}.pipe`, "deleted");
|
|
411
456
|
}
|
|
412
457
|
}
|
|
458
|
+
|
|
459
|
+
output.showBuildSuccess(result.durationMs, true);
|
|
413
460
|
}
|
|
414
461
|
}
|
|
415
462
|
},
|
|
416
463
|
onSchemaValidation: (validation) => {
|
|
417
464
|
if (validation.issues.length > 0) {
|
|
418
|
-
|
|
465
|
+
output.info("Schema validation:");
|
|
419
466
|
for (const issue of validation.issues) {
|
|
420
467
|
if (issue.type === "error") {
|
|
421
|
-
|
|
422
|
-
` ERROR [${issue.pipeName}]: ${issue.message}`
|
|
423
|
-
);
|
|
468
|
+
output.error(` ERROR [${issue.pipeName}]: ${issue.message}`);
|
|
424
469
|
} else {
|
|
425
|
-
|
|
470
|
+
output.warning(` WARN [${issue.pipeName}]: ${issue.message}`);
|
|
426
471
|
}
|
|
427
472
|
}
|
|
428
473
|
}
|
|
429
474
|
},
|
|
430
|
-
onError: (
|
|
431
|
-
|
|
475
|
+
onError: (err) => {
|
|
476
|
+
output.error(err.message);
|
|
432
477
|
},
|
|
433
478
|
});
|
|
434
479
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CLI output utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
6
|
+
import {
|
|
7
|
+
formatDuration,
|
|
8
|
+
showResourceChange,
|
|
9
|
+
showBuildErrors,
|
|
10
|
+
showBuildSuccess,
|
|
11
|
+
showBuildFailure,
|
|
12
|
+
showNoChanges,
|
|
13
|
+
} from "./output.js";
|
|
14
|
+
|
|
15
|
+
describe("output utilities", () => {
|
|
16
|
+
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
|
|
17
|
+
let consoleErrorSpy: ReturnType<typeof vi.spyOn>;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
21
|
+
consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
consoleLogSpy.mockRestore();
|
|
26
|
+
consoleErrorSpy.mockRestore();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("formatDuration", () => {
|
|
30
|
+
it("formats milliseconds for durations under 1 second", () => {
|
|
31
|
+
expect(formatDuration(500)).toBe("500ms");
|
|
32
|
+
expect(formatDuration(0)).toBe("0ms");
|
|
33
|
+
expect(formatDuration(999)).toBe("999ms");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("formats seconds for durations 1 second or more", () => {
|
|
37
|
+
expect(formatDuration(1000)).toBe("1.0s");
|
|
38
|
+
expect(formatDuration(1500)).toBe("1.5s");
|
|
39
|
+
expect(formatDuration(2345)).toBe("2.3s");
|
|
40
|
+
expect(formatDuration(10000)).toBe("10.0s");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("showResourceChange", () => {
|
|
45
|
+
it("shows created resource", () => {
|
|
46
|
+
showResourceChange("events.datasource", "created");
|
|
47
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ events.datasource created");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("shows changed resource", () => {
|
|
51
|
+
showResourceChange("top_pages.pipe", "changed");
|
|
52
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ top_pages.pipe changed");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("shows deleted resource", () => {
|
|
56
|
+
showResourceChange("old_data.datasource", "deleted");
|
|
57
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("✓ old_data.datasource deleted");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("showBuildErrors", () => {
|
|
62
|
+
it("shows errors with filename", () => {
|
|
63
|
+
showBuildErrors([
|
|
64
|
+
{ filename: "events.datasource", error: "Invalid column type" },
|
|
65
|
+
]);
|
|
66
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("events.datasource");
|
|
67
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Invalid column type");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("shows errors without filename", () => {
|
|
71
|
+
showBuildErrors([{ error: "General build error" }]);
|
|
72
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("General build error");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("shows multiple errors", () => {
|
|
76
|
+
showBuildErrors([
|
|
77
|
+
{ filename: "a.datasource", error: "Error A" },
|
|
78
|
+
{ filename: "b.pipe", error: "Error B" },
|
|
79
|
+
]);
|
|
80
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("a.datasource");
|
|
81
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Error A");
|
|
82
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("b.pipe");
|
|
83
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Error B");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("handles multi-line errors", () => {
|
|
87
|
+
showBuildErrors([
|
|
88
|
+
{ filename: "test.pipe", error: "Line 1\nLine 2\nLine 3" },
|
|
89
|
+
]);
|
|
90
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("test.pipe");
|
|
91
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 1");
|
|
92
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 2");
|
|
93
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 3");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("showBuildSuccess", () => {
|
|
98
|
+
it("shows build success with duration in ms", () => {
|
|
99
|
+
showBuildSuccess(500);
|
|
100
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
101
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
102
|
+
expect(call).toContain("✓");
|
|
103
|
+
expect(call).toContain("Build completed in 500ms");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("shows build success with duration in seconds", () => {
|
|
107
|
+
showBuildSuccess(2500);
|
|
108
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
109
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
110
|
+
expect(call).toContain("Build completed in 2.5s");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("shows rebuild success when isRebuild is true", () => {
|
|
114
|
+
showBuildSuccess(1000, true);
|
|
115
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
116
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
117
|
+
expect(call).toContain("Rebuild completed in 1.0s");
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("showBuildFailure", () => {
|
|
122
|
+
it("shows build failure", () => {
|
|
123
|
+
showBuildFailure();
|
|
124
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
125
|
+
const call = consoleErrorSpy.mock.calls[0][0];
|
|
126
|
+
expect(call).toContain("✗");
|
|
127
|
+
expect(call).toContain("Build failed");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("shows rebuild failure when isRebuild is true", () => {
|
|
131
|
+
showBuildFailure(true);
|
|
132
|
+
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
133
|
+
const call = consoleErrorSpy.mock.calls[0][0];
|
|
134
|
+
expect(call).toContain("Rebuild failed");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("showNoChanges", () => {
|
|
139
|
+
it("shows no changes message", () => {
|
|
140
|
+
showNoChanges();
|
|
141
|
+
expect(consoleLogSpy).toHaveBeenCalledWith("No changes. Build skipped.");
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|