@tinybirdco/sdk 0.0.3 → 0.0.4
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 +38 -4
- package/dist/api/local.d.ts +92 -0
- package/dist/api/local.d.ts.map +1 -0
- package/dist/api/local.js +176 -0
- package/dist/api/local.js.map +1 -0
- package/dist/api/local.test.d.ts +2 -0
- package/dist/api/local.test.d.ts.map +1 -0
- package/dist/api/local.test.js +182 -0
- package/dist/api/local.test.js.map +1 -0
- package/dist/cli/commands/build.d.ts +3 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +97 -47
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +9 -2
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +56 -31
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/config.d.ts +14 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +7 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/config.test.js +29 -0
- package/dist/cli/config.test.js.map +1 -1
- package/dist/cli/index.js +39 -3
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/local.test.ts +250 -0
- package/src/api/local.ts +270 -0
- package/src/cli/commands/build.ts +120 -54
- package/src/cli/commands/dev.ts +76 -38
- package/src/cli/config.test.ts +47 -0
- package/src/cli/config.ts +20 -0
- package/src/cli/index.ts +39 -3
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
* Build command - generates and pushes resources to Tinybird
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { loadConfig, type ResolvedConfig } from "../config.js";
|
|
5
|
+
import { loadConfig, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } 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 { deployToMain } from "../../api/deploy.js";
|
|
9
9
|
import { getOrCreateBranch } from "../../api/branches.js";
|
|
10
|
+
import {
|
|
11
|
+
getLocalTokens,
|
|
12
|
+
getOrCreateLocalWorkspace,
|
|
13
|
+
getLocalWorkspaceName,
|
|
14
|
+
LocalNotRunningError,
|
|
15
|
+
} from "../../api/local.js";
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* Build command options
|
|
@@ -20,6 +26,8 @@ export interface BuildCommandOptions {
|
|
|
20
26
|
tokenOverride?: string;
|
|
21
27
|
/** Use /v1/deploy instead of /v1/build (for main branch) */
|
|
22
28
|
useDeployEndpoint?: boolean;
|
|
29
|
+
/** Override the devMode from config */
|
|
30
|
+
devModeOverride?: DevMode;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
/**
|
|
@@ -86,84 +94,142 @@ export async function runBuild(options: BuildCommandOptions = {}): Promise<Build
|
|
|
86
94
|
};
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
let effectiveToken = options.tokenOverride ?? config.token;
|
|
92
|
-
let useDeployEndpoint = options.useDeployEndpoint ?? config.isMainBranch;
|
|
93
|
-
|
|
94
|
-
// For feature branches, get or create the Tinybird branch and use its token
|
|
97
|
+
// Determine devMode
|
|
98
|
+
const devMode = options.devModeOverride ?? config.devMode;
|
|
95
99
|
const debug = !!process.env.TINYBIRD_DEBUG;
|
|
100
|
+
|
|
96
101
|
if (debug) {
|
|
97
|
-
console.log(`[debug]
|
|
98
|
-
console.log(`[debug] tinybirdBranch: ${config.tinybirdBranch}`);
|
|
99
|
-
console.log(`[debug] tokenOverride: ${!!options.tokenOverride}`);
|
|
102
|
+
console.log(`[debug] devMode: ${devMode}`);
|
|
100
103
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
|
|
105
|
+
let deployResult: BuildApiResult;
|
|
106
|
+
|
|
107
|
+
// Handle local mode
|
|
108
|
+
if (devMode === "local") {
|
|
105
109
|
try {
|
|
106
|
-
|
|
110
|
+
// Get tokens from local container
|
|
111
|
+
if (debug) {
|
|
112
|
+
console.log(`[debug] Getting local tokens from ${LOCAL_BASE_URL}/tokens`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const localTokens = await getLocalTokens();
|
|
116
|
+
|
|
117
|
+
// Get or create workspace based on branch name
|
|
118
|
+
const workspaceName = getLocalWorkspaceName(config.tinybirdBranch, config.cwd);
|
|
119
|
+
if (debug) {
|
|
120
|
+
console.log(`[debug] Using local workspace: ${workspaceName}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { workspace, wasCreated } = await getOrCreateLocalWorkspace(localTokens, workspaceName);
|
|
124
|
+
if (debug) {
|
|
125
|
+
console.log(`[debug] Workspace ${wasCreated ? "created" : "found"}: ${workspace.name}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Always use /v1/build for local (no deploy endpoint)
|
|
129
|
+
deployResult = await buildToTinybird(
|
|
107
130
|
{
|
|
108
|
-
baseUrl:
|
|
109
|
-
token:
|
|
131
|
+
baseUrl: LOCAL_BASE_URL,
|
|
132
|
+
token: workspace.token,
|
|
110
133
|
},
|
|
111
|
-
|
|
134
|
+
buildResult.resources
|
|
112
135
|
);
|
|
113
|
-
|
|
114
|
-
if (
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof LocalNotRunningError) {
|
|
115
138
|
return {
|
|
116
139
|
success: false,
|
|
117
140
|
build: buildResult,
|
|
118
|
-
error:
|
|
141
|
+
error: error.message,
|
|
119
142
|
durationMs: Date.now() - startTime,
|
|
120
143
|
};
|
|
121
144
|
}
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
build: buildResult,
|
|
148
|
+
error: `Local build failed: ${(error as Error).message}`,
|
|
149
|
+
durationMs: Date.now() - startTime,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
// Branch mode (default) - existing logic
|
|
154
|
+
// Deploy to Tinybird
|
|
155
|
+
// Determine token and endpoint based on git branch
|
|
156
|
+
let effectiveToken = options.tokenOverride ?? config.token;
|
|
157
|
+
// Use deploy endpoint if on main branch OR if no branch can be detected
|
|
158
|
+
let useDeployEndpoint = options.useDeployEndpoint ?? (config.isMainBranch || !config.tinybirdBranch);
|
|
122
159
|
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
if (debug) {
|
|
161
|
+
console.log(`[debug] isMainBranch: ${config.isMainBranch}`);
|
|
162
|
+
console.log(`[debug] tinybirdBranch: ${config.tinybirdBranch}`);
|
|
163
|
+
console.log(`[debug] tokenOverride: ${!!options.tokenOverride}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// For feature branches, get or create the Tinybird branch and use its token
|
|
167
|
+
if (!config.isMainBranch && config.tinybirdBranch && !options.tokenOverride) {
|
|
125
168
|
if (debug) {
|
|
126
|
-
console.log(`[debug]
|
|
169
|
+
console.log(`[debug] Getting/creating Tinybird branch: ${config.tinybirdBranch}`);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const tinybirdBranch = await getOrCreateBranch(
|
|
173
|
+
{
|
|
174
|
+
baseUrl: config.baseUrl,
|
|
175
|
+
token: config.token,
|
|
176
|
+
},
|
|
177
|
+
config.tinybirdBranch
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (!tinybirdBranch.token) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
build: buildResult,
|
|
184
|
+
error: `Branch '${config.tinybirdBranch}' was created but no token was returned.`,
|
|
185
|
+
durationMs: Date.now() - startTime,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
effectiveToken = tinybirdBranch.token;
|
|
190
|
+
useDeployEndpoint = false; // Always use /v1/build for branches
|
|
191
|
+
if (debug) {
|
|
192
|
+
console.log(`[debug] Using branch token for branch: ${config.tinybirdBranch}`);
|
|
193
|
+
}
|
|
194
|
+
} catch (error) {
|
|
195
|
+
return {
|
|
196
|
+
success: false,
|
|
197
|
+
build: buildResult,
|
|
198
|
+
error: `Failed to get/create branch: ${(error as Error).message}`,
|
|
199
|
+
durationMs: Date.now() - startTime,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
// Use /v1/deploy for main branch, /v1/build for feature branches
|
|
206
|
+
if (useDeployEndpoint) {
|
|
207
|
+
deployResult = await deployToMain(
|
|
208
|
+
{
|
|
209
|
+
baseUrl: config.baseUrl,
|
|
210
|
+
token: effectiveToken,
|
|
211
|
+
},
|
|
212
|
+
buildResult.resources
|
|
213
|
+
);
|
|
214
|
+
} else {
|
|
215
|
+
deployResult = await buildToTinybird(
|
|
216
|
+
{
|
|
217
|
+
baseUrl: config.baseUrl,
|
|
218
|
+
token: effectiveToken,
|
|
219
|
+
},
|
|
220
|
+
buildResult.resources
|
|
221
|
+
);
|
|
127
222
|
}
|
|
128
223
|
} catch (error) {
|
|
129
224
|
return {
|
|
130
225
|
success: false,
|
|
131
226
|
build: buildResult,
|
|
132
|
-
error: `
|
|
227
|
+
error: `Deploy failed: ${(error as Error).message}`,
|
|
133
228
|
durationMs: Date.now() - startTime,
|
|
134
229
|
};
|
|
135
230
|
}
|
|
136
231
|
}
|
|
137
232
|
|
|
138
|
-
let deployResult: BuildApiResult;
|
|
139
|
-
try {
|
|
140
|
-
// Use /v1/deploy for main branch, /v1/build for feature branches
|
|
141
|
-
if (useDeployEndpoint) {
|
|
142
|
-
deployResult = await deployToMain(
|
|
143
|
-
{
|
|
144
|
-
baseUrl: config.baseUrl,
|
|
145
|
-
token: effectiveToken,
|
|
146
|
-
},
|
|
147
|
-
buildResult.resources
|
|
148
|
-
);
|
|
149
|
-
} else {
|
|
150
|
-
deployResult = await buildToTinybird(
|
|
151
|
-
{
|
|
152
|
-
baseUrl: config.baseUrl,
|
|
153
|
-
token: effectiveToken,
|
|
154
|
-
},
|
|
155
|
-
buildResult.resources
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
return {
|
|
160
|
-
success: false,
|
|
161
|
-
build: buildResult,
|
|
162
|
-
error: `Deploy failed: ${(error as Error).message}`,
|
|
163
|
-
durationMs: Date.now() - startTime,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
233
|
if (!deployResult.success) {
|
|
168
234
|
return {
|
|
169
235
|
success: false,
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { watch } from "chokidar";
|
|
7
|
-
import { loadConfig, configExists, findConfigFile, hasValidToken, updateConfig, type ResolvedConfig } from "../config.js";
|
|
7
|
+
import { loadConfig, configExists, findConfigFile, hasValidToken, updateConfig, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } from "../config.js";
|
|
8
8
|
import { runBuild, type BuildCommandResult } from "./build.js";
|
|
9
9
|
import { getOrCreateBranch, type TinybirdBranch } from "../../api/branches.js";
|
|
10
10
|
import { browserLogin } from "../auth.js";
|
|
@@ -13,6 +13,12 @@ import {
|
|
|
13
13
|
validatePipeSchemas,
|
|
14
14
|
type SchemaValidationResult,
|
|
15
15
|
} from "../utils/schema-validation.js";
|
|
16
|
+
import {
|
|
17
|
+
getLocalTokens,
|
|
18
|
+
getOrCreateLocalWorkspace,
|
|
19
|
+
getLocalWorkspaceName,
|
|
20
|
+
type LocalWorkspace,
|
|
21
|
+
} from "../../api/local.js";
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* Login result info
|
|
@@ -44,6 +50,8 @@ export interface DevCommandOptions {
|
|
|
44
50
|
onLoginComplete?: (info: LoginInfo) => void;
|
|
45
51
|
/** Callback when schema validation completes */
|
|
46
52
|
onSchemaValidation?: (result: SchemaValidationResult) => void;
|
|
53
|
+
/** Override the devMode from config */
|
|
54
|
+
devModeOverride?: DevMode;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
/**
|
|
@@ -54,10 +62,14 @@ export interface BranchReadyInfo {
|
|
|
54
62
|
gitBranch: string | null;
|
|
55
63
|
/** Whether we're on the main branch */
|
|
56
64
|
isMainBranch: boolean;
|
|
57
|
-
/** Tinybird branch info (null if on main) */
|
|
65
|
+
/** Tinybird branch info (null if on main or local mode) */
|
|
58
66
|
tinybirdBranch?: TinybirdBranch;
|
|
59
67
|
/** Whether the branch was newly created */
|
|
60
68
|
wasCreated?: boolean;
|
|
69
|
+
/** Whether using local mode */
|
|
70
|
+
isLocal?: boolean;
|
|
71
|
+
/** Local workspace info (only in local mode) */
|
|
72
|
+
localWorkspace?: LocalWorkspace;
|
|
61
73
|
}
|
|
62
74
|
|
|
63
75
|
/**
|
|
@@ -98,8 +110,19 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
|
|
|
98
110
|
);
|
|
99
111
|
}
|
|
100
112
|
|
|
101
|
-
//
|
|
102
|
-
|
|
113
|
+
// Load config first to determine devMode
|
|
114
|
+
let config: ResolvedConfig;
|
|
115
|
+
try {
|
|
116
|
+
config = loadConfig(cwd);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Determine devMode
|
|
122
|
+
const devMode = options.devModeOverride ?? config.devMode;
|
|
123
|
+
|
|
124
|
+
// Check if authentication is set up, if not trigger login (skip for local mode)
|
|
125
|
+
if (devMode !== "local" && !hasValidToken(cwd)) {
|
|
103
126
|
console.log("No authentication found. Starting login flow...\n");
|
|
104
127
|
|
|
105
128
|
const authResult = await browserLogin();
|
|
@@ -134,51 +157,65 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
|
|
|
134
157
|
workspaceName: authResult.workspaceName,
|
|
135
158
|
userEmail: authResult.userEmail,
|
|
136
159
|
});
|
|
137
|
-
}
|
|
138
160
|
|
|
139
|
-
|
|
140
|
-
let config: ResolvedConfig;
|
|
141
|
-
try {
|
|
161
|
+
// Reload config after login
|
|
142
162
|
config = loadConfig(cwd);
|
|
143
|
-
} catch (error) {
|
|
144
|
-
throw error;
|
|
145
163
|
}
|
|
146
164
|
|
|
147
|
-
// Determine effective token based on
|
|
165
|
+
// Determine effective token and branch info based on devMode
|
|
148
166
|
let effectiveToken = config.token;
|
|
167
|
+
let effectiveBaseUrl = config.baseUrl;
|
|
149
168
|
let branchInfo: BranchReadyInfo = {
|
|
150
169
|
gitBranch: config.gitBranch,
|
|
151
170
|
isMainBranch: config.isMainBranch,
|
|
152
171
|
};
|
|
153
172
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
// Always fetch fresh from API to avoid stale cache issues
|
|
160
|
-
const tinybirdBranch = await getOrCreateBranch(
|
|
161
|
-
{
|
|
162
|
-
baseUrl: config.baseUrl,
|
|
163
|
-
token: config.token,
|
|
164
|
-
},
|
|
165
|
-
branchName
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
if (!tinybirdBranch.token) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
`Branch '${branchName}' was created but no token was returned. ` +
|
|
171
|
-
`This may be an API issue.`
|
|
172
|
-
);
|
|
173
|
-
}
|
|
173
|
+
if (devMode === "local") {
|
|
174
|
+
// Local mode: get tokens from local container and set up workspace
|
|
175
|
+
const localTokens = await getLocalTokens();
|
|
176
|
+
const workspaceName = getLocalWorkspaceName(config.tinybirdBranch, config.cwd);
|
|
177
|
+
const { workspace, wasCreated } = await getOrCreateLocalWorkspace(localTokens, workspaceName);
|
|
174
178
|
|
|
175
|
-
effectiveToken =
|
|
179
|
+
effectiveToken = workspace.token;
|
|
180
|
+
effectiveBaseUrl = LOCAL_BASE_URL;
|
|
176
181
|
branchInfo = {
|
|
177
|
-
gitBranch: config.gitBranch,
|
|
178
|
-
isMainBranch: false,
|
|
179
|
-
|
|
180
|
-
|
|
182
|
+
gitBranch: config.gitBranch,
|
|
183
|
+
isMainBranch: false, // Local mode always uses build, not deploy
|
|
184
|
+
isLocal: true,
|
|
185
|
+
localWorkspace: workspace,
|
|
186
|
+
wasCreated,
|
|
181
187
|
};
|
|
188
|
+
} else {
|
|
189
|
+
// Branch mode: use Tinybird cloud with branches
|
|
190
|
+
// If we're on a feature branch, get or create the Tinybird branch
|
|
191
|
+
// Use tinybirdBranch (sanitized name) for Tinybird API, gitBranch for display
|
|
192
|
+
if (!config.isMainBranch && config.tinybirdBranch) {
|
|
193
|
+
const branchName = config.tinybirdBranch; // Sanitized name for Tinybird
|
|
194
|
+
|
|
195
|
+
// Always fetch fresh from API to avoid stale cache issues
|
|
196
|
+
const tinybirdBranch = await getOrCreateBranch(
|
|
197
|
+
{
|
|
198
|
+
baseUrl: config.baseUrl,
|
|
199
|
+
token: config.token,
|
|
200
|
+
},
|
|
201
|
+
branchName
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (!tinybirdBranch.token) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Branch '${branchName}' was created but no token was returned. ` +
|
|
207
|
+
`This may be an API issue.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
effectiveToken = tinybirdBranch.token;
|
|
212
|
+
branchInfo = {
|
|
213
|
+
gitBranch: config.gitBranch, // Original git branch name for display
|
|
214
|
+
isMainBranch: false,
|
|
215
|
+
tinybirdBranch,
|
|
216
|
+
wasCreated: tinybirdBranch.wasCreated ?? false,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
182
219
|
}
|
|
183
220
|
|
|
184
221
|
// Notify about branch readiness
|
|
@@ -212,7 +249,8 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
|
|
|
212
249
|
const result = await runBuild({
|
|
213
250
|
cwd: config.cwd,
|
|
214
251
|
tokenOverride: effectiveToken,
|
|
215
|
-
useDeployEndpoint: config.isMainBranch,
|
|
252
|
+
useDeployEndpoint: devMode !== "local" && config.isMainBranch,
|
|
253
|
+
devModeOverride: devMode,
|
|
216
254
|
});
|
|
217
255
|
options.onBuildComplete?.(result);
|
|
218
256
|
|
|
@@ -234,7 +272,7 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
|
|
|
234
272
|
const validation = await validatePipeSchemas({
|
|
235
273
|
entities: result.build.entities,
|
|
236
274
|
pipeNames: changedPipes,
|
|
237
|
-
baseUrl:
|
|
275
|
+
baseUrl: effectiveBaseUrl,
|
|
238
276
|
token: effectiveToken,
|
|
239
277
|
});
|
|
240
278
|
|
package/src/cli/config.test.ts
CHANGED
|
@@ -267,6 +267,53 @@ describe("Config", () => {
|
|
|
267
267
|
|
|
268
268
|
expect(() => loadConfig(tempDir)).toThrow("Failed to parse");
|
|
269
269
|
});
|
|
270
|
+
|
|
271
|
+
it("defaults devMode to branch when not specified", () => {
|
|
272
|
+
const config = {
|
|
273
|
+
include: ["lib/datasources.ts"],
|
|
274
|
+
token: "test-token",
|
|
275
|
+
};
|
|
276
|
+
fs.writeFileSync(
|
|
277
|
+
path.join(tempDir, "tinybird.json"),
|
|
278
|
+
JSON.stringify(config)
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const result = loadConfig(tempDir);
|
|
282
|
+
|
|
283
|
+
expect(result.devMode).toBe("branch");
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("loads devMode as branch when explicitly set", () => {
|
|
287
|
+
const config = {
|
|
288
|
+
include: ["lib/datasources.ts"],
|
|
289
|
+
token: "test-token",
|
|
290
|
+
devMode: "branch",
|
|
291
|
+
};
|
|
292
|
+
fs.writeFileSync(
|
|
293
|
+
path.join(tempDir, "tinybird.json"),
|
|
294
|
+
JSON.stringify(config)
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const result = loadConfig(tempDir);
|
|
298
|
+
|
|
299
|
+
expect(result.devMode).toBe("branch");
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("loads devMode as local when set", () => {
|
|
303
|
+
const config = {
|
|
304
|
+
include: ["lib/datasources.ts"],
|
|
305
|
+
token: "test-token",
|
|
306
|
+
devMode: "local",
|
|
307
|
+
};
|
|
308
|
+
fs.writeFileSync(
|
|
309
|
+
path.join(tempDir, "tinybird.json"),
|
|
310
|
+
JSON.stringify(config)
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const result = loadConfig(tempDir);
|
|
314
|
+
|
|
315
|
+
expect(result.devMode).toBe("local");
|
|
316
|
+
});
|
|
270
317
|
});
|
|
271
318
|
|
|
272
319
|
describe("updateConfig", () => {
|
package/src/cli/config.ts
CHANGED
|
@@ -6,6 +6,13 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import { getCurrentGitBranch, isMainBranch, getTinybirdBranchName } from "./git.js";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Development mode options
|
|
11
|
+
* - "branch": Use Tinybird cloud with branches (default)
|
|
12
|
+
* - "local": Use local Tinybird container at localhost:7181
|
|
13
|
+
*/
|
|
14
|
+
export type DevMode = "branch" | "local";
|
|
15
|
+
|
|
9
16
|
/**
|
|
10
17
|
* Tinybird configuration file structure
|
|
11
18
|
*/
|
|
@@ -18,6 +25,8 @@ export interface TinybirdConfig {
|
|
|
18
25
|
token: string;
|
|
19
26
|
/** Tinybird API base URL (optional, defaults to EU region) */
|
|
20
27
|
baseUrl?: string;
|
|
28
|
+
/** Development mode: "branch" (default) or "local" */
|
|
29
|
+
devMode?: DevMode;
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
/**
|
|
@@ -40,6 +49,8 @@ export interface ResolvedConfig {
|
|
|
40
49
|
tinybirdBranch: string | null;
|
|
41
50
|
/** Whether we're on the main/master branch */
|
|
42
51
|
isMainBranch: boolean;
|
|
52
|
+
/** Development mode: "branch" or "local" */
|
|
53
|
+
devMode: DevMode;
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
/**
|
|
@@ -47,6 +58,11 @@ export interface ResolvedConfig {
|
|
|
47
58
|
*/
|
|
48
59
|
const DEFAULT_BASE_URL = "https://api.tinybird.co";
|
|
49
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Local Tinybird base URL
|
|
63
|
+
*/
|
|
64
|
+
export const LOCAL_BASE_URL = "http://localhost:7181";
|
|
65
|
+
|
|
50
66
|
/**
|
|
51
67
|
* Config file name
|
|
52
68
|
*/
|
|
@@ -243,6 +259,9 @@ export function loadConfig(cwd: string = process.cwd()): ResolvedConfig {
|
|
|
243
259
|
const gitBranch = getCurrentGitBranch();
|
|
244
260
|
const tinybirdBranch = getTinybirdBranchName();
|
|
245
261
|
|
|
262
|
+
// Resolve devMode (default to "branch")
|
|
263
|
+
const devMode: DevMode = config.devMode ?? "branch";
|
|
264
|
+
|
|
246
265
|
return {
|
|
247
266
|
include,
|
|
248
267
|
token: resolvedToken,
|
|
@@ -252,6 +271,7 @@ export function loadConfig(cwd: string = process.cwd()): ResolvedConfig {
|
|
|
252
271
|
gitBranch,
|
|
253
272
|
tinybirdBranch,
|
|
254
273
|
isMainBranch: isMainBranch(),
|
|
274
|
+
devMode,
|
|
255
275
|
};
|
|
256
276
|
}
|
|
257
277
|
|
package/src/cli/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
runBranchStatus,
|
|
24
24
|
runBranchDelete,
|
|
25
25
|
} from "./commands/branch.js";
|
|
26
|
+
import type { DevMode } from "./config.js";
|
|
26
27
|
|
|
27
28
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
28
29
|
const packageJson = JSON.parse(
|
|
@@ -137,14 +138,27 @@ function createCli(): Command {
|
|
|
137
138
|
.description("Build and push resources to Tinybird")
|
|
138
139
|
.option("--dry-run", "Generate without pushing to API")
|
|
139
140
|
.option("--debug", "Show debug output including API requests/responses")
|
|
141
|
+
.option("--local", "Use local Tinybird container")
|
|
142
|
+
.option("--branch", "Use Tinybird cloud with branches")
|
|
140
143
|
.action(async (options) => {
|
|
141
144
|
if (options.debug) {
|
|
142
145
|
process.env.TINYBIRD_DEBUG = "1";
|
|
143
146
|
}
|
|
144
|
-
|
|
147
|
+
|
|
148
|
+
// Determine devMode override
|
|
149
|
+
let devModeOverride: DevMode | undefined;
|
|
150
|
+
if (options.local) {
|
|
151
|
+
devModeOverride = "local";
|
|
152
|
+
} else if (options.branch) {
|
|
153
|
+
devModeOverride = "branch";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const modeLabel = devModeOverride === "local" ? " (local)" : "";
|
|
157
|
+
console.log(`[${formatTime()}] Building${modeLabel}...\n`);
|
|
145
158
|
|
|
146
159
|
const result = await runBuild({
|
|
147
160
|
dryRun: options.dryRun,
|
|
161
|
+
devModeOverride,
|
|
148
162
|
});
|
|
149
163
|
|
|
150
164
|
if (!result.success) {
|
|
@@ -190,12 +204,23 @@ function createCli(): Command {
|
|
|
190
204
|
program
|
|
191
205
|
.command("dev")
|
|
192
206
|
.description("Watch for changes and sync with Tinybird")
|
|
193
|
-
.
|
|
207
|
+
.option("--local", "Use local Tinybird container")
|
|
208
|
+
.option("--branch", "Use Tinybird cloud with branches")
|
|
209
|
+
.action(async (options) => {
|
|
210
|
+
// Determine devMode override
|
|
211
|
+
let devModeOverride: DevMode | undefined;
|
|
212
|
+
if (options.local) {
|
|
213
|
+
devModeOverride = "local";
|
|
214
|
+
} else if (options.branch) {
|
|
215
|
+
devModeOverride = "branch";
|
|
216
|
+
}
|
|
217
|
+
|
|
194
218
|
console.log(`tinybird dev v${VERSION}`);
|
|
195
219
|
console.log("Loading config from tinybird.json...\n");
|
|
196
220
|
|
|
197
221
|
try {
|
|
198
222
|
const controller = await runDev({
|
|
223
|
+
devModeOverride,
|
|
199
224
|
onLoginComplete: (info) => {
|
|
200
225
|
console.log("\nAuthentication successful!");
|
|
201
226
|
if (info.workspaceName) {
|
|
@@ -207,7 +232,18 @@ function createCli(): Command {
|
|
|
207
232
|
console.log("");
|
|
208
233
|
},
|
|
209
234
|
onBranchReady: (info) => {
|
|
210
|
-
if (info.
|
|
235
|
+
if (info.isLocal) {
|
|
236
|
+
// Local mode
|
|
237
|
+
const workspaceName = info.localWorkspace?.name ?? "unknown";
|
|
238
|
+
if (info.wasCreated) {
|
|
239
|
+
console.log(`Using local Tinybird container`);
|
|
240
|
+
console.log(`Creating local workspace '${workspaceName}'...`);
|
|
241
|
+
console.log("Workspace created.\n");
|
|
242
|
+
} else {
|
|
243
|
+
console.log(`Using local Tinybird container`);
|
|
244
|
+
console.log(`Using existing local workspace '${workspaceName}'\n`);
|
|
245
|
+
}
|
|
246
|
+
} else if (info.isMainBranch) {
|
|
211
247
|
console.log("On main branch - deploying to workspace\n");
|
|
212
248
|
} else if (info.gitBranch) {
|
|
213
249
|
const tinybirdName = info.tinybirdBranch?.name ?? info.gitBranch;
|