@@ -92,6 +92,12 @@ class DeploymentResult:
9292 auth_mode : str
9393
9494
95+ @dataclass
96+ class BuildResult :
97+ revision : str
98+ app_name : str | None
99+
100+
95101@dataclass
96102class PreparedDeployment :
97103 host : FalServerlessHost
@@ -412,6 +418,110 @@ def _execute_loaded_deployment(
412418 )
413419
414420
421+ def _execute_loaded_build (
422+ * ,
423+ host : FalServerlessHost ,
424+ loaded : LoadedFunction ,
425+ app_data : AppData ,
426+ environment_name : str | None = None ,
427+ result_handler : ResultHandler | None = None ,
428+ build_result_handler : ResultHandler | None = None ,
429+ prepare_options_handler : ProgressCallback | None = None ,
430+ ) -> BuildResult :
431+ from fal .api import FalServerlessError
432+
433+ build_result_handler = (
434+ result_handler if build_result_handler is None else build_result_handler
435+ )
436+
437+ isolated_function = replace (
438+ loaded .function ,
439+ options = host .prepare_options (
440+ loaded .function .options ,
441+ func = loaded .function .func ,
442+ on_progress = prepare_options_handler ,
443+ ),
444+ )
445+
446+ host .build_environment (
447+ isolated_function .options ,
448+ application_name = loaded .app_name ,
449+ environment_name = environment_name ,
450+ result_handler = build_result_handler ,
451+ )
452+
453+ isolated_function .fetch_metadata (build_environment = False )
454+
455+ metadata = dict (isolated_function .build_metadata ())
456+ if app_data .message is not None :
457+ metadata ["message" ] = app_data .message
458+ if app_data .annotations :
459+ metadata ["annotations" ] = dict (app_data .annotations )
460+
461+ # Registering without an application_name stores the revision and leaves
462+ # every alias pointing where it already pointed.
463+ result = host .register (
464+ func = isolated_function .func ,
465+ options = isolated_function .options ,
466+ application_name = None ,
467+ source_code = loaded .source_code ,
468+ metadata = metadata ,
469+ deployment_strategy = app_data .deployment_strategy or "rolling" ,
470+ scale = app_data .reset_scale ,
471+ environment_name = environment_name ,
472+ result_handler = result_handler ,
473+ entrypoint = isolated_function .run_entrypoint ,
474+ build_environment = False ,
475+ )
476+
477+ if not result or not result .result :
478+ raise FalServerlessError (
479+ "Build failed: The server did not confirm the revision. "
480+ "This may indicate a network issue or server error. "
481+ "Please try again."
482+ )
483+
484+ return BuildResult (
485+ revision = result .result .application_id ,
486+ app_name = loaded .app_name ,
487+ )
488+
489+
490+ def build (
491+ client : SyncServerlessClient ,
492+ app_ref : str | tuple [str | None , str | None ] | None = None ,
493+ * ,
494+ app_name : str | None = None ,
495+ force_env_build : bool = False ,
496+ environment_name : str | None = None ,
497+ message : str | None = None ,
498+ annotations : dict [str , str ] | None = None ,
499+ result_handler : ResultHandler | None = None ,
500+ build_result_handler : ResultHandler | None = None ,
501+ ) -> BuildResult :
502+ resolved_app_ref , app_data = _resolve_deployment_reference (
503+ app_ref ,
504+ app_name = app_name ,
505+ message = message ,
506+ annotations = annotations ,
507+ )
508+ prepared = _prepare_deployment_from_reference (
509+ client ,
510+ resolved_app_ref ,
511+ app_data ,
512+ force_env_build = force_env_build ,
513+ environment_name = environment_name ,
514+ )
515+ return _execute_loaded_build (
516+ host = prepared .host ,
517+ loaded = prepared .loaded ,
518+ app_data = prepared .app_data ,
519+ environment_name = prepared .environment_name ,
520+ result_handler = result_handler ,
521+ build_result_handler = build_result_handler ,
522+ )
523+
524+
415525def prepare_deployment (
416526 client : SyncServerlessClient ,
417527 app_ref : str | tuple [str | None , str | None ] | None = None ,
0 commit comments