@tinybirdco/sdk 0.0.30 → 0.0.32
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 +29 -4
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +1 -0
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/commands/branch.js +5 -5
- package/dist/cli/commands/branch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +2 -2
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/build.test.d.ts +2 -0
- package/dist/cli/commands/build.test.d.ts.map +1 -0
- package/dist/cli/commands/build.test.js +266 -0
- package/dist/cli/commands/build.test.js.map +1 -0
- package/dist/cli/commands/clear.d.ts.map +1 -1
- package/dist/cli/commands/clear.js +2 -2
- package/dist/cli/commands/clear.js.map +1 -1
- package/dist/cli/commands/deploy.js +2 -2
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/dev.js +12 -12
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/info.js +2 -2
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/info.test.js +11 -13
- package/dist/cli/commands/info.test.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +44 -26
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +44 -25
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/login.js +7 -6
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/login.test.js +1 -1
- package/dist/cli/commands/login.test.js.map +1 -1
- package/dist/cli/commands/preview.d.ts.map +1 -1
- package/dist/cli/commands/preview.js +2 -2
- package/dist/cli/commands/preview.js.map +1 -1
- package/dist/cli/config-loader.d.ts +18 -0
- package/dist/cli/config-loader.d.ts.map +1 -0
- package/dist/cli/config-loader.js +57 -0
- package/dist/cli/config-loader.js.map +1 -0
- package/dist/cli/config-types.d.ts +28 -0
- package/dist/cli/config-types.d.ts.map +1 -0
- package/dist/cli/config-types.js +8 -0
- package/dist/cli/config-types.js.map +1 -0
- package/dist/cli/config.d.ts +63 -29
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +139 -43
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/config.test.js +73 -9
- package/dist/cli/config.test.js.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/client/base.d.ts.map +1 -1
- package/dist/client/base.js +21 -9
- package/dist/client/base.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/auth.ts +1 -0
- package/src/cli/commands/branch.ts +5 -5
- package/src/cli/commands/build.test.ts +310 -0
- package/src/cli/commands/build.ts +2 -2
- package/src/cli/commands/clear.ts +2 -2
- package/src/cli/commands/deploy.ts +2 -2
- package/src/cli/commands/dev.ts +12 -12
- package/src/cli/commands/info.test.ts +11 -13
- package/src/cli/commands/info.ts +2 -2
- package/src/cli/commands/init.test.ts +53 -37
- package/src/cli/commands/init.ts +49 -30
- package/src/cli/commands/login.test.ts +1 -1
- package/src/cli/commands/login.ts +7 -6
- package/src/cli/commands/preview.ts +2 -2
- package/src/cli/config-loader.ts +87 -0
- package/src/cli/config-types.ts +29 -0
- package/src/cli/config.test.ts +95 -8
- package/src/cli/config.ts +179 -70
- package/src/cli/index.ts +3 -0
- package/src/client/base.ts +33 -16
- package/src/index.ts +4 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Clear command - clears a local workspace or branch by deleting and recreating it
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { loadConfigAsync, type ResolvedConfig, type DevMode } from "../config.js";
|
|
6
6
|
import {
|
|
7
7
|
getLocalTokens,
|
|
8
8
|
clearLocalWorkspace,
|
|
@@ -60,7 +60,7 @@ export async function runClear(
|
|
|
60
60
|
|
|
61
61
|
let config: ResolvedConfig;
|
|
62
62
|
try {
|
|
63
|
-
config =
|
|
63
|
+
config = await loadConfigAsync(cwd);
|
|
64
64
|
} catch (error) {
|
|
65
65
|
return {
|
|
66
66
|
success: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Deploy command - deploys resources to main Tinybird workspace
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { loadConfigAsync, type ResolvedConfig } from "../config.js";
|
|
6
6
|
import { buildFromInclude, type BuildFromIncludeResult } from "../../generator/index.js";
|
|
7
7
|
import { deployToMain, type DeployCallbacks } from "../../api/deploy.js";
|
|
8
8
|
import type { BuildApiResult } from "../../api/build.js";
|
|
@@ -52,7 +52,7 @@ export async function runDeploy(options: DeployCommandOptions = {}): Promise<Dep
|
|
|
52
52
|
// Load config
|
|
53
53
|
let config: ResolvedConfig;
|
|
54
54
|
try {
|
|
55
|
-
config =
|
|
55
|
+
config = await loadConfigAsync(cwd);
|
|
56
56
|
} catch (error) {
|
|
57
57
|
return {
|
|
58
58
|
success: false,
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { watch } from "chokidar";
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
loadConfigAsync,
|
|
9
9
|
configExists,
|
|
10
10
|
findConfigFile,
|
|
11
11
|
hasValidToken,
|
|
@@ -121,14 +121,14 @@ export async function runDev(
|
|
|
121
121
|
// Check if project is initialized
|
|
122
122
|
if (!configExists(cwd)) {
|
|
123
123
|
throw new Error(
|
|
124
|
-
"No tinybird
|
|
124
|
+
"No tinybird config found. Run 'npx tinybird init' to initialize a project."
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// Load config first to determine devMode
|
|
129
129
|
let config: ResolvedConfig;
|
|
130
130
|
try {
|
|
131
|
-
config =
|
|
131
|
+
config = await loadConfigAsync(cwd);
|
|
132
132
|
} catch (error) {
|
|
133
133
|
throw error;
|
|
134
134
|
}
|
|
@@ -150,18 +150,18 @@ export async function runDev(
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
// Find the config file (may be in parent directory)
|
|
153
|
-
const
|
|
154
|
-
if (!
|
|
155
|
-
throw new Error("No tinybird
|
|
153
|
+
const configResult = findConfigFile(cwd);
|
|
154
|
+
if (!configResult) {
|
|
155
|
+
throw new Error("No tinybird config found. Run 'npx tinybird init' first.");
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
// Save token to .env.local (in same directory as
|
|
159
|
-
const configDir = path.dirname(
|
|
158
|
+
// Save token to .env.local (in same directory as config file)
|
|
159
|
+
const configDir = path.dirname(configResult.path);
|
|
160
160
|
saveTinybirdToken(configDir, authResult.token);
|
|
161
161
|
|
|
162
|
-
// Update baseUrl in
|
|
163
|
-
if (authResult.baseUrl) {
|
|
164
|
-
updateConfig(
|
|
162
|
+
// Update baseUrl in config file if it changed (only for JSON configs)
|
|
163
|
+
if (authResult.baseUrl && configResult.path.endsWith(".json")) {
|
|
164
|
+
updateConfig(configResult.path, {
|
|
165
165
|
baseUrl: authResult.baseUrl,
|
|
166
166
|
});
|
|
167
167
|
}
|
|
@@ -175,7 +175,7 @@ export async function runDev(
|
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
// Reload config after login
|
|
178
|
-
config =
|
|
178
|
+
config = await loadConfigAsync(cwd);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// Determine effective token and branch info based on devMode
|
|
@@ -3,7 +3,7 @@ import { runInfo } from "./info.js";
|
|
|
3
3
|
|
|
4
4
|
// Mock the config module
|
|
5
5
|
vi.mock("../config.js", () => ({
|
|
6
|
-
|
|
6
|
+
loadConfigAsync: vi.fn(),
|
|
7
7
|
LOCAL_BASE_URL: "http://localhost:7181",
|
|
8
8
|
}));
|
|
9
9
|
|
|
@@ -31,7 +31,7 @@ vi.mock("../../api/local.js", () => ({
|
|
|
31
31
|
}));
|
|
32
32
|
|
|
33
33
|
// Import mocked functions
|
|
34
|
-
import {
|
|
34
|
+
import { loadConfigAsync } from "../config.js";
|
|
35
35
|
import { getWorkspace } from "../../api/workspaces.js";
|
|
36
36
|
import { listBranches, getBranch } from "../../api/branches.js";
|
|
37
37
|
import { getDashboardUrl, getBranchDashboardUrl, getLocalDashboardUrl } from "../../api/dashboard.js";
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
getLocalWorkspaceName,
|
|
43
43
|
} from "../../api/local.js";
|
|
44
44
|
|
|
45
|
-
const
|
|
45
|
+
const mockedLoadConfigAsync = vi.mocked(loadConfigAsync);
|
|
46
46
|
const mockedGetWorkspace = vi.mocked(getWorkspace);
|
|
47
47
|
const mockedListBranches = vi.mocked(listBranches);
|
|
48
48
|
const mockedGetBranch = vi.mocked(getBranch);
|
|
@@ -61,9 +61,7 @@ describe("Info Command", () => {
|
|
|
61
61
|
|
|
62
62
|
describe("config loading", () => {
|
|
63
63
|
it("returns error when config loading fails", async () => {
|
|
64
|
-
|
|
65
|
-
throw new Error("No tinybird.json found");
|
|
66
|
-
});
|
|
64
|
+
mockedLoadConfigAsync.mockRejectedValue(new Error("No tinybird.json found"));
|
|
67
65
|
|
|
68
66
|
const result = await runInfo();
|
|
69
67
|
|
|
@@ -95,7 +93,7 @@ describe("Info Command", () => {
|
|
|
95
93
|
};
|
|
96
94
|
|
|
97
95
|
beforeEach(() => {
|
|
98
|
-
|
|
96
|
+
mockedLoadConfigAsync.mockResolvedValue(mockConfig);
|
|
99
97
|
mockedGetWorkspace.mockResolvedValue(mockWorkspace);
|
|
100
98
|
mockedListBranches.mockResolvedValue([]);
|
|
101
99
|
mockedGetDashboardUrl.mockReturnValue("https://cloud.tinybird.co/gcp/europe-west3/test-workspace");
|
|
@@ -161,7 +159,7 @@ describe("Info Command", () => {
|
|
|
161
159
|
});
|
|
162
160
|
|
|
163
161
|
it("does not return branch info when on main branch", async () => {
|
|
164
|
-
|
|
162
|
+
mockedLoadConfigAsync.mockResolvedValue({
|
|
165
163
|
...mockConfig,
|
|
166
164
|
gitBranch: "main",
|
|
167
165
|
tinybirdBranch: null,
|
|
@@ -212,7 +210,7 @@ describe("Info Command", () => {
|
|
|
212
210
|
};
|
|
213
211
|
|
|
214
212
|
beforeEach(() => {
|
|
215
|
-
|
|
213
|
+
mockedLoadConfigAsync.mockResolvedValue(mockConfig);
|
|
216
214
|
mockedGetWorkspace.mockResolvedValue(mockWorkspace);
|
|
217
215
|
mockedGetDashboardUrl.mockReturnValue("https://cloud.tinybird.co/gcp/europe-west3/test-workspace");
|
|
218
216
|
});
|
|
@@ -285,7 +283,7 @@ describe("Info Command", () => {
|
|
|
285
283
|
|
|
286
284
|
describe("error handling", () => {
|
|
287
285
|
it("returns error when workspace fetch fails", async () => {
|
|
288
|
-
|
|
286
|
+
mockedLoadConfigAsync.mockResolvedValue({
|
|
289
287
|
cwd: "/test",
|
|
290
288
|
configPath: "/test/tinybird.json",
|
|
291
289
|
devMode: "branch" as const,
|
|
@@ -306,7 +304,7 @@ describe("Info Command", () => {
|
|
|
306
304
|
});
|
|
307
305
|
|
|
308
306
|
it("handles branch fetch error gracefully", async () => {
|
|
309
|
-
|
|
307
|
+
mockedLoadConfigAsync.mockResolvedValue({
|
|
310
308
|
cwd: "/test",
|
|
311
309
|
configPath: "/test/tinybird.json",
|
|
312
310
|
devMode: "branch" as const,
|
|
@@ -336,7 +334,7 @@ describe("Info Command", () => {
|
|
|
336
334
|
});
|
|
337
335
|
|
|
338
336
|
it("handles branches list fetch error gracefully", async () => {
|
|
339
|
-
|
|
337
|
+
mockedLoadConfigAsync.mockResolvedValue({
|
|
340
338
|
cwd: "/test",
|
|
341
339
|
configPath: "/test/tinybird.json",
|
|
342
340
|
devMode: "branch" as const,
|
|
@@ -365,7 +363,7 @@ describe("Info Command", () => {
|
|
|
365
363
|
});
|
|
366
364
|
|
|
367
365
|
it("handles local workspace fetch error gracefully", async () => {
|
|
368
|
-
|
|
366
|
+
mockedLoadConfigAsync.mockResolvedValue({
|
|
369
367
|
cwd: "/test",
|
|
370
368
|
configPath: "/test/tinybird.json",
|
|
371
369
|
devMode: "local" as const,
|
package/src/cli/commands/info.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Info command - shows information about the current project and workspace
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { loadConfigAsync, LOCAL_BASE_URL, type ResolvedConfig } from "../config.js";
|
|
6
6
|
import { getWorkspace, type TinybirdWorkspace } from "../../api/workspaces.js";
|
|
7
7
|
import { listBranches, getBranch, type TinybirdBranch } from "../../api/branches.js";
|
|
8
8
|
import { getDashboardUrl, getBranchDashboardUrl, getLocalDashboardUrl } from "../../api/dashboard.js";
|
|
@@ -125,7 +125,7 @@ export async function runInfo(
|
|
|
125
125
|
// Load config
|
|
126
126
|
let config: ResolvedConfig;
|
|
127
127
|
try {
|
|
128
|
-
config =
|
|
128
|
+
config = await loadConfigAsync(cwd);
|
|
129
129
|
} catch (error) {
|
|
130
130
|
return {
|
|
131
131
|
success: false,
|
|
@@ -46,45 +46,45 @@ describe("Init Command", () => {
|
|
|
46
46
|
).toBe(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it("creates tinybird.json with correct include path for lib/tinybird.ts", async () => {
|
|
49
|
+
it("creates tinybird.config.json with correct include path for lib/tinybird.ts", async () => {
|
|
50
50
|
const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "lib/tinybird.ts" });
|
|
51
51
|
|
|
52
52
|
expect(result.success).toBe(true);
|
|
53
|
-
expect(result.created).toContain("tinybird.json");
|
|
53
|
+
expect(result.created).toContain("tinybird.config.json");
|
|
54
54
|
|
|
55
55
|
const config = JSON.parse(
|
|
56
|
-
fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
|
|
56
|
+
fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8")
|
|
57
57
|
);
|
|
58
|
-
expect(config.include).
|
|
58
|
+
expect(config.include).toContain("lib/tinybird.ts");
|
|
59
|
+
expect(config.token).toBe("${TINYBIRD_TOKEN}");
|
|
59
60
|
});
|
|
60
61
|
|
|
61
|
-
it("creates tinybird.json with correct include path for src/lib/tinybird.ts", async () => {
|
|
62
|
+
it("creates tinybird.config.json with correct include path for src/lib/tinybird.ts", async () => {
|
|
62
63
|
fs.mkdirSync(path.join(tempDir, "src"));
|
|
63
64
|
|
|
64
65
|
const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "src/lib/tinybird.ts" });
|
|
65
66
|
|
|
66
67
|
expect(result.success).toBe(true);
|
|
67
68
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
);
|
|
71
|
-
expect(config.include).toEqual(["src/lib/tinybird.ts"]);
|
|
69
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
70
|
+
expect(content).toContain('"src/lib/tinybird.ts"');
|
|
72
71
|
});
|
|
73
72
|
});
|
|
74
73
|
|
|
75
74
|
describe("config file creation", () => {
|
|
76
|
-
it("creates tinybird.json with default values", async () => {
|
|
75
|
+
it("creates tinybird.config.json with default values", async () => {
|
|
77
76
|
await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "lib/tinybird.ts" });
|
|
78
77
|
|
|
79
78
|
const config = JSON.parse(
|
|
80
|
-
fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
|
|
79
|
+
fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8")
|
|
81
80
|
);
|
|
82
81
|
|
|
83
82
|
expect(config.token).toBe("${TINYBIRD_TOKEN}");
|
|
84
83
|
expect(config.baseUrl).toBe("https://api.tinybird.co");
|
|
84
|
+
expect(config.devMode).toBe("branch");
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
it("updates tinybird.json if it already exists", async () => {
|
|
87
|
+
it("updates legacy tinybird.json if it already exists", async () => {
|
|
88
88
|
const existingConfig = {
|
|
89
89
|
include: ["custom.ts"],
|
|
90
90
|
token: "existing",
|
|
@@ -109,22 +109,46 @@ describe("Init Command", () => {
|
|
|
109
109
|
expect(config.token).toBe("existing");
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it("
|
|
113
|
-
const existingConfig = {
|
|
112
|
+
it("updates tinybird.config.json if it already exists", async () => {
|
|
113
|
+
const existingConfig = {
|
|
114
|
+
include: ["custom.ts"],
|
|
115
|
+
token: "existing",
|
|
116
|
+
devMode: "local",
|
|
117
|
+
};
|
|
114
118
|
fs.writeFileSync(
|
|
115
|
-
path.join(tempDir, "tinybird.json"),
|
|
119
|
+
path.join(tempDir, "tinybird.config.json"),
|
|
116
120
|
JSON.stringify(existingConfig)
|
|
117
121
|
);
|
|
118
122
|
|
|
119
|
-
const result = await runInit({ cwd: tempDir, skipLogin: true,
|
|
123
|
+
const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "lib/tinybird.ts" });
|
|
120
124
|
|
|
121
125
|
expect(result.success).toBe(true);
|
|
122
|
-
expect(result.created).toContain("tinybird.json");
|
|
126
|
+
expect(result.created).toContain("tinybird.config.json (updated)");
|
|
123
127
|
|
|
128
|
+
// Verify include/devMode updated but token preserved
|
|
124
129
|
const config = JSON.parse(
|
|
125
|
-
fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
|
|
130
|
+
fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8")
|
|
126
131
|
);
|
|
127
132
|
expect(config.include).toEqual(["lib/tinybird.ts"]);
|
|
133
|
+
expect(config.devMode).toBe("branch");
|
|
134
|
+
expect(config.token).toBe("existing");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("overwrites existing config with force option", async () => {
|
|
138
|
+
const existingConfig = { include: ["custom.ts"], token: "existing" };
|
|
139
|
+
fs.writeFileSync(
|
|
140
|
+
path.join(tempDir, "tinybird.json"),
|
|
141
|
+
JSON.stringify(existingConfig)
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const result = await runInit({ cwd: tempDir, skipLogin: true, force: true, devMode: "branch", clientPath: "lib/tinybird.ts" });
|
|
145
|
+
|
|
146
|
+
expect(result.success).toBe(true);
|
|
147
|
+
// With force, it creates a new tinybird.config.json
|
|
148
|
+
expect(result.created).toContain("tinybird.config.json");
|
|
149
|
+
|
|
150
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
151
|
+
expect(content).toContain('"lib/tinybird.ts"');
|
|
128
152
|
});
|
|
129
153
|
});
|
|
130
154
|
|
|
@@ -417,11 +441,9 @@ describe("Init Command", () => {
|
|
|
417
441
|
expect(result.existingDatafiles).toContain("datasources/events.datasource");
|
|
418
442
|
expect(result.existingDatafiles).toContain("pipes/top_events.pipe");
|
|
419
443
|
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
);
|
|
423
|
-
expect(config.include).toContain("datasources/events.datasource");
|
|
424
|
-
expect(config.include).toContain("pipes/top_events.pipe");
|
|
444
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
445
|
+
expect(content).toContain('"datasources/events.datasource"');
|
|
446
|
+
expect(content).toContain('"pipes/top_events.pipe"');
|
|
425
447
|
});
|
|
426
448
|
|
|
427
449
|
it("does not include existing datafiles when user opts out", async () => {
|
|
@@ -441,11 +463,9 @@ describe("Init Command", () => {
|
|
|
441
463
|
expect(result.success).toBe(true);
|
|
442
464
|
expect(result.existingDatafiles).toBeUndefined();
|
|
443
465
|
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
);
|
|
447
|
-
expect(config.include).not.toContain("datasources/events.datasource");
|
|
448
|
-
expect(config.include).toEqual(["lib/tinybird.ts"]);
|
|
466
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
467
|
+
expect(content).not.toContain("datasources/events.datasource");
|
|
468
|
+
expect(content).toContain('"lib/tinybird.ts"');
|
|
449
469
|
});
|
|
450
470
|
|
|
451
471
|
it("preserves TypeScript include paths alongside datafiles", async () => {
|
|
@@ -464,12 +484,10 @@ describe("Init Command", () => {
|
|
|
464
484
|
|
|
465
485
|
expect(result.success).toBe(true);
|
|
466
486
|
|
|
467
|
-
const
|
|
468
|
-
fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
|
|
469
|
-
);
|
|
487
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
470
488
|
// Should have both TypeScript file AND datafiles
|
|
471
|
-
expect(
|
|
472
|
-
expect(
|
|
489
|
+
expect(content).toContain('"lib/tinybird.ts"');
|
|
490
|
+
expect(content).toContain('"datasources/events.datasource"');
|
|
473
491
|
});
|
|
474
492
|
|
|
475
493
|
it("handles projects with no existing datafiles", async () => {
|
|
@@ -485,10 +503,8 @@ describe("Init Command", () => {
|
|
|
485
503
|
expect(result.success).toBe(true);
|
|
486
504
|
expect(result.existingDatafiles).toBeUndefined();
|
|
487
505
|
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
);
|
|
491
|
-
expect(config.include).toEqual(["lib/tinybird.ts"]);
|
|
506
|
+
const content = fs.readFileSync(path.join(tempDir, "tinybird.config.json"), "utf-8");
|
|
507
|
+
expect(content).toContain('"lib/tinybird.ts"');
|
|
492
508
|
});
|
|
493
509
|
});
|
|
494
510
|
});
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
hasValidToken,
|
|
11
11
|
getRelativeTinybirdDir,
|
|
12
12
|
getConfigPath,
|
|
13
|
+
findExistingConfigPath,
|
|
13
14
|
updateConfig,
|
|
14
|
-
|
|
15
|
+
loadConfigAsync,
|
|
15
16
|
type DevMode,
|
|
16
17
|
} from "../config.js";
|
|
17
18
|
import { browserLogin } from "../auth.js";
|
|
@@ -130,6 +131,7 @@ function generateGithubCiWorkflow(workingDirectory?: string): string {
|
|
|
130
131
|
on:
|
|
131
132
|
pull_request:
|
|
132
133
|
paths:
|
|
134
|
+
- "${pathPrefix}tinybird.config.*"
|
|
133
135
|
- "${pathPrefix}tinybird.json"
|
|
134
136
|
- "${pathPrefix}**/*.ts"
|
|
135
137
|
|
|
@@ -176,6 +178,7 @@ on:
|
|
|
176
178
|
branches:
|
|
177
179
|
- main
|
|
178
180
|
paths:
|
|
181
|
+
- "${pathPrefix}tinybird.config.*"
|
|
179
182
|
- "${pathPrefix}tinybird.json"
|
|
180
183
|
- "${pathPrefix}**/*.ts"
|
|
181
184
|
|
|
@@ -218,6 +221,7 @@ tinybird_ci:
|
|
|
218
221
|
image: node:22
|
|
219
222
|
rules:
|
|
220
223
|
- changes:
|
|
224
|
+
- ${pathPrefix}tinybird.config.*
|
|
221
225
|
- ${pathPrefix}tinybird.json
|
|
222
226
|
- ${pathPrefix}**/*.ts
|
|
223
227
|
script:
|
|
@@ -246,6 +250,7 @@ tinybird_cd:
|
|
|
246
250
|
rules:
|
|
247
251
|
- if: '$CI_COMMIT_BRANCH == "main"'
|
|
248
252
|
changes:
|
|
253
|
+
- ${pathPrefix}tinybird.config.*
|
|
249
254
|
- ${pathPrefix}tinybird.json
|
|
250
255
|
- ${pathPrefix}**/*.ts
|
|
251
256
|
script:
|
|
@@ -258,7 +263,7 @@ tinybird_cd:
|
|
|
258
263
|
}
|
|
259
264
|
|
|
260
265
|
/**
|
|
261
|
-
* Default config content generator
|
|
266
|
+
* Default config content generator (for JSON files)
|
|
262
267
|
*/
|
|
263
268
|
function createDefaultConfig(
|
|
264
269
|
tinybirdFilePath: string,
|
|
@@ -419,7 +424,7 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
419
424
|
|
|
420
425
|
if (!options.devMode) {
|
|
421
426
|
// Show interactive prompt for workflow selection
|
|
422
|
-
p.intro(pc.cyan("tinybird.json"));
|
|
427
|
+
p.intro(pc.cyan("tinybird.config.json"));
|
|
423
428
|
|
|
424
429
|
const workflowChoice = await p.select({
|
|
425
430
|
message: "How do you want to develop with Tinybird?",
|
|
@@ -589,43 +594,54 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
589
594
|
const tinybirdFilePath = path.join(cwd, relativeTinybirdDir);
|
|
590
595
|
const tinybirdDir = path.dirname(tinybirdFilePath);
|
|
591
596
|
|
|
592
|
-
// Create config file
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
597
|
+
// Create or update config file
|
|
598
|
+
// Check for any existing config file first
|
|
599
|
+
const existingConfigPath = findExistingConfigPath(cwd);
|
|
600
|
+
const newConfigPath = getConfigPath(cwd);
|
|
601
|
+
|
|
602
|
+
if (existingConfigPath && !force) {
|
|
603
|
+
// Update existing config file (only if it's JSON)
|
|
604
|
+
const configFileName = path.basename(existingConfigPath);
|
|
605
|
+
if (existingConfigPath.endsWith(".json")) {
|
|
606
|
+
try {
|
|
607
|
+
const config = createDefaultConfig(
|
|
608
|
+
relativeTinybirdDir,
|
|
609
|
+
devMode,
|
|
610
|
+
existingDatafiles
|
|
611
|
+
);
|
|
612
|
+
updateConfig(existingConfigPath, {
|
|
613
|
+
include: config.include,
|
|
614
|
+
devMode: config.devMode,
|
|
615
|
+
});
|
|
616
|
+
created.push(`${configFileName} (updated)`);
|
|
617
|
+
} catch (error) {
|
|
618
|
+
return {
|
|
619
|
+
success: false,
|
|
620
|
+
created,
|
|
621
|
+
skipped,
|
|
622
|
+
error: `Failed to update ${configFileName}: ${(error as Error).message}`,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
} else {
|
|
626
|
+
// JS config file exists - skip and let user update manually
|
|
627
|
+
skipped.push(`${configFileName} (JS config files must be updated manually)`);
|
|
613
628
|
}
|
|
614
629
|
} else {
|
|
630
|
+
// Create new config file with JSON format
|
|
615
631
|
try {
|
|
616
632
|
const config = createDefaultConfig(
|
|
617
633
|
relativeTinybirdDir,
|
|
618
634
|
devMode,
|
|
619
635
|
existingDatafiles
|
|
620
636
|
);
|
|
621
|
-
fs.writeFileSync(
|
|
622
|
-
created.push("tinybird.json");
|
|
637
|
+
fs.writeFileSync(newConfigPath, JSON.stringify(config, null, 2) + "\n");
|
|
638
|
+
created.push("tinybird.config.json");
|
|
623
639
|
} catch (error) {
|
|
624
640
|
return {
|
|
625
641
|
success: false,
|
|
626
642
|
created,
|
|
627
643
|
skipped,
|
|
628
|
-
error: `Failed to create tinybird.json: ${(error as Error).message}`,
|
|
644
|
+
error: `Failed to create tinybird.config.json: ${(error as Error).message}`,
|
|
629
645
|
};
|
|
630
646
|
}
|
|
631
647
|
}
|
|
@@ -841,10 +857,13 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
841
857
|
created.push(".env.local");
|
|
842
858
|
}
|
|
843
859
|
|
|
844
|
-
// If custom base URL, update
|
|
860
|
+
// If custom base URL, update config file
|
|
845
861
|
const baseUrl = authResult.baseUrl ?? "https://api.tinybird.co";
|
|
846
862
|
if (baseUrl !== "https://api.tinybird.co") {
|
|
847
|
-
|
|
863
|
+
const currentConfigPath = findExistingConfigPath(cwd);
|
|
864
|
+
if (currentConfigPath && currentConfigPath.endsWith(".json")) {
|
|
865
|
+
updateConfig(currentConfigPath, { baseUrl });
|
|
866
|
+
}
|
|
848
867
|
}
|
|
849
868
|
|
|
850
869
|
// Generate TypeScript from existing Tinybird resources if requested
|
|
@@ -916,7 +935,7 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
916
935
|
// (when user is already logged in)
|
|
917
936
|
if (datafileAction === "codegen" && hasValidToken(cwd)) {
|
|
918
937
|
try {
|
|
919
|
-
const config =
|
|
938
|
+
const config = await loadConfigAsync(cwd);
|
|
920
939
|
const tinybirdDir = path.join(cwd, relativeTinybirdDir);
|
|
921
940
|
await runCodegen(
|
|
922
941
|
config.baseUrl,
|
|
@@ -35,7 +35,7 @@ describe("Login Command", () => {
|
|
|
35
35
|
const result = await runLogin({ cwd: tempDir });
|
|
36
36
|
|
|
37
37
|
expect(result.success).toBe(false);
|
|
38
|
-
expect(result.error).toContain("No tinybird
|
|
38
|
+
expect(result.error).toContain("No tinybird config found");
|
|
39
39
|
expect(result.error).toContain("npx tinybird init");
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -45,14 +45,15 @@ export async function runLogin(options: RunLoginOptions = {}): Promise<LoginResu
|
|
|
45
45
|
const cwd = options.cwd ?? process.cwd();
|
|
46
46
|
|
|
47
47
|
// Find the actual config file (may be in parent directory)
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
48
|
+
const configResult = findConfigFile(cwd);
|
|
49
|
+
if (!configResult) {
|
|
50
50
|
return {
|
|
51
51
|
success: false,
|
|
52
|
-
error: "No tinybird
|
|
52
|
+
error: "No tinybird config found. Run 'npx tinybird init' first.",
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
const configPath = configResult.path;
|
|
56
57
|
// Get the directory containing the config file for .env.local
|
|
57
58
|
const configDir = path.dirname(configPath);
|
|
58
59
|
|
|
@@ -72,12 +73,12 @@ export async function runLogin(options: RunLoginOptions = {}): Promise<LoginResu
|
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
// Save token to .env.local (in same directory as
|
|
76
|
+
// Save token to .env.local (in same directory as config file)
|
|
76
77
|
try {
|
|
77
78
|
saveTinybirdToken(configDir, authResult.token);
|
|
78
79
|
|
|
79
|
-
// Update baseUrl in
|
|
80
|
-
if (authResult.baseUrl) {
|
|
80
|
+
// Update baseUrl in config file if it changed (only for JSON configs)
|
|
81
|
+
if (authResult.baseUrl && configPath.endsWith(".json")) {
|
|
81
82
|
updateConfig(configPath, {
|
|
82
83
|
baseUrl: authResult.baseUrl,
|
|
83
84
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Preview command - creates ephemeral preview branch and deploys resources
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { loadConfigAsync, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } from "../config.js";
|
|
6
6
|
import { buildFromInclude, type BuildFromIncludeResult } from "../../generator/index.js";
|
|
7
7
|
import { createBranch, deleteBranch, getBranch, type TinybirdBranch } from "../../api/branches.js";
|
|
8
8
|
import { deployToMain } from "../../api/deploy.js";
|
|
@@ -90,7 +90,7 @@ export async function runPreview(options: PreviewCommandOptions = {}): Promise<P
|
|
|
90
90
|
// Load config
|
|
91
91
|
let config: ResolvedConfig;
|
|
92
92
|
try {
|
|
93
|
-
config =
|
|
93
|
+
config = await loadConfigAsync(cwd);
|
|
94
94
|
} catch (error) {
|
|
95
95
|
return {
|
|
96
96
|
success: false,
|