@tinybirdco/sdk 0.0.11 → 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/branches.d.ts +12 -1
- package/dist/api/branches.d.ts.map +1 -1
- package/dist/api/branches.js +21 -2
- package/dist/api/branches.js.map +1 -1
- package/dist/api/branches.test.js +95 -5
- package/dist/api/branches.test.js.map +1 -1
- 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/api/local.d.ts +15 -0
- package/dist/api/local.d.ts.map +1 -1
- package/dist/api/local.js +52 -0
- package/dist/api/local.js.map +1 -1
- package/dist/api/local.test.js +80 -1
- package/dist/api/local.test.js.map +1 -1
- package/dist/cli/commands/clear.d.ts +37 -0
- package/dist/cli/commands/clear.d.ts.map +1 -0
- package/dist/cli/commands/clear.js +141 -0
- package/dist/cli/commands/clear.js.map +1 -0
- package/dist/cli/index.js +144 -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/branches.test.ts +116 -4
- package/src/api/branches.ts +28 -2
- package/src/api/build.ts +5 -1
- package/src/api/local.test.ts +106 -0
- package/src/api/local.ts +77 -0
- package/src/cli/commands/clear.ts +194 -0
- package/src/cli/index.ts +159 -58
- package/src/cli/output.test.ts +144 -0
- package/src/cli/output.ts +173 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console output utilities with color support
|
|
3
|
+
* Provides consistent formatting similar to the Python CLI
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Output a success message (green)
|
|
7
|
+
*/
|
|
8
|
+
export declare function success(message: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Output an error message (red)
|
|
11
|
+
*/
|
|
12
|
+
export declare function error(message: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Output a warning message (yellow/orange)
|
|
15
|
+
*/
|
|
16
|
+
export declare function warning(message: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Output an info message (default color)
|
|
19
|
+
*/
|
|
20
|
+
export declare function info(message: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Output a highlighted message (blue)
|
|
23
|
+
*/
|
|
24
|
+
export declare function highlight(message: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Output a gray message (dimmed)
|
|
27
|
+
*/
|
|
28
|
+
export declare function gray(message: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Output a bold message
|
|
31
|
+
*/
|
|
32
|
+
export declare function bold(message: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Format a timestamp for console output
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatTime(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Format duration in human-readable format
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatDuration(ms: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* Show a resource change (checkmark + path + status)
|
|
43
|
+
*/
|
|
44
|
+
export declare function showResourceChange(path: string, status: "created" | "changed" | "deleted"): void;
|
|
45
|
+
/**
|
|
46
|
+
* Show a warning for a resource
|
|
47
|
+
*/
|
|
48
|
+
export declare function showResourceWarning(level: string, resource: string, message: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Show build errors in formatted style
|
|
51
|
+
*/
|
|
52
|
+
export declare function showBuildErrors(errors: Array<{
|
|
53
|
+
filename?: string;
|
|
54
|
+
error: string;
|
|
55
|
+
}>): void;
|
|
56
|
+
/**
|
|
57
|
+
* Show final build success message
|
|
58
|
+
*/
|
|
59
|
+
export declare function showBuildSuccess(durationMs: number, isRebuild?: boolean): void;
|
|
60
|
+
/**
|
|
61
|
+
* Show final build failure message
|
|
62
|
+
*/
|
|
63
|
+
export declare function showBuildFailure(isRebuild?: boolean): void;
|
|
64
|
+
/**
|
|
65
|
+
* Show no changes message
|
|
66
|
+
*/
|
|
67
|
+
export declare function showNoChanges(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Output object containing all output functions
|
|
70
|
+
*/
|
|
71
|
+
export declare const output: {
|
|
72
|
+
success: typeof success;
|
|
73
|
+
error: typeof error;
|
|
74
|
+
warning: typeof warning;
|
|
75
|
+
info: typeof info;
|
|
76
|
+
highlight: typeof highlight;
|
|
77
|
+
gray: typeof gray;
|
|
78
|
+
bold: typeof bold;
|
|
79
|
+
formatTime: typeof formatTime;
|
|
80
|
+
formatDuration: typeof formatDuration;
|
|
81
|
+
showResourceChange: typeof showResourceChange;
|
|
82
|
+
showResourceWarning: typeof showResourceWarning;
|
|
83
|
+
showBuildErrors: typeof showBuildErrors;
|
|
84
|
+
showBuildSuccess: typeof showBuildSuccess;
|
|
85
|
+
showBuildFailure: typeof showBuildFailure;
|
|
86
|
+
showNoChanges: typeof showNoChanges;
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GACxC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAczF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,IAAI,CAG5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,UAAQ,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;CAgBlB,CAAC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console output utilities with color support
|
|
3
|
+
* Provides consistent formatting similar to the Python CLI
|
|
4
|
+
*/
|
|
5
|
+
// ANSI color codes
|
|
6
|
+
const colors = {
|
|
7
|
+
reset: "\x1b[0m",
|
|
8
|
+
bold: "\x1b[1m",
|
|
9
|
+
red: "\x1b[91m",
|
|
10
|
+
green: "\x1b[92m",
|
|
11
|
+
yellow: "\x1b[38;5;208m",
|
|
12
|
+
blue: "\x1b[94m",
|
|
13
|
+
gray: "\x1b[90m",
|
|
14
|
+
};
|
|
15
|
+
// Check if colors should be disabled
|
|
16
|
+
const noColor = process.env.NO_COLOR !== undefined || !process.stdout.isTTY;
|
|
17
|
+
function colorize(text, color) {
|
|
18
|
+
if (noColor)
|
|
19
|
+
return text;
|
|
20
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Output a success message (green)
|
|
24
|
+
*/
|
|
25
|
+
export function success(message) {
|
|
26
|
+
console.log(colorize(message, "green"));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Output an error message (red)
|
|
30
|
+
*/
|
|
31
|
+
export function error(message) {
|
|
32
|
+
console.error(colorize(message, "red"));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Output a warning message (yellow/orange)
|
|
36
|
+
*/
|
|
37
|
+
export function warning(message) {
|
|
38
|
+
console.log(colorize(message, "yellow"));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Output an info message (default color)
|
|
42
|
+
*/
|
|
43
|
+
export function info(message) {
|
|
44
|
+
console.log(message);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Output a highlighted message (blue)
|
|
48
|
+
*/
|
|
49
|
+
export function highlight(message) {
|
|
50
|
+
console.log(colorize(message, "blue"));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Output a gray message (dimmed)
|
|
54
|
+
*/
|
|
55
|
+
export function gray(message) {
|
|
56
|
+
console.log(colorize(message, "gray"));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Output a bold message
|
|
60
|
+
*/
|
|
61
|
+
export function bold(message) {
|
|
62
|
+
console.log(colorize(message, "bold"));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Format a timestamp for console output
|
|
66
|
+
*/
|
|
67
|
+
export function formatTime() {
|
|
68
|
+
return new Date().toLocaleTimeString("en-US", { hour12: false });
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Format duration in human-readable format
|
|
72
|
+
*/
|
|
73
|
+
export function formatDuration(ms) {
|
|
74
|
+
if (ms < 1000) {
|
|
75
|
+
return `${ms}ms`;
|
|
76
|
+
}
|
|
77
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Show a resource change (checkmark + path + status)
|
|
81
|
+
*/
|
|
82
|
+
export function showResourceChange(path, status) {
|
|
83
|
+
console.log(`✓ ${path} ${status}`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Show a warning for a resource
|
|
87
|
+
*/
|
|
88
|
+
export function showResourceWarning(level, resource, message) {
|
|
89
|
+
warning(`△ ${level}: ${resource}: ${message}`);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Show build errors in formatted style
|
|
93
|
+
*/
|
|
94
|
+
export function showBuildErrors(errors) {
|
|
95
|
+
for (const err of errors) {
|
|
96
|
+
if (err.filename) {
|
|
97
|
+
error(`${err.filename}`);
|
|
98
|
+
// Indent the error message
|
|
99
|
+
const lines = err.error.split("\n");
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
error(` ${line}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
error(err.error);
|
|
106
|
+
}
|
|
107
|
+
console.log(); // Empty line between errors
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Show final build success message
|
|
112
|
+
*/
|
|
113
|
+
export function showBuildSuccess(durationMs, isRebuild = false) {
|
|
114
|
+
const prefix = isRebuild ? "Rebuild" : "Build";
|
|
115
|
+
success(`\n✓ ${prefix} completed in ${formatDuration(durationMs)}`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Show final build failure message
|
|
119
|
+
*/
|
|
120
|
+
export function showBuildFailure(isRebuild = false) {
|
|
121
|
+
const prefix = isRebuild ? "Rebuild" : "Build";
|
|
122
|
+
error(`\n✗ ${prefix} failed`);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Show no changes message
|
|
126
|
+
*/
|
|
127
|
+
export function showNoChanges() {
|
|
128
|
+
info("No changes. Build skipped.");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Output object containing all output functions
|
|
132
|
+
*/
|
|
133
|
+
export const output = {
|
|
134
|
+
success,
|
|
135
|
+
error,
|
|
136
|
+
warning,
|
|
137
|
+
info,
|
|
138
|
+
highlight,
|
|
139
|
+
gray,
|
|
140
|
+
bold,
|
|
141
|
+
formatTime,
|
|
142
|
+
formatDuration,
|
|
143
|
+
showResourceChange,
|
|
144
|
+
showResourceWarning,
|
|
145
|
+
showBuildErrors,
|
|
146
|
+
showBuildSuccess,
|
|
147
|
+
showBuildFailure,
|
|
148
|
+
showNoChanges,
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -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/branches.test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
deleteBranch,
|
|
8
8
|
branchExists,
|
|
9
9
|
getOrCreateBranch,
|
|
10
|
+
clearBranch,
|
|
10
11
|
type BranchApiConfig,
|
|
11
12
|
} from "./branches.js";
|
|
12
13
|
|
|
@@ -271,16 +272,39 @@ describe("Branch API client", () => {
|
|
|
271
272
|
|
|
272
273
|
describe("deleteBranch", () => {
|
|
273
274
|
it("deletes a branch successfully", async () => {
|
|
275
|
+
const mockBranch = {
|
|
276
|
+
id: "branch-123",
|
|
277
|
+
name: "my-feature",
|
|
278
|
+
token: "p.branch-token",
|
|
279
|
+
created_at: "2024-01-01T00:00:00Z",
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// 1. getBranch to get the ID
|
|
283
|
+
mockFetch.mockResolvedValueOnce({
|
|
284
|
+
ok: true,
|
|
285
|
+
json: () => Promise.resolve(mockBranch),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// 2. DELETE the branch by ID
|
|
274
289
|
mockFetch.mockResolvedValueOnce({
|
|
275
290
|
ok: true,
|
|
276
291
|
});
|
|
277
292
|
|
|
278
293
|
await deleteBranch(config, "my-feature");
|
|
279
294
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
295
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
296
|
+
|
|
297
|
+
// First call: get branch
|
|
298
|
+
const [getUrl, getInit] = mockFetch.mock.calls[0];
|
|
299
|
+
const getParsed = expectFromParam(getUrl);
|
|
300
|
+
expect(getParsed.pathname).toBe("/v0/environments/my-feature");
|
|
301
|
+
expect(getInit.method).toBe("GET");
|
|
302
|
+
|
|
303
|
+
// Second call: delete branch by ID
|
|
304
|
+
const [deleteUrl, deleteInit] = mockFetch.mock.calls[1];
|
|
305
|
+
const deleteParsed = expectFromParam(deleteUrl);
|
|
306
|
+
expect(deleteParsed.pathname).toBe("/v0/environments/branch-123");
|
|
307
|
+
expect(deleteInit).toEqual({
|
|
284
308
|
method: "DELETE",
|
|
285
309
|
headers: {
|
|
286
310
|
Authorization: "Bearer p.test-token",
|
|
@@ -382,4 +406,92 @@ describe("Branch API client", () => {
|
|
|
382
406
|
expect(mockFetch).toHaveBeenCalledTimes(4);
|
|
383
407
|
});
|
|
384
408
|
});
|
|
409
|
+
|
|
410
|
+
describe("clearBranch", () => {
|
|
411
|
+
it("clears a branch by deleting and recreating it", async () => {
|
|
412
|
+
const existingBranch = {
|
|
413
|
+
id: "branch-old",
|
|
414
|
+
name: "my-feature",
|
|
415
|
+
token: "p.old-token",
|
|
416
|
+
created_at: "2024-01-01T00:00:00Z",
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const newBranch = {
|
|
420
|
+
id: "branch-new",
|
|
421
|
+
name: "my-feature",
|
|
422
|
+
token: "p.new-token",
|
|
423
|
+
created_at: "2024-01-02T00:00:00Z",
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// 1. GET branch to get ID (for delete)
|
|
427
|
+
mockFetch.mockResolvedValueOnce({
|
|
428
|
+
ok: true,
|
|
429
|
+
json: () => Promise.resolve(existingBranch),
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// 2. DELETE branch by ID
|
|
433
|
+
mockFetch.mockResolvedValueOnce({
|
|
434
|
+
ok: true,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// 3. POST to /v1/environments returns a job
|
|
438
|
+
mockFetch.mockResolvedValueOnce({
|
|
439
|
+
ok: true,
|
|
440
|
+
json: () => Promise.resolve({
|
|
441
|
+
job: { id: "job-789", status: "waiting" },
|
|
442
|
+
workspace: { id: "ws-789" },
|
|
443
|
+
}),
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// 4. Poll job - done
|
|
447
|
+
mockFetch.mockResolvedValueOnce({
|
|
448
|
+
ok: true,
|
|
449
|
+
json: () => Promise.resolve({ id: "job-789", status: "done" }),
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// 5. Get branch with token (after create)
|
|
453
|
+
mockFetch.mockResolvedValueOnce({
|
|
454
|
+
ok: true,
|
|
455
|
+
json: () => Promise.resolve(newBranch),
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const result = await clearBranch(config, "my-feature");
|
|
459
|
+
|
|
460
|
+
expect(mockFetch).toHaveBeenCalledTimes(5);
|
|
461
|
+
|
|
462
|
+
// Verify get was called first
|
|
463
|
+
const [getUrl, getInit] = mockFetch.mock.calls[0];
|
|
464
|
+
const getParsed = expectFromParam(getUrl);
|
|
465
|
+
expect(getParsed.pathname).toBe("/v0/environments/my-feature");
|
|
466
|
+
expect(getInit.method).toBe("GET");
|
|
467
|
+
|
|
468
|
+
// Verify delete was called with ID
|
|
469
|
+
const [deleteUrl, deleteInit] = mockFetch.mock.calls[1];
|
|
470
|
+
const deleteParsed = expectFromParam(deleteUrl);
|
|
471
|
+
expect(deleteParsed.pathname).toBe("/v0/environments/branch-old");
|
|
472
|
+
expect(deleteInit.method).toBe("DELETE");
|
|
473
|
+
|
|
474
|
+
// Verify create was called
|
|
475
|
+
const [createUrl, createInit] = mockFetch.mock.calls[2];
|
|
476
|
+
const createParsed = expectFromParam(createUrl);
|
|
477
|
+
expect(createParsed.pathname).toBe("/v1/environments");
|
|
478
|
+
expect(createParsed.searchParams.get("name")).toBe("my-feature");
|
|
479
|
+
expect(createInit.method).toBe("POST");
|
|
480
|
+
|
|
481
|
+
expect(result).toEqual(newBranch);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it("throws BranchApiError when branch does not exist", async () => {
|
|
485
|
+
mockFetch.mockResolvedValueOnce({
|
|
486
|
+
ok: false,
|
|
487
|
+
status: 404,
|
|
488
|
+
statusText: "Not Found",
|
|
489
|
+
text: () => Promise.resolve("Branch not found"),
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
await expect(clearBranch(config, "nonexistent")).rejects.toThrow(
|
|
493
|
+
BranchApiError
|
|
494
|
+
);
|
|
495
|
+
});
|
|
496
|
+
});
|
|
385
497
|
});
|
package/src/api/branches.ts
CHANGED
|
@@ -264,7 +264,10 @@ export async function getBranch(
|
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
266
|
* Delete a branch
|
|
267
|
-
* DELETE /
|
|
267
|
+
* DELETE /v0/environments/{id}
|
|
268
|
+
*
|
|
269
|
+
* Note: The API requires the branch ID, not name. This function first
|
|
270
|
+
* fetches the branch to get its ID, then deletes it.
|
|
268
271
|
*
|
|
269
272
|
* @param config - API configuration
|
|
270
273
|
* @param name - Branch name to delete
|
|
@@ -273,7 +276,10 @@ export async function deleteBranch(
|
|
|
273
276
|
config: BranchApiConfig,
|
|
274
277
|
name: string
|
|
275
278
|
): Promise<void> {
|
|
276
|
-
|
|
279
|
+
// First get the branch to find its ID
|
|
280
|
+
const branch = await getBranch(config, name);
|
|
281
|
+
|
|
282
|
+
const url = new URL(`/v0/environments/${branch.id}`, config.baseUrl);
|
|
277
283
|
|
|
278
284
|
const response = await tinybirdFetch(url.toString(), {
|
|
279
285
|
method: "DELETE",
|
|
@@ -334,3 +340,23 @@ export async function getOrCreateBranch(
|
|
|
334
340
|
throw error;
|
|
335
341
|
}
|
|
336
342
|
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Clear a branch by deleting and recreating it
|
|
346
|
+
*
|
|
347
|
+
* @param config - API configuration
|
|
348
|
+
* @param name - Branch name to clear
|
|
349
|
+
* @returns The recreated branch with token
|
|
350
|
+
*/
|
|
351
|
+
export async function clearBranch(
|
|
352
|
+
config: BranchApiConfig,
|
|
353
|
+
name: string
|
|
354
|
+
): Promise<TinybirdBranch> {
|
|
355
|
+
// Delete the branch
|
|
356
|
+
await deleteBranch(config, name);
|
|
357
|
+
|
|
358
|
+
// Recreate the branch
|
|
359
|
+
const branch = await createBranch(config, name);
|
|
360
|
+
|
|
361
|
+
return branch;
|
|
362
|
+
}
|
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,
|