Skip to content

Commit 61a26ac

Browse files
committed
chore(blueprints): Add convenience build_context API that takes a StorageObject directly.
1 parent 9edd07f commit 61a26ac

3 files changed

Lines changed: 65 additions & 6 deletions

File tree

src/sdk.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export * from './sdk/index';
22
import type * as Core from './core';
33
import { Runloop, type ClientOptions } from './index';
44
import { Devbox } from './sdk/devbox';
5-
import { Blueprint } from './sdk/blueprint';
5+
import { Blueprint, type CreateParams as BlueprintCreateParams } from './sdk/blueprint';
66
import { Snapshot } from './sdk/snapshot';
77
import { StorageObject } from './sdk/storage-object';
88

@@ -13,7 +13,7 @@ import type {
1313
DevboxView,
1414
DevboxListDiskSnapshotsParams,
1515
} from './resources/devboxes/devboxes';
16-
import type { BlueprintCreateParams, BlueprintListParams } from './resources/blueprints';
16+
import type { BlueprintListParams } from './resources/blueprints';
1717
import type { ObjectCreateParams, ObjectListParams } from './resources/objects';
1818
import { PollingOptions } from './lib/polling';
1919

@@ -283,6 +283,26 @@ export class DevboxOps {
283283
* });
284284
* const devbox = await sdk.devbox.createFromBlueprintId(blueprint.id, { name: 'my-devbox' });
285285
* ```
286+
*
287+
* To use a local directory as a build context, use an object.
288+
*
289+
* @example
290+
* ```typescript
291+
* const sdk = new RunloopSDK();
292+
* const obj = await sdk.storageObject.uploadFromDir(
293+
* './',
294+
* {
295+
* name: 'build-context',
296+
* ttl_ms: 3600000, // 1 hour
297+
* }
298+
* );
299+
* const blueprint = await sdk.blueprint.create({
300+
* name: 'my-blueprint-with-context',
301+
* dockerfile: `FROM ubuntu:22.04
302+
* COPY . .`,
303+
* build_context: obj,
304+
* });
305+
* ```
286306
*/
287307
export class BlueprintOps {
288308
/**

src/sdk/blueprint.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,18 @@ import type {
88
import type { DevboxCreateParams, DevboxView } from '../resources/devboxes/devboxes';
99
import type { PollingOptions } from '../lib/polling';
1010
import { Devbox } from './devbox';
11+
import { StorageObject } from './storage-object';
12+
13+
export type CreateParams = Omit<BlueprintCreateParams, 'build_context'> & {
14+
/**
15+
* A build context to attach to the Blueprint build.
16+
* Enables the use of `COPY` Dockerfile directives.
17+
*/
18+
build_context?: StorageObject | BlueprintCreateParams.BuildContext | null;
19+
};
1120

1221
/**
1322
* Object-oriented interface for working with Blueprints.
14-
* ```
1523
*/
1624
export class Blueprint {
1725
private client: Runloop;
@@ -30,18 +38,25 @@ export class Blueprint {
3038
* @private
3139
*
3240
* @param {Runloop} client - The Runloop client instance
33-
* @param {BlueprintCreateParams} params - Parameters for creating the blueprint
41+
* @param {CreateParams} params - Parameters for creating the blueprint
3442
* @param {Core.RequestOptions & { polling?: Partial<PollingOptions<BlueprintView>> }} [options] - Request options with optional polling configuration
3543
* @returns {Promise<Blueprint>} A {@link Blueprint} instance with completed build
3644
*/
3745
static async create(
3846
client: Runloop,
39-
params: BlueprintCreateParams,
47+
params: CreateParams,
4048
options?: Core.RequestOptions & {
4149
polling?: Partial<PollingOptions<BlueprintView>>;
4250
},
4351
): Promise<Blueprint> {
44-
const blueprintData = await client.blueprints.createAndAwaitBuildCompleted(params, options);
52+
let rawParams = { ...params };
53+
if (params.build_context instanceof StorageObject) {
54+
rawParams.build_context = { type: 'object', object_id: params.build_context.id };
55+
}
56+
const blueprintData = await client.blueprints.createAndAwaitBuildCompleted(
57+
rawParams as BlueprintCreateParams,
58+
options,
59+
);
4560
return new Blueprint(client, blueprintData.id);
4661
}
4762

tests/objects/blueprint.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Blueprint } from '../../src/sdk/blueprint';
22
import { Devbox } from '../../src/sdk/devbox';
33
import type { BlueprintView, BlueprintBuildLogsListView } from '../../src/resources/blueprints';
4+
import { StorageObject } from '@runloop/api-client/sdk';
45

56
// Mock the Runloop client
67
jest.mock('../../src/index');
@@ -125,6 +126,29 @@ describe('Blueprint (New API)', () => {
125126
undefined,
126127
);
127128
});
129+
130+
it('should support convenience object build_context blueprint configuration', async () => {
131+
mockClient.blueprints.createAndAwaitBuildCompleted.mockResolvedValue(mockBlueprintData);
132+
133+
const obj = StorageObject.fromId(mockClient, 'obj_foo');
134+
135+
await Blueprint.create(mockClient, {
136+
name: 'build-context-object-blueprint',
137+
dockerfile: 'FROM ubuntu:22.04',
138+
build_context: obj,
139+
metadata: { version: '1.0' },
140+
});
141+
142+
expect(mockClient.blueprints.createAndAwaitBuildCompleted).toHaveBeenCalledWith(
143+
{
144+
name: 'build-context-object-blueprint',
145+
dockerfile: 'FROM ubuntu:22.04',
146+
build_context: { type: 'object', object_id: 'obj_foo' },
147+
metadata: { version: '1.0' },
148+
},
149+
undefined,
150+
);
151+
});
128152
});
129153

130154
describe('fromId', () => {

0 commit comments

Comments
 (0)