diff --git a/src/deno_sandbox/revisions.py b/src/deno_sandbox/revisions.py index 00b89f4..bdf60a7 100644 --- a/src/deno_sandbox/revisions.py +++ b/src/deno_sandbox/revisions.py @@ -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. @@ -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). @@ -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)) @@ -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. @@ -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). @@ -289,5 +305,7 @@ def deploy( layers=layers, env_vars=env_vars, labels=labels, + production=production, + preview=preview, ) ) diff --git a/tests/test_revisions.py b/tests/test_revisions.py index 4cf5ba2..9d5e6aa 100644 --- a/tests/test_revisions.py +++ b/tests/test_revisions.py @@ -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"])