Skip to content

Commit c68469e

Browse files
committed
blueprint build with context added to examples
1 parent bceb953 commit c68469e

3 files changed

Lines changed: 166 additions & 0 deletions

File tree

EXAMPLES.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,40 @@ Runnable examples live in [`examples/`](./examples).
77

88
## Table of Contents
99

10+
- [Blueprint with Build Context](#blueprint-with-build-context)
1011
- [Devbox From Blueprint (Run Command, Shutdown)](#devbox-from-blueprint-lifecycle)
1112
- [MCP Hub + Claude Code + GitHub](#mcp-github-tools)
1213

14+
<a id="blueprint-with-build-context"></a>
15+
## Blueprint with Build Context
16+
17+
**Use case:** Create a blueprint using the object store to provide docker build context files, then verify files are copied into the image.
18+
19+
**Tags:** `blueprint`, `object-store`, `build-context`, `devbox`, `cleanup`
20+
21+
### Workflow
22+
- Create a temporary directory with sample application files
23+
- Upload the directory to object storage as build context
24+
- Create a blueprint with a Dockerfile that copies the context files
25+
- Create a devbox from the blueprint
26+
- Verify the files were copied into the image
27+
- Shutdown devbox and delete blueprint and storage object
28+
29+
### Prerequisites
30+
- `RUNLOOP_API_KEY`
31+
32+
### Run
33+
```sh
34+
uv run python -m examples.blueprint_with_build_context
35+
```
36+
37+
### Test
38+
```sh
39+
uv run pytest -m smoketest tests/smoketests/examples/
40+
```
41+
42+
**Source:** [`examples/blueprint_with_build_context.py`](./examples/blueprint_with_build_context.py)
43+
1344
<a id="devbox-from-blueprint-lifecycle"></a>
1445
## Devbox From Blueprint (Run Command, Shutdown)
1546

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env -S uv run python
2+
"""
3+
---
4+
title: Blueprint with Build Context
5+
slug: blueprint-with-build-context
6+
use_case: Create a blueprint using the object store to provide docker build context files, then verify files are copied into the image.
7+
workflow:
8+
- Create a temporary directory with sample application files
9+
- Upload the directory to object storage as build context
10+
- Create a blueprint with a Dockerfile that copies the context files
11+
- Create a devbox from the blueprint
12+
- Verify the files were copied into the image
13+
- Shutdown devbox and delete blueprint and storage object
14+
tags:
15+
- blueprint
16+
- object-store
17+
- build-context
18+
- devbox
19+
- cleanup
20+
prerequisites:
21+
- RUNLOOP_API_KEY
22+
run: uv run python -m examples.blueprint_with_build_context
23+
test: uv run pytest -m smoketest tests/smoketests/examples/
24+
---
25+
"""
26+
27+
from __future__ import annotations
28+
29+
import tempfile
30+
from pathlib import Path
31+
from datetime import timedelta
32+
33+
from runloop_api_client import RunloopSDK
34+
from runloop_api_client.lib.polling import PollingConfig
35+
36+
from ._harness import run_as_cli, unique_name, wrap_recipe
37+
from .example_types import ExampleCheck, RecipeOutput, RecipeContext
38+
39+
# building can take time: make sure to set a long blueprint build timeout
40+
BLUEPRINT_POLL_TIMEOUT_S = 10 * 60
41+
BLUEPRINT_POLL_MAX_ATTEMPTS = 600
42+
ONE_WEEK = timedelta(weeks=1)
43+
44+
45+
def recipe(ctx: RecipeContext) -> RecipeOutput:
46+
"""Create a blueprint with build context from object storage, then verify files in a devbox."""
47+
cleanup = ctx.cleanup
48+
49+
sdk = RunloopSDK()
50+
51+
# setup: create a temporary directory with sample application files to use as build context
52+
with tempfile.TemporaryDirectory() as tmp_dir:
53+
tmp_path = Path(tmp_dir)
54+
(tmp_path / "app.py").write_text('print("Hello from app")')
55+
(tmp_path / "config.txt").write_text("key=value")
56+
57+
# upload the build context to object storage
58+
storage_obj = sdk.storage_object.upload_from_dir(
59+
tmp_path,
60+
name=unique_name("example-build-context"),
61+
ttl=ONE_WEEK,
62+
)
63+
cleanup.add(f"storage_object:{storage_obj.id}", storage_obj.delete)
64+
65+
# create a blueprint with the build context
66+
blueprint = sdk.blueprint.create(
67+
name=unique_name("example-blueprint-context"),
68+
dockerfile="FROM ubuntu:22.04\nWORKDIR /app\nCOPY . .",
69+
build_context=storage_obj.as_build_context(),
70+
polling_config=PollingConfig(
71+
timeout_seconds=BLUEPRINT_POLL_TIMEOUT_S,
72+
max_attempts=BLUEPRINT_POLL_MAX_ATTEMPTS,
73+
),
74+
)
75+
cleanup.add(f"blueprint:{blueprint.id}", blueprint.delete)
76+
77+
devbox = blueprint.create_devbox(
78+
name=unique_name("example-devbox"),
79+
launch_parameters={
80+
"resource_size_request": "X_SMALL",
81+
"keep_alive_time_seconds": 60 * 5,
82+
},
83+
)
84+
cleanup.add(f"devbox:{devbox.id}", devbox.shutdown)
85+
86+
app_result = devbox.cmd.exec("cat /app/app.py")
87+
app_stdout = app_result.stdout()
88+
89+
config_result = devbox.cmd.exec("cat /app/config.txt")
90+
config_stdout = config_result.stdout()
91+
92+
return RecipeOutput(
93+
resources_created=[
94+
f"storage_object:{storage_obj.id}",
95+
f"blueprint:{blueprint.id}",
96+
f"devbox:{devbox.id}",
97+
],
98+
checks=[
99+
ExampleCheck(
100+
name="app.py exists and readable",
101+
passed=app_result.exit_code == 0,
102+
details=f"exitCode={app_result.exit_code}",
103+
),
104+
ExampleCheck(
105+
name="app.py contains expected content",
106+
passed='print("Hello from app")' in app_stdout,
107+
details=app_stdout.strip(),
108+
),
109+
ExampleCheck(
110+
name="config.txt exists and readable",
111+
passed=config_result.exit_code == 0,
112+
details=f"exitCode={config_result.exit_code}",
113+
),
114+
ExampleCheck(
115+
name="config.txt contains expected content",
116+
passed="key=value" in config_stdout,
117+
details=config_stdout.strip(),
118+
),
119+
],
120+
)
121+
122+
123+
run_blueprint_with_build_context_example = wrap_recipe(recipe)
124+
125+
126+
if __name__ == "__main__":
127+
run_as_cli(run_blueprint_with_build_context_example)

examples/registry.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,19 @@
99

1010
from .example_types import ExampleResult
1111
from .mcp_github_tools import run_mcp_github_tools_example
12+
from .blueprint_with_build_context import run_blueprint_with_build_context_example
1213
from .devbox_from_blueprint_lifecycle import run_devbox_from_blueprint_lifecycle_example
1314

1415
ExampleRegistryEntry = dict[str, Any]
1516

1617
example_registry: list[ExampleRegistryEntry] = [
18+
{
19+
"slug": "blueprint-with-build-context",
20+
"title": "Blueprint with Build Context",
21+
"file_name": "blueprint_with_build_context.py",
22+
"required_env": ["RUNLOOP_API_KEY"],
23+
"run": run_blueprint_with_build_context_example,
24+
},
1725
{
1826
"slug": "devbox-from-blueprint-lifecycle",
1927
"title": "Devbox From Blueprint (Run Command, Shutdown)",

0 commit comments

Comments
 (0)