Skip to content

Commit 82a76d3

Browse files
authored
Update tRPC template for lazy initialization (#3974)
Aligns tRPC template with lazy warehouse initialization. ## Changes - Add .env.example with DATABRICKS_WAREHOUSE_ID - Integrate dotenv loading in template - Update package dependencies - Fix test environment setup - Export appRouter for testing ## Dependencies - Requires PR #3973 (lazy warehouse resolution) ## Testing - Template files updated - Follows lazy init pattern
1 parent 6f4b03f commit 82a76d3

File tree

10 files changed

+35
-39
lines changed

10 files changed

+35
-39
lines changed

experimental/apps-mcp/lib/providers/io/provider.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,19 @@ func (p *Provider) RegisterTools(server *mcpsdk.Server) error {
4848

4949
// Register scaffold_data_app
5050
type ScaffoldInput struct {
51-
WorkDir string `json:"work_dir" jsonschema:"required" jsonschema_description:"Absolute path to the work directory"`
52-
ForceRewrite bool `json:"force_rewrite,omitempty" jsonschema_description:"Overwrite existing files if directory is not empty"`
51+
WorkDir string `json:"work_dir" jsonschema:"required" jsonschema_description:"Absolute path to the work directory"`
5352
}
5453

5554
mcpsdk.AddTool(server,
5655
&mcpsdk.Tool{
5756
Name: "scaffold_data_app",
58-
Description: "Initialize a project by copying template files from the default TypeScript (tRPC + React) template to a work directory. Supports force rewrite to wipe and recreate the directory. It sets up a basic project structure, and should be ALWAYS used as the first step in creating a new data or web app.",
57+
Description: "Initialize a project by copying template files from the default TypeScript (tRPC + React) template to a work directory. It sets up a basic project structure, and should be ALWAYS used as the first step in creating a new data or web app.",
5958
},
6059
func(ctx context.Context, req *mcpsdk.CallToolRequest, args ScaffoldInput) (*mcpsdk.CallToolResult, any, error) {
6160
log.Debugf(ctx, "scaffold_data_app called: work_dir=%s", args.WorkDir)
6261

6362
scaffoldArgs := &ScaffoldArgs{
64-
WorkDir: args.WorkDir,
65-
ForceRewrite: args.ForceRewrite,
63+
WorkDir: args.WorkDir,
6664
}
6765

6866
result, err := p.Scaffold(ctx, scaffoldArgs)

experimental/apps-mcp/lib/providers/io/scaffold.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ import (
66
"errors"
77
"fmt"
88
"io/fs"
9+
"os"
910
"path/filepath"
1011

12+
"github.com/databricks/cli/experimental/apps-mcp/lib/middlewares"
1113
"github.com/databricks/cli/experimental/apps-mcp/lib/templates"
1214
"github.com/databricks/cli/libs/filer"
1315
"github.com/databricks/cli/libs/log"
1416
)
1517

1618
// ScaffoldArgs contains arguments for scaffolding operation
1719
type ScaffoldArgs struct {
18-
WorkDir string `json:"work_dir"`
19-
ForceRewrite bool `json:"force_rewrite,omitempty"`
20+
WorkDir string `json:"work_dir"`
2021
}
2122

2223
// ScaffoldResult contains the result of a scaffold operation
@@ -52,16 +53,14 @@ func (p *Provider) Scaffold(ctx context.Context, args *ScaffoldArgs) (*ScaffoldR
5253
return nil, err
5354
}
5455

55-
if len(entries) > 0 && !args.ForceRewrite {
56-
return nil, errors.New("work_dir is not empty (use force_rewrite to overwrite)")
56+
allowedEntries := map[string]bool{
57+
".git": true,
58+
".claude": true,
5759
}
5860

59-
// Clear directory if force_rewrite
60-
if args.ForceRewrite {
61-
for _, entry := range entries {
62-
if err := f.Delete(ctx, entry.Name(), filer.DeleteRecursively); err != nil {
63-
return nil, fmt.Errorf("failed to delete %s: %w", entry.Name(), err)
64-
}
61+
for _, entry := range entries {
62+
if !allowedEntries[entry.Name()] {
63+
return nil, fmt.Errorf("work_dir is not empty: %s", entry.Name())
6564
}
6665
}
6766
} else if !errors.Is(err, fs.ErrNotExist) {
@@ -93,6 +92,19 @@ func (p *Provider) Scaffold(ctx context.Context, args *ScaffoldArgs) (*ScaffoldR
9392
filesCopied++
9493
}
9594

95+
// write .env file
96+
warehouseID, err := middlewares.GetWarehouseID(ctx)
97+
if err != nil {
98+
return nil, fmt.Errorf("failed to get warehouse ID: %w", err)
99+
}
100+
host := middlewares.MustGetDatabricksClient(ctx).Config.Host
101+
102+
envContent := fmt.Sprintf("DATABRICKS_WAREHOUSE_ID=%s\nDATABRICKS_HOST=%s", warehouseID, host)
103+
envPath := filepath.Join(workDir, ".env")
104+
if err := os.WriteFile(envPath, []byte(envContent), 0o644); err != nil {
105+
return nil, fmt.Errorf("failed to write .env file: %w", err)
106+
}
107+
96108
log.Infof(ctx, "scaffolded project (template=%s, work_dir=%s, files=%d)",
97109
template.Name(), workDir, filesCopied)
98110

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DATABRICKS_WAREHOUSE_ID=<warehouse_id>

experimental/apps-mcp/lib/templates/trpc/server/drizzle.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'dotenv/config';
21
import { defineConfig } from 'drizzle-kit';
32

43
export default defineConfig({

experimental/apps-mcp/lib/templates/trpc/server/package-lock.json

Lines changed: 0 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

experimental/apps-mcp/lib/templates/trpc/server/package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@
44
"scripts": {
55
"build": "tsc -p tsconfig.json",
66
"check": "tsc -p tsconfig.json --noEmit",
7-
"start": "tsx src/index.ts",
8-
"dev": "tsx watch src/index.ts",
9-
"db:push": "drizzle-kit push --force",
7+
"start": "tsx --env-file-if-exists=../.env src/index.ts",
8+
"dev": "tsx --env-file-if-exists=../.env watch src/index.ts",
9+
"db:push": "drizzle-kit --env-file-if-exists=../.env push --force",
1010
"db:push-ci": "yes | npm run db:push",
1111
"lint": "eslint --cache src/index.ts",
12-
"test": "node --test --import tsx src/*.test.ts"
12+
"test": "node --env-file-if-exists=../.env --test --import tsx src/*.test.ts"
1313
},
1414
"dependencies": {
1515
"@databricks/sdk-experimental": "^0.14.2",
1616
"@databricks/sql": "^1.12.0",
1717
"@trpc/server": "^11.6.0",
1818
"@types/express": "^5.0.3",
1919
"cors": "2.8.5",
20-
"dotenv": "16.4.7",
2120
"drizzle-orm": "0.40.0",
2221
"express": "^5.1.0",
2322
"pg": "8.14.0",

experimental/apps-mcp/lib/templates/trpc/server/src/databricks.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { type HeadersInit, Headers, ApiClient, Config } from "@databricks/sdk-ex
2222
import { DBSQLClient } from "@databricks/sql";
2323
import { z } from "zod";
2424

25-
// Environment variables
2625
const warehouseId: string = process.env["DATABRICKS_WAREHOUSE_ID"] || "";
2726
const httpPath = `/sql/1.0/warehouses/${warehouseId}`;
2827

experimental/apps-mcp/lib/templates/trpc/server/src/db/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'dotenv/config';
21
import { drizzle } from 'drizzle-orm/node-postgres';
32
import { Pool } from 'pg';
43
import * as schema from './schema';

experimental/apps-mcp/lib/templates/trpc/server/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { initTRPC } from "@trpc/server";
22
import { createExpressMiddleware } from "@trpc/server/adapters/express";
33
import express from "express";
4-
import "dotenv/config";
54
import superjson from "superjson";
65
import path from "node:path";
76
import { z } from "zod";
@@ -29,6 +28,7 @@ const appRouter = router({
2928
// }),
3029
});
3130

31+
export { appRouter };
3232
export type AppRouter = typeof appRouter;
3333

3434
export const app = express();

experimental/apps-mcp/lib/templates/trpc/server/src/server.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { test } from "node:test";
22
import { strict as assert } from "node:assert";
33
import type { Server } from "node:http";
4+
import path from "node:path";
5+
import superjson from "superjson";
46

57
test("server starts and responds to healthcheck", async () => {
68
// dynamic import to ensure env vars are set first
@@ -38,7 +40,7 @@ test("server starts and responds to healthcheck", async () => {
3840
// const { initTRPC } = await import("@trpc/server");
3941
//
4042
// // create tRPC caller - no HTTP server needed
41-
// const t = initTRPC.create();
43+
// const t = initTRPC.create({transformer: superjson});
4244
// const caller = t.createCallerFactory(appRouter)({});
4345
//
4446
// const result = await caller.getUsers();
@@ -58,7 +60,7 @@ test("server starts and responds to healthcheck", async () => {
5860
// const t = initTRPC.create();
5961
// const caller = t.createCallerFactory(appRouter)({});
6062
//
61-
// const result = await caller.getMetrics({ category: "sales" });
63+
// const result = await caller['getMetrics']({ category: "sales" });
6264
//
6365
// assert.ok(Array.isArray(result));
6466
// // add assertions for your expected data structure

0 commit comments

Comments
 (0)