Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/api/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,36 @@ describe("Build API", () => {
const allValues = capturedFormData!.getAll("data_project://");
expect(allValues.length).toBe(3);
});

it("includes connections in form data", async () => {
const resourcesWithConnections: GeneratedResources = {
...resources,
connections: [
{
name: "my_kafka",
content: "TYPE kafka\nKAFKA_BROKERS kafka:9092\nKAFKA_TOPIC events\n",
},
],
};

let capturedFormData: FormData | null = null;

server.use(
http.post(`${BASE_URL}/v1/build`, async ({ request }) => {
capturedFormData = await request.formData();
return HttpResponse.json(createBuildSuccessResponse());
})
);

const result = await buildToTinybird(config, resourcesWithConnections);

expect(result.success).toBe(true);
expect(result.connectionCount).toBe(1);
expect(capturedFormData).not.toBeNull();
// 2 datasources + 1 pipe + 1 connection
const allValues = capturedFormData!.getAll("data_project://");
expect(allValues.length).toBe(4);
});
});

describe("validateBuildConfig", () => {
Expand Down
42 changes: 42 additions & 0 deletions src/api/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,5 +374,47 @@ describe("Deploy API", () => {
expect(result.success).toBe(false);
expect(result.error).toContain("Deployment timed out");
});

it("includes connections in deploy form data", async () => {
const resourcesWithConnections: GeneratedResources = {
...resources,
connections: [
{
name: "my_kafka",
content: "TYPE kafka\nKAFKA_BROKERS kafka:9092\nKAFKA_TOPIC events\n",
},
],
};

let capturedFormData: FormData | null = null;

server.use(
http.post(`${BASE_URL}/v1/deploy`, async ({ request }) => {
capturedFormData = await request.formData();
return HttpResponse.json(
createDeploySuccessResponse({ deploymentId: "deploy-conn", status: "pending" })
);
}),
http.get(`${BASE_URL}/v1/deployments/deploy-conn`, () => {
return HttpResponse.json(
createDeploymentStatusResponse({ deploymentId: "deploy-conn", status: "data_ready" })
);
}),
http.post(`${BASE_URL}/v1/deployments/deploy-conn/set-live`, () => {
return HttpResponse.json(createSetLiveSuccessResponse());
})
);

const result = await deployToMain(config, resourcesWithConnections, {
pollIntervalMs: 1,
});

expect(result.success).toBe(true);
expect(result.connectionCount).toBe(1);
expect(capturedFormData).not.toBeNull();
// 1 datasource + 1 pipe + 1 connection
const allValues = capturedFormData!.getAll("data_project://");
expect(allValues.length).toBe(3);
});
});
});
15 changes: 15 additions & 0 deletions src/api/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,21 @@ export async function deployToMain(
);
}

// Add connections
for (const conn of resources.connections ?? []) {
const fieldName = `data_project://`;
const fileName = `${conn.name}.connection`;
if (debug) {
console.log(`[debug] Adding connection: ${fieldName} (filename: ${fileName})`);
console.log(`[debug] Content:\n${conn.content}\n`);
}
formData.append(
fieldName,
new Blob([conn.content], { type: "text/plain" }),
fileName
);
}

// Step 0: Clean up any stale non-live deployments that might block the new deployment
try {
const deploymentsUrl = `${baseUrl}/v1/deployments`;
Expand Down