@tinybirdco/sdk 0.0.78 → 0.0.80
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 +4 -3
- package/dist/api/branches.d.ts.map +1 -1
- package/dist/api/branches.js +4 -4
- package/dist/api/branches.js.map +1 -1
- package/dist/api/branches.test.js +34 -1
- package/dist/api/branches.test.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +7 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/build.test.js +159 -0
- package/dist/cli/commands/build.test.js.map +1 -1
- package/dist/cli/commands/clear.d.ts.map +1 -1
- package/dist/cli/commands/clear.js +4 -1
- package/dist/cli/commands/clear.js.map +1 -1
- package/dist/cli/commands/deploy.test.js +1 -0
- package/dist/cli/commands/deploy.test.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +7 -1
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/generate.test.js +3 -0
- package/dist/cli/commands/generate.test.js.map +1 -1
- package/dist/cli/commands/preview.d.ts.map +1 -1
- package/dist/cli/commands/preview.js +4 -1
- package/dist/cli/commands/preview.js.map +1 -1
- package/dist/cli/commands/preview.test.js +116 -2
- package/dist/cli/commands/preview.test.js.map +1 -1
- package/dist/cli/config-types.d.ts +4 -0
- package/dist/cli/config-types.d.ts.map +1 -1
- package/dist/cli/config-types.js +1 -1
- package/dist/cli/config-types.js.map +1 -1
- package/dist/cli/config.d.ts +4 -2
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +27 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/config.test.js +79 -0
- package/dist/cli/config.test.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/client/base.d.ts.map +1 -1
- package/dist/client/base.js +4 -1
- package/dist/client/base.js.map +1 -1
- package/dist/client/base.test.js +2 -1
- package/dist/client/base.test.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/api/branches.test.ts +38 -1
- package/src/api/branches.ts +8 -6
- package/src/cli/commands/build.test.ts +176 -0
- package/src/cli/commands/build.ts +9 -2
- package/src/cli/commands/clear.ts +8 -1
- package/src/cli/commands/deploy.test.ts +1 -0
- package/src/cli/commands/dev.ts +9 -1
- package/src/cli/commands/generate.test.ts +3 -0
- package/src/cli/commands/preview.test.ts +133 -2
- package/src/cli/commands/preview.ts +6 -2
- package/src/cli/config-types.ts +4 -0
- package/src/cli/config.test.ts +123 -0
- package/src/cli/config.ts +41 -3
- package/src/cli/index.ts +8 -2
- package/src/client/base.test.ts +3 -1
- package/src/client/base.ts +7 -1
- package/src/index.ts +1 -1
|
@@ -64,6 +64,7 @@ describe("Build Command", () => {
|
|
|
64
64
|
gitBranch: "feature-test",
|
|
65
65
|
tinybirdBranch: "feature_test",
|
|
66
66
|
isMainBranch: false,
|
|
67
|
+
branchDataMode: null,
|
|
67
68
|
});
|
|
68
69
|
|
|
69
70
|
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
@@ -156,6 +157,7 @@ describe("Build Command", () => {
|
|
|
156
157
|
gitBranch: "feature-test",
|
|
157
158
|
tinybirdBranch: "feature_test",
|
|
158
159
|
isMainBranch: false,
|
|
160
|
+
branchDataMode: null,
|
|
159
161
|
});
|
|
160
162
|
|
|
161
163
|
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
@@ -242,6 +244,7 @@ describe("Build Command", () => {
|
|
|
242
244
|
gitBranch: "feature-test",
|
|
243
245
|
tinybirdBranch: "feature_test",
|
|
244
246
|
isMainBranch: false,
|
|
247
|
+
branchDataMode: null,
|
|
245
248
|
});
|
|
246
249
|
|
|
247
250
|
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
@@ -307,4 +310,177 @@ describe("Build Command", () => {
|
|
|
307
310
|
expect(getLocalTokens).toHaveBeenCalled();
|
|
308
311
|
});
|
|
309
312
|
});
|
|
313
|
+
|
|
314
|
+
describe("branch_data_mode wiring", () => {
|
|
315
|
+
it("uses config-only last_partition when flag is absent", async () => {
|
|
316
|
+
const { loadConfigAsync } = await import("../config.js");
|
|
317
|
+
const { buildFromInclude } = await import("../../generator/index.js");
|
|
318
|
+
const { getOrCreateBranch } = await import("../../api/branches.js");
|
|
319
|
+
const { buildToTinybird } = await import("../../api/build.js");
|
|
320
|
+
const { getWorkspace } = await import("../../api/workspaces.js");
|
|
321
|
+
const { getBranchDashboardUrl } = await import("../../api/dashboard.js");
|
|
322
|
+
|
|
323
|
+
vi.mocked(loadConfigAsync).mockResolvedValue({
|
|
324
|
+
include: ["test.ts"],
|
|
325
|
+
token: "p.test-token",
|
|
326
|
+
baseUrl: "https://api.tinybird.co",
|
|
327
|
+
configPath: "/test/tinybird.config.json",
|
|
328
|
+
devMode: "branch",
|
|
329
|
+
cwd: "/test",
|
|
330
|
+
gitBranch: "feature-test",
|
|
331
|
+
tinybirdBranch: "feature_test",
|
|
332
|
+
isMainBranch: false,
|
|
333
|
+
branchDataMode: "last_partition",
|
|
334
|
+
});
|
|
335
|
+
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
336
|
+
resources: { datasources: [], pipes: [], connections: [] },
|
|
337
|
+
entities: { datasources: {}, pipes: {}, connections: {}, rawDatasources: [], rawPipes: [], sourceFiles: [] },
|
|
338
|
+
stats: { datasourceCount: 0, pipeCount: 0, connectionCount: 0 },
|
|
339
|
+
});
|
|
340
|
+
vi.mocked(getOrCreateBranch).mockResolvedValue({
|
|
341
|
+
id: "branch-id",
|
|
342
|
+
name: "feature_test",
|
|
343
|
+
token: "branch-token",
|
|
344
|
+
wasCreated: false,
|
|
345
|
+
created_at: "2024-01-01",
|
|
346
|
+
});
|
|
347
|
+
vi.mocked(getWorkspace).mockResolvedValue({
|
|
348
|
+
id: "ws-id",
|
|
349
|
+
name: "test-workspace",
|
|
350
|
+
user_id: "user-id",
|
|
351
|
+
user_email: "user@test.com",
|
|
352
|
+
scope: "USER",
|
|
353
|
+
main: null,
|
|
354
|
+
});
|
|
355
|
+
vi.mocked(getBranchDashboardUrl).mockReturnValue("https://app.tinybird.co/dashboard");
|
|
356
|
+
vi.mocked(buildToTinybird).mockResolvedValue({
|
|
357
|
+
success: true,
|
|
358
|
+
result: "success",
|
|
359
|
+
datasourceCount: 0,
|
|
360
|
+
pipeCount: 0,
|
|
361
|
+
connectionCount: 0,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await runBuild();
|
|
365
|
+
expect(getOrCreateBranch).toHaveBeenCalledWith(
|
|
366
|
+
expect.any(Object),
|
|
367
|
+
"feature_test",
|
|
368
|
+
{ branch_data_mode: "last_partition" }
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("keeps CLI --last-partition precedence over config", async () => {
|
|
373
|
+
const { loadConfigAsync } = await import("../config.js");
|
|
374
|
+
const { buildFromInclude } = await import("../../generator/index.js");
|
|
375
|
+
const { getOrCreateBranch } = await import("../../api/branches.js");
|
|
376
|
+
const { buildToTinybird } = await import("../../api/build.js");
|
|
377
|
+
const { getWorkspace } = await import("../../api/workspaces.js");
|
|
378
|
+
const { getBranchDashboardUrl } = await import("../../api/dashboard.js");
|
|
379
|
+
|
|
380
|
+
vi.mocked(loadConfigAsync).mockResolvedValue({
|
|
381
|
+
include: ["test.ts"],
|
|
382
|
+
token: "p.test-token",
|
|
383
|
+
baseUrl: "https://api.tinybird.co",
|
|
384
|
+
configPath: "/test/tinybird.config.json",
|
|
385
|
+
devMode: "branch",
|
|
386
|
+
cwd: "/test",
|
|
387
|
+
gitBranch: "feature-test",
|
|
388
|
+
tinybirdBranch: "feature_test",
|
|
389
|
+
isMainBranch: false,
|
|
390
|
+
branchDataMode: null,
|
|
391
|
+
});
|
|
392
|
+
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
393
|
+
resources: { datasources: [], pipes: [], connections: [] },
|
|
394
|
+
entities: { datasources: {}, pipes: {}, connections: {}, rawDatasources: [], rawPipes: [], sourceFiles: [] },
|
|
395
|
+
stats: { datasourceCount: 0, pipeCount: 0, connectionCount: 0 },
|
|
396
|
+
});
|
|
397
|
+
vi.mocked(getOrCreateBranch).mockResolvedValue({
|
|
398
|
+
id: "branch-id",
|
|
399
|
+
name: "feature_test",
|
|
400
|
+
token: "branch-token",
|
|
401
|
+
wasCreated: false,
|
|
402
|
+
created_at: "2024-01-01",
|
|
403
|
+
});
|
|
404
|
+
vi.mocked(getWorkspace).mockResolvedValue({
|
|
405
|
+
id: "ws-id",
|
|
406
|
+
name: "test-workspace",
|
|
407
|
+
user_id: "user-id",
|
|
408
|
+
user_email: "user@test.com",
|
|
409
|
+
scope: "USER",
|
|
410
|
+
main: null,
|
|
411
|
+
});
|
|
412
|
+
vi.mocked(getBranchDashboardUrl).mockReturnValue("https://app.tinybird.co/dashboard");
|
|
413
|
+
vi.mocked(buildToTinybird).mockResolvedValue({
|
|
414
|
+
success: true,
|
|
415
|
+
result: "success",
|
|
416
|
+
datasourceCount: 0,
|
|
417
|
+
pipeCount: 0,
|
|
418
|
+
connectionCount: 0,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
await runBuild({ lastPartition: true });
|
|
422
|
+
expect(getOrCreateBranch).toHaveBeenCalledWith(
|
|
423
|
+
expect.any(Object),
|
|
424
|
+
"feature_test",
|
|
425
|
+
{ branch_data_mode: "last_partition" }
|
|
426
|
+
);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it("ignores config branch_data_mode in local mode", async () => {
|
|
430
|
+
const { loadConfigAsync } = await import("../config.js");
|
|
431
|
+
const { buildFromInclude } = await import("../../generator/index.js");
|
|
432
|
+
const { getOrCreateBranch } = await import("../../api/branches.js");
|
|
433
|
+
const { getLocalTokens, getOrCreateLocalWorkspace, getLocalWorkspaceName } = await import("../../api/local.js");
|
|
434
|
+
const { buildToTinybird } = await import("../../api/build.js");
|
|
435
|
+
const { getWorkspace } = await import("../../api/workspaces.js");
|
|
436
|
+
const { getLocalDashboardUrl } = await import("../../api/dashboard.js");
|
|
437
|
+
|
|
438
|
+
vi.mocked(loadConfigAsync).mockResolvedValue({
|
|
439
|
+
include: ["test.ts"],
|
|
440
|
+
token: "p.test-token",
|
|
441
|
+
baseUrl: "https://api.tinybird.co",
|
|
442
|
+
configPath: "/test/tinybird.config.json",
|
|
443
|
+
devMode: "local",
|
|
444
|
+
cwd: "/test",
|
|
445
|
+
gitBranch: "feature-test",
|
|
446
|
+
tinybirdBranch: "feature_test",
|
|
447
|
+
isMainBranch: false,
|
|
448
|
+
branchDataMode: "last_partition",
|
|
449
|
+
});
|
|
450
|
+
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
451
|
+
resources: { datasources: [], pipes: [], connections: [] },
|
|
452
|
+
entities: { datasources: {}, pipes: {}, connections: {}, rawDatasources: [], rawPipes: [], sourceFiles: [] },
|
|
453
|
+
stats: { datasourceCount: 0, pipeCount: 0, connectionCount: 0 },
|
|
454
|
+
});
|
|
455
|
+
vi.mocked(getLocalTokens).mockResolvedValue({
|
|
456
|
+
admin_token: "admin-token",
|
|
457
|
+
user_token: "user-token",
|
|
458
|
+
workspace_admin_token: "workspace-admin-token",
|
|
459
|
+
});
|
|
460
|
+
vi.mocked(getWorkspace).mockResolvedValue({
|
|
461
|
+
id: "ws-id",
|
|
462
|
+
name: "test-workspace",
|
|
463
|
+
user_id: "user-id",
|
|
464
|
+
user_email: "user@test.com",
|
|
465
|
+
scope: "USER",
|
|
466
|
+
main: null,
|
|
467
|
+
});
|
|
468
|
+
vi.mocked(getLocalWorkspaceName).mockReturnValue("feature_test_workspace");
|
|
469
|
+
vi.mocked(getOrCreateLocalWorkspace).mockResolvedValue({
|
|
470
|
+
workspace: { id: "local-ws-id", name: "feature_test_workspace", token: "local-token" },
|
|
471
|
+
wasCreated: false,
|
|
472
|
+
});
|
|
473
|
+
vi.mocked(getLocalDashboardUrl).mockReturnValue("http://localhost:7181/dashboard");
|
|
474
|
+
vi.mocked(buildToTinybird).mockResolvedValue({
|
|
475
|
+
success: true,
|
|
476
|
+
result: "success",
|
|
477
|
+
datasourceCount: 0,
|
|
478
|
+
pipeCount: 0,
|
|
479
|
+
connectionCount: 0,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
await runBuild();
|
|
483
|
+
expect(getOrCreateBranch).not.toHaveBeenCalled();
|
|
484
|
+
});
|
|
485
|
+
});
|
|
310
486
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Build command - generates and pushes resources to Tinybird branches
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { loadConfigAsync, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } from "../config.js";
|
|
5
|
+
import { loadConfigAsync, LOCAL_BASE_URL, type ResolvedConfig, type DevMode, type BranchDataMode } from "../config.js";
|
|
6
6
|
import { buildFromInclude, type BuildFromIncludeResult } from "../../generator/index.js";
|
|
7
7
|
import { buildToTinybird, type BuildApiResult } from "../../api/build.js";
|
|
8
8
|
import { getOrCreateBranch } from "../../api/branches.js";
|
|
@@ -225,13 +225,20 @@ export async function runBuild(options: BuildCommandOptions = {}): Promise<Build
|
|
|
225
225
|
console.log(`[debug] Getting/creating Tinybird branch: ${config.tinybirdBranch}`);
|
|
226
226
|
}
|
|
227
227
|
try {
|
|
228
|
+
const branchDataMode: BranchDataMode | undefined =
|
|
229
|
+
options.lastPartition || config.branchDataMode === "last_partition"
|
|
230
|
+
? "last_partition"
|
|
231
|
+
: undefined;
|
|
232
|
+
const branchOptions = branchDataMode
|
|
233
|
+
? { branch_data_mode: branchDataMode }
|
|
234
|
+
: undefined;
|
|
228
235
|
const tinybirdBranch = await getOrCreateBranch(
|
|
229
236
|
{
|
|
230
237
|
baseUrl: config.baseUrl,
|
|
231
238
|
token: config.token,
|
|
232
239
|
},
|
|
233
240
|
config.tinybirdBranch!,
|
|
234
|
-
|
|
241
|
+
branchOptions
|
|
235
242
|
);
|
|
236
243
|
|
|
237
244
|
if (!tinybirdBranch.token) {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
clearBranch,
|
|
15
15
|
BranchApiError,
|
|
16
|
+
type CreateBranchOptions,
|
|
16
17
|
} from "../../api/branches.js";
|
|
17
18
|
import {
|
|
18
19
|
setBranchToken,
|
|
@@ -147,12 +148,18 @@ async function clearCloudBranch(config: ResolvedConfig): Promise<ClearResult> {
|
|
|
147
148
|
});
|
|
148
149
|
|
|
149
150
|
// Clear the branch (delete and recreate)
|
|
151
|
+
const branchOptions: CreateBranchOptions | undefined =
|
|
152
|
+
config.devMode !== "local" && config.branchDataMode === "last_partition"
|
|
153
|
+
? { branch_data_mode: "last_partition" }
|
|
154
|
+
: undefined;
|
|
155
|
+
|
|
150
156
|
const newBranch = await clearBranch(
|
|
151
157
|
{
|
|
152
158
|
baseUrl: config.baseUrl,
|
|
153
159
|
token: config.token,
|
|
154
160
|
},
|
|
155
|
-
branchName
|
|
161
|
+
branchName,
|
|
162
|
+
branchOptions
|
|
156
163
|
);
|
|
157
164
|
|
|
158
165
|
// Update the cached token with the new branch token
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
LOCAL_BASE_URL,
|
|
14
14
|
type ResolvedConfig,
|
|
15
15
|
type DevMode,
|
|
16
|
+
type BranchDataMode,
|
|
16
17
|
} from "../config.js";
|
|
17
18
|
import { runBuild, type BuildCommandResult } from "./build.js";
|
|
18
19
|
import { getOrCreateBranch, type TinybirdBranch } from "../../api/branches.js";
|
|
@@ -239,6 +240,13 @@ export async function runDev(
|
|
|
239
240
|
// Use tinybirdBranch (sanitized name) for Tinybird API, gitBranch for display
|
|
240
241
|
if (config.tinybirdBranch) {
|
|
241
242
|
const branchName = config.tinybirdBranch; // Sanitized name for Tinybird
|
|
243
|
+
const branchDataMode: BranchDataMode | undefined =
|
|
244
|
+
options.lastPartition || config.branchDataMode === "last_partition"
|
|
245
|
+
? "last_partition"
|
|
246
|
+
: undefined;
|
|
247
|
+
const branchOptions = branchDataMode
|
|
248
|
+
? { branch_data_mode: branchDataMode }
|
|
249
|
+
: undefined;
|
|
242
250
|
|
|
243
251
|
// Always fetch fresh from API to avoid stale cache issues
|
|
244
252
|
const tinybirdBranch = await getOrCreateBranch(
|
|
@@ -247,7 +255,7 @@ export async function runDev(
|
|
|
247
255
|
token: config.token,
|
|
248
256
|
},
|
|
249
257
|
branchName,
|
|
250
|
-
|
|
258
|
+
branchOptions
|
|
251
259
|
);
|
|
252
260
|
|
|
253
261
|
if (!tinybirdBranch.token) {
|
|
@@ -35,6 +35,7 @@ describe("Generate command", () => {
|
|
|
35
35
|
tinybirdBranch: "feature_x",
|
|
36
36
|
isMainBranch: false,
|
|
37
37
|
devMode: "branch",
|
|
38
|
+
branchDataMode: null,
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
@@ -108,6 +109,7 @@ describe("Generate command", () => {
|
|
|
108
109
|
tinybirdBranch: "feature_x",
|
|
109
110
|
isMainBranch: false,
|
|
110
111
|
devMode: "branch",
|
|
112
|
+
branchDataMode: null,
|
|
111
113
|
});
|
|
112
114
|
|
|
113
115
|
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
@@ -167,6 +169,7 @@ describe("Generate command", () => {
|
|
|
167
169
|
tinybirdBranch: "feature_x",
|
|
168
170
|
isMainBranch: false,
|
|
169
171
|
devMode: "branch",
|
|
172
|
+
branchDataMode: null,
|
|
170
173
|
});
|
|
171
174
|
vi.mocked(buildFromInclude).mockRejectedValue(
|
|
172
175
|
new Error("generator failed")
|
|
@@ -1,7 +1,45 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { generatePreviewBranchName } from "./preview.js";
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { generatePreviewBranchName, runPreview } from "./preview.js";
|
|
3
|
+
|
|
4
|
+
vi.mock("../config.js", () => ({
|
|
5
|
+
loadConfigAsync: vi.fn(),
|
|
6
|
+
LOCAL_BASE_URL: "http://localhost:7181",
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
vi.mock("../../generator/index.js", () => ({
|
|
10
|
+
buildFromInclude: vi.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
vi.mock("../../api/branches.js", () => ({
|
|
14
|
+
createBranch: vi.fn(),
|
|
15
|
+
deleteBranch: vi.fn(),
|
|
16
|
+
getBranch: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("../../api/deploy.js", () => ({
|
|
20
|
+
deployToMain: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock("../../api/build.js", () => ({
|
|
24
|
+
buildToTinybird: vi.fn(),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock("../../api/local.js", () => ({
|
|
28
|
+
getLocalTokens: vi.fn(),
|
|
29
|
+
getOrCreateLocalWorkspace: vi.fn(),
|
|
30
|
+
LocalNotRunningError: class LocalNotRunningError extends Error {},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock("../git.js", () => ({
|
|
34
|
+
sanitizeBranchName: (value: string) => value.replace(/[^a-zA-Z0-9]/g, "_"),
|
|
35
|
+
getCurrentGitBranch: vi.fn(() => "feature/test"),
|
|
36
|
+
}));
|
|
3
37
|
|
|
4
38
|
describe("Preview command", () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
vi.clearAllMocks();
|
|
41
|
+
});
|
|
42
|
+
|
|
5
43
|
describe("generatePreviewBranchName", () => {
|
|
6
44
|
it("generates name with tmp_ci prefix", () => {
|
|
7
45
|
const result = generatePreviewBranchName("feature-branch");
|
|
@@ -34,4 +72,97 @@ describe("Preview command", () => {
|
|
|
34
72
|
expect(result1).toBe(result2);
|
|
35
73
|
});
|
|
36
74
|
});
|
|
75
|
+
|
|
76
|
+
describe("branch_data_mode wiring", () => {
|
|
77
|
+
it("uses config-only last_partition when creating cloud preview branch", async () => {
|
|
78
|
+
const { loadConfigAsync } = await import("../config.js");
|
|
79
|
+
const { buildFromInclude } = await import("../../generator/index.js");
|
|
80
|
+
const { getBranch, createBranch } = await import("../../api/branches.js");
|
|
81
|
+
const { deployToMain } = await import("../../api/deploy.js");
|
|
82
|
+
|
|
83
|
+
vi.mocked(loadConfigAsync).mockResolvedValue({
|
|
84
|
+
include: ["test.ts"],
|
|
85
|
+
token: "p.test-token",
|
|
86
|
+
baseUrl: "https://api.tinybird.co",
|
|
87
|
+
configPath: "/test/tinybird.config.json",
|
|
88
|
+
devMode: "branch",
|
|
89
|
+
cwd: "/test",
|
|
90
|
+
gitBranch: "feature-test",
|
|
91
|
+
tinybirdBranch: "feature_test",
|
|
92
|
+
isMainBranch: false,
|
|
93
|
+
branchDataMode: "last_partition",
|
|
94
|
+
});
|
|
95
|
+
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
96
|
+
resources: { datasources: [], pipes: [], connections: [] },
|
|
97
|
+
entities: { datasources: {}, pipes: {}, connections: {}, rawDatasources: [], rawPipes: [], sourceFiles: [] },
|
|
98
|
+
stats: { datasourceCount: 0, pipeCount: 0, connectionCount: 0 },
|
|
99
|
+
});
|
|
100
|
+
vi.mocked(getBranch).mockRejectedValue(new Error("not found"));
|
|
101
|
+
vi.mocked(createBranch).mockResolvedValue({
|
|
102
|
+
id: "b1",
|
|
103
|
+
name: "tmp_ci_feature_test",
|
|
104
|
+
token: "p.branch",
|
|
105
|
+
created_at: "2024-01-01T00:00:00Z",
|
|
106
|
+
});
|
|
107
|
+
vi.mocked(deployToMain).mockResolvedValue({
|
|
108
|
+
success: true,
|
|
109
|
+
result: "success",
|
|
110
|
+
datasourceCount: 0,
|
|
111
|
+
pipeCount: 0,
|
|
112
|
+
connectionCount: 0,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await runPreview();
|
|
116
|
+
expect(createBranch).toHaveBeenCalledWith(
|
|
117
|
+
expect.any(Object),
|
|
118
|
+
"tmp_ci_feature_test",
|
|
119
|
+
{ branch_data_mode: "last_partition" }
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("ignores config branch_data_mode in local mode", async () => {
|
|
124
|
+
const { loadConfigAsync } = await import("../config.js");
|
|
125
|
+
const { buildFromInclude } = await import("../../generator/index.js");
|
|
126
|
+
const { createBranch } = await import("../../api/branches.js");
|
|
127
|
+
const { getLocalTokens, getOrCreateLocalWorkspace } = await import("../../api/local.js");
|
|
128
|
+
const { buildToTinybird } = await import("../../api/build.js");
|
|
129
|
+
|
|
130
|
+
vi.mocked(loadConfigAsync).mockResolvedValue({
|
|
131
|
+
include: ["test.ts"],
|
|
132
|
+
token: "p.test-token",
|
|
133
|
+
baseUrl: "https://api.tinybird.co",
|
|
134
|
+
configPath: "/test/tinybird.config.json",
|
|
135
|
+
devMode: "local",
|
|
136
|
+
cwd: "/test",
|
|
137
|
+
gitBranch: "feature-test",
|
|
138
|
+
tinybirdBranch: "feature_test",
|
|
139
|
+
isMainBranch: false,
|
|
140
|
+
branchDataMode: "last_partition",
|
|
141
|
+
});
|
|
142
|
+
vi.mocked(buildFromInclude).mockResolvedValue({
|
|
143
|
+
resources: { datasources: [], pipes: [], connections: [] },
|
|
144
|
+
entities: { datasources: {}, pipes: {}, connections: {}, rawDatasources: [], rawPipes: [], sourceFiles: [] },
|
|
145
|
+
stats: { datasourceCount: 0, pipeCount: 0, connectionCount: 0 },
|
|
146
|
+
});
|
|
147
|
+
vi.mocked(getLocalTokens).mockResolvedValue({
|
|
148
|
+
admin_token: "admin-token",
|
|
149
|
+
user_token: "user-token",
|
|
150
|
+
workspace_admin_token: "workspace-admin-token",
|
|
151
|
+
});
|
|
152
|
+
vi.mocked(getOrCreateLocalWorkspace).mockResolvedValue({
|
|
153
|
+
workspace: { id: "lw1", name: "tmp_ci_feature_test", token: "local-token" },
|
|
154
|
+
wasCreated: true,
|
|
155
|
+
});
|
|
156
|
+
vi.mocked(buildToTinybird).mockResolvedValue({
|
|
157
|
+
success: true,
|
|
158
|
+
result: "success",
|
|
159
|
+
datasourceCount: 0,
|
|
160
|
+
pipeCount: 0,
|
|
161
|
+
connectionCount: 0,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await runPreview();
|
|
165
|
+
expect(createBranch).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
37
168
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { loadConfigAsync, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } from "../config.js";
|
|
6
6
|
import { buildFromInclude, type BuildFromIncludeResult } from "../../generator/index.js";
|
|
7
|
-
import { createBranch, deleteBranch, getBranch, type TinybirdBranch } from "../../api/branches.js";
|
|
7
|
+
import { createBranch, deleteBranch, getBranch, type CreateBranchOptions, type TinybirdBranch } from "../../api/branches.js";
|
|
8
8
|
import { deployToMain } from "../../api/deploy.js";
|
|
9
9
|
import { buildToTinybird } from "../../api/build.js";
|
|
10
10
|
import {
|
|
@@ -226,6 +226,10 @@ export async function runPreview(options: PreviewCommandOptions = {}): Promise<P
|
|
|
226
226
|
let branch: TinybirdBranch;
|
|
227
227
|
try {
|
|
228
228
|
const apiConfig = { baseUrl: config.baseUrl, token: config.token };
|
|
229
|
+
const branchOptions: CreateBranchOptions | undefined =
|
|
230
|
+
config.branchDataMode === "last_partition"
|
|
231
|
+
? { branch_data_mode: "last_partition" }
|
|
232
|
+
: undefined;
|
|
229
233
|
|
|
230
234
|
// Check if branch already exists and delete it for a fresh start
|
|
231
235
|
try {
|
|
@@ -250,7 +254,7 @@ export async function runPreview(options: PreviewCommandOptions = {}): Promise<P
|
|
|
250
254
|
console.log(`[debug] Creating preview branch: ${previewBranchName}`);
|
|
251
255
|
}
|
|
252
256
|
|
|
253
|
-
branch = await createBranch(apiConfig, previewBranchName);
|
|
257
|
+
branch = await createBranch(apiConfig, previewBranchName, branchOptions);
|
|
254
258
|
|
|
255
259
|
if (debug) {
|
|
256
260
|
console.log(`[debug] Branch created: ${branch.name} (${branch.id})`);
|
package/src/cli/config-types.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* - "local": Use local Tinybird container at localhost:7181
|
|
12
12
|
*/
|
|
13
13
|
export type DevMode = "branch" | "local";
|
|
14
|
+
export type BranchDataMode = "last_partition";
|
|
15
|
+
export const BRANCH_DATA_MODE_VALUES = ["last_partition"] as const satisfies readonly BranchDataMode[];
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Tinybird configuration file structure
|
|
@@ -26,4 +28,6 @@ export interface TinybirdConfig {
|
|
|
26
28
|
baseUrl?: string;
|
|
27
29
|
/** Development mode: "branch" (default) or "local" */
|
|
28
30
|
devMode?: DevMode;
|
|
31
|
+
/** Branch data mode applied on cloud branch creation (shared snake_case key) */
|
|
32
|
+
branch_data_mode?: BranchDataMode;
|
|
29
33
|
}
|
package/src/cli/config.test.ts
CHANGED
|
@@ -327,6 +327,129 @@ describe("Config", () => {
|
|
|
327
327
|
|
|
328
328
|
expect(result.devMode).toBe("local");
|
|
329
329
|
});
|
|
330
|
+
|
|
331
|
+
it("resolves branch_data_mode as last_partition", () => {
|
|
332
|
+
const config = {
|
|
333
|
+
include: ["lib/datasources.ts"],
|
|
334
|
+
token: "test-token",
|
|
335
|
+
branch_data_mode: "last_partition",
|
|
336
|
+
};
|
|
337
|
+
fs.writeFileSync(
|
|
338
|
+
path.join(tempDir, "tinybird.json"),
|
|
339
|
+
JSON.stringify(config)
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const result = loadConfig(tempDir);
|
|
343
|
+
expect(result.branchDataMode).toBe("last_partition");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("defaults branch_data_mode to last_partition when missing", () => {
|
|
347
|
+
const config = {
|
|
348
|
+
include: ["lib/datasources.ts"],
|
|
349
|
+
token: "test-token",
|
|
350
|
+
};
|
|
351
|
+
fs.writeFileSync(
|
|
352
|
+
path.join(tempDir, "tinybird.json"),
|
|
353
|
+
JSON.stringify(config)
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
const result = loadConfig(tempDir);
|
|
357
|
+
expect(result.branchDataMode).toBe("last_partition");
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("defaults empty branch_data_mode to last_partition", () => {
|
|
361
|
+
const config = {
|
|
362
|
+
include: ["lib/datasources.ts"],
|
|
363
|
+
token: "test-token",
|
|
364
|
+
branch_data_mode: " ",
|
|
365
|
+
};
|
|
366
|
+
fs.writeFileSync(
|
|
367
|
+
path.join(tempDir, "tinybird.json"),
|
|
368
|
+
JSON.stringify(config)
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
const result = loadConfig(tempDir);
|
|
372
|
+
expect(result.branchDataMode).toBe("last_partition");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("throws when branch_data_mode is all_partitions", () => {
|
|
376
|
+
const config = {
|
|
377
|
+
include: ["lib/datasources.ts"],
|
|
378
|
+
token: "test-token",
|
|
379
|
+
branch_data_mode: "all_partitions",
|
|
380
|
+
};
|
|
381
|
+
fs.writeFileSync(
|
|
382
|
+
path.join(tempDir, "tinybird.json"),
|
|
383
|
+
JSON.stringify(config)
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
expect(() => loadConfig(tempDir)).toThrow("Invalid branch_data_mode");
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("throws when branch_data_mode is invalid", () => {
|
|
390
|
+
const config = {
|
|
391
|
+
include: ["lib/datasources.ts"],
|
|
392
|
+
token: "test-token",
|
|
393
|
+
branch_data_mode: "invalid",
|
|
394
|
+
};
|
|
395
|
+
fs.writeFileSync(
|
|
396
|
+
path.join(tempDir, "tinybird.json"),
|
|
397
|
+
JSON.stringify(config)
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
expect(() => loadConfig(tempDir)).toThrow("Invalid branch_data_mode");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("warns when branch_data_mode is set with devMode local", () => {
|
|
404
|
+
const config = {
|
|
405
|
+
include: ["lib/datasources.ts"],
|
|
406
|
+
token: "test-token",
|
|
407
|
+
devMode: "local",
|
|
408
|
+
branch_data_mode: "last_partition",
|
|
409
|
+
};
|
|
410
|
+
fs.writeFileSync(
|
|
411
|
+
path.join(tempDir, "tinybird.json"),
|
|
412
|
+
JSON.stringify(config)
|
|
413
|
+
);
|
|
414
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
415
|
+
|
|
416
|
+
loadConfig(tempDir);
|
|
417
|
+
|
|
418
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
419
|
+
expect.stringContaining("branch_data_mode is set")
|
|
420
|
+
);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it("does not warn when branch_data_mode is implicit in local mode", () => {
|
|
424
|
+
const config = {
|
|
425
|
+
include: ["lib/datasources.ts"],
|
|
426
|
+
token: "test-token",
|
|
427
|
+
devMode: "local",
|
|
428
|
+
};
|
|
429
|
+
fs.writeFileSync(
|
|
430
|
+
path.join(tempDir, "tinybird.json"),
|
|
431
|
+
JSON.stringify(config)
|
|
432
|
+
);
|
|
433
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
434
|
+
|
|
435
|
+
loadConfig(tempDir);
|
|
436
|
+
|
|
437
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("throws when legacy branch_data_on_create key is used", () => {
|
|
441
|
+
const config = {
|
|
442
|
+
include: ["lib/datasources.ts"],
|
|
443
|
+
token: "test-token",
|
|
444
|
+
branch_data_on_create: "last_partition",
|
|
445
|
+
};
|
|
446
|
+
fs.writeFileSync(
|
|
447
|
+
path.join(tempDir, "tinybird.json"),
|
|
448
|
+
JSON.stringify(config)
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
expect(() => loadConfig(tempDir)).toThrow("renamed to `branch_data_mode`");
|
|
452
|
+
});
|
|
330
453
|
});
|
|
331
454
|
|
|
332
455
|
describe("loadConfigAsync", () => {
|