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
18 changes: 18 additions & 0 deletions src/deno_sandbox/revisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ async def deploy(
layers: Optional[List[str]] = None,
env_vars: Optional[List[EnvVarInputForDeploy]] = None,
labels: Optional[Dict[str, str]] = None,
production: Optional[bool] = None,
preview: Optional[bool] = None,
) -> Revision:
"""Deploy a revision by uploading source files as assets.

Expand All @@ -192,6 +194,10 @@ async def deploy(
layers: Layer IDs or slugs to reference for this revision.
env_vars: Optional environment variables for this revision.
labels: Optional labels (e.g., git metadata).
production: Whether to deploy to the production timeline.
Defaults to true on the server.
preview: Whether to deploy as a preview deployment.
Defaults to false on the server.

Returns:
The created Revision (build is async; poll for status).
Expand All @@ -205,6 +211,10 @@ async def deploy(
body["env_vars"] = env_vars
if labels is not None:
body["labels"] = labels
if production is not None:
body["production"] = production
if preview is not None:
body["preview"] = preview
result = await self._client.post(f"/api/v2/apps/{app}/deploy", body)
return cast(Revision, convert_to_snake_case(result))

Expand Down Expand Up @@ -267,6 +277,8 @@ def deploy(
layers: Optional[List[str]] = None,
env_vars: Optional[List[EnvVarInputForDeploy]] = None,
labels: Optional[Dict[str, str]] = None,
production: Optional[bool] = None,
preview: Optional[bool] = None,
) -> Revision:
"""Deploy a revision by uploading source files as assets.

Expand All @@ -277,6 +289,10 @@ def deploy(
layers: Layer IDs or slugs to reference for this revision.
env_vars: Optional environment variables for this revision.
labels: Optional labels (e.g., git metadata).
production: Whether to deploy to the production timeline.
Defaults to true on the server.
preview: Whether to deploy as a preview deployment.
Defaults to false on the server.

Returns:
The created Revision (build is async; poll for status).
Expand All @@ -289,5 +305,7 @@ def deploy(
layers=layers,
env_vars=env_vars,
labels=labels,
production=production,
preview=preview,
)
)
48 changes: 48 additions & 0 deletions tests/test_revisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,51 @@ def test_revisions_deploy_sync():
assert revision["status"] == "succeeded", revision.get("failure_reason")
finally:
sdk.apps.delete(app["id"])


@pytest.mark.timeout(120)
@pytest.mark.asyncio(loop_scope="session")
async def test_revisions_deploy_preview_only_async():
"""Deploy with production=False, preview=True and verify timeline assignment."""
sdk = AsyncDenoDeploy()
app = await sdk.apps.create()
try:
revision = await sdk.revisions.deploy(
app["id"],
assets={
"main.ts": {
"kind": "file",
"encoding": "utf-8",
"content": 'Deno.serve(() => new Response("Hello"))',
}
},
production=False,
preview=True,
)
assert revision["id"] is not None
while revision["status"] in ("queued", "building"):
await asyncio.sleep(1)
revision = await sdk.revisions.get(revision["id"])
assert revision is not None
assert revision["status"] == "succeeded", revision.get("failure_reason")

# Verify timeline assignment via the revision timelines API
timelines = await sdk.revisions._client.get(
f"/api/v2/revisions/{revision['id']}/timelines"
)
production = [
t
for t in timelines
if t["slug"] == "production"
and not t.get("partition", {}).get("deno.revision.id")
]
preview = [
t
for t in timelines
if t["slug"] == "preview"
and t.get("partition", {}).get("deno.revision.id") == revision["id"]
]
assert len(production) == 0, "should not be on production timeline"
assert len(preview) > 0, "should be on preview timeline"
finally:
await sdk.apps.delete(app["id"])