3232import re
3333import shlex
3434import time
35- import re
3635from contextlib import contextmanager
36+ from pathlib import Path
3737from typing import Any
3838
3939from app .core .config import get_settings
6969 Sandbox ,
7070 SandboxError ,
7171)
72+ from app .services .uploads import get_upload_record
7273
7374log = logging .getLogger (__name__ )
7475
@@ -308,6 +309,11 @@ def _clone_into_sync(sb: Sandbox, github_url: str) -> None:
308309 raise
309310
310311
312+ def _extract_upload_into_repo_sync (sb : Sandbox , archive_path : Path ) -> None :
313+ """Seed REPO_DIR from an uploaded tarball."""
314+ sb .extract_upload_archive (archive_path )
315+
316+
311317def _repo_has (sb : Sandbox , relative_path : str ) -> bool :
312318 res = sb .exec (
313319 f"test -f { shlex .quote (relative_path )} " ,
@@ -444,21 +450,21 @@ async def run_deployment(deployment_id: str) -> None:
444450 f"Starting deployment: source={ github_url or upload_id } model={ model } " ,
445451 )
446452
447- if not github_url :
453+ if not github_url and not upload_id :
448454 await _update_deployment (
449455 deployment_id ,
450456 status = DEPLOYMENT_STATUS_FAILED ,
451- error = (
452- "Upload-based deployments not yet supported. "
453- "Provide `github_url` instead."
454- ),
457+ error = "Deployment source missing (expected github_url or upload_id)." ,
455458 )
456459 await _append_log (
457460 deployment_id ,
458- "ERROR: upload-based deployments not yet supported. Use github_url." ,
461+ "ERROR: deployment source missing." ,
462+ )
463+ dlog .warning (
464+ "deployment source missing (github_url=%s upload_id=%s)" ,
465+ github_url ,
466+ upload_id ,
459467 )
460- dlog .warning ("upload-based deployments not supported (upload_id=%s); failing fast" ,
461- upload_id )
462468 return
463469
464470 sb : Sandbox | None = None
@@ -479,10 +485,25 @@ async def run_deployment(deployment_id: str) -> None:
479485 dlog .info ("sandbox acquired: id=%s" , sb .object_id )
480486 await _append_log (deployment_id , f"Sandbox ready: { sb .object_id } " )
481487
482- await _append_log (deployment_id , f"Cloning { github_url } ..." )
483- with _step (dlog , "clone repo" ):
484- await asyncio .to_thread (_clone_into_sync , sb , github_url )
485- await _append_log (deployment_id , "Repo cloned." )
488+ source_description = ""
489+ if github_url :
490+ await _append_log (deployment_id , f"Cloning { github_url } ..." )
491+ with _step (dlog , "clone repo" ):
492+ await asyncio .to_thread (_clone_into_sync , sb , github_url )
493+ await _append_log (deployment_id , "Repo cloned." )
494+ source_description = f"GitHub repo: { github_url } "
495+ else :
496+ record = get_upload_record (upload_id or "" )
497+ if record is None :
498+ raise RuntimeError (f"Upload { upload_id } is missing from upload storage" )
499+ await _append_log (
500+ deployment_id ,
501+ f"Preparing uploaded source { record .upload_id } ({ record .original_filename } )..." ,
502+ )
503+ with _step (dlog , "extract uploaded archive" , upload_id = record .upload_id ):
504+ await asyncio .to_thread (_extract_upload_into_repo_sync , sb , record .archive_path )
505+ await _append_log (deployment_id , "Uploaded project extracted." )
506+ source_description = f"Uploaded archive: { record .upload_id } "
486507
487508 # ------------------------------------------------------------------
488509 # 2. Agent #1 — analyze (with heuristic fast-path)
@@ -528,7 +549,7 @@ async def run_deployment(deployment_id: str) -> None:
528549 f"Heuristic uncertain; running Agent #1 (analyze) with { model } ..." ,
529550 )
530551 analyze_user = render_analyze_user (
531- source_description = f"GitHub repo: { github_url } " ,
552+ source_description = source_description ,
532553 name = name ,
533554 user_env_keys = env_keys ,
534555 )
0 commit comments