Skip to content
Draft
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
14 changes: 10 additions & 4 deletions projects/fal/src/fal/api/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _resolve_deployment_reference(
*,
app_name: str | None = None,
auth: AuthModeLiteral | None = None,
strategy: DeploymentStrategyLiteral = "rolling",
strategy: DeploymentStrategyLiteral | None = None,
reset_scale: bool = False,
) -> tuple[tuple[str | None, str | None], AppData]:
from fal.cli._utils import AppData, get_app_data_from_toml, is_app_name
Expand All @@ -127,7 +127,7 @@ def _resolve_deployment_reference(

app_data = AppData(
auth=auth,
deployment_strategy=cast(DeploymentStrategyLiteral, strategy),
deployment_strategy=strategy,
reset_scale=cast(bool, reset_scale),
name=app_name,
)
Expand All @@ -141,6 +141,12 @@ def _resolve_deployment_reference(
assert resolved_app_name is not None

app_data = get_app_data_from_toml(resolved_app_name)

# re-apply the config user explicitly set so they take precedence over
# the TOML values.
if strategy is not None:
app_data = replace(app_data, deployment_strategy=strategy)

if app_data.python_entry_point is not None or app_data.ref is None:
# python_entry_point is resolved by the loader; ref is None for
# image-only apps.
Expand Down Expand Up @@ -326,7 +332,7 @@ def prepare_deployment(
*,
app_name: str | None = None,
auth: AuthModeLiteral | None = None,
strategy: DeploymentStrategyLiteral = "rolling",
strategy: DeploymentStrategyLiteral | None = None,
reset_scale: bool = False,
force_env_build: bool = False,
environment_name: str | None = None,
Expand Down Expand Up @@ -372,7 +378,7 @@ def deploy(
*,
app_name: str | None = None,
auth: AuthModeLiteral | None = None,
strategy: DeploymentStrategyLiteral = "rolling",
strategy: DeploymentStrategyLiteral | None = None,
reset_scale: bool = False,
force_env_build: bool = False,
environment_name: str | None = None,
Expand Down
5 changes: 3 additions & 2 deletions projects/fal/src/fal/cli/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,9 @@ def valid_auth_option(option):
parser.add_argument(
"--strategy",
choices=["recreate", "rolling"],
help="Deployment strategy.",
default="rolling",
help="Deployment strategy. Defaults to the value in pyproject.toml, "
"or 'rolling' if unset.",
default=None,
)
parser.add_argument(
"--no-scale",
Expand Down
40 changes: 40 additions & 0 deletions projects/fal/tests/unit/cli/test_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,46 @@ def test_deploy_with_toml_deployment_strategy(
)


@patch("fal.cli._utils.find_pyproject_toml", return_value="pyproject.toml")
@patch("fal.cli._utils.parse_pyproject_toml")
@patch("fal.api.deploy.execute_prepared_deployment")
@patch("fal.api.deploy._prepare_deployment_from_reference")
def test_deploy_cli_strategy_overrides_toml_for_app_name(
mock_prepare_ref,
mock_execute,
mock_parse_toml,
mock_find_toml,
mock_parse_pyproject_toml,
):
# Regression test: an explicit --strategy on the CLI must take precedence
# over the deployment_strategy set in pyproject.toml when deploying by app
# name. Previously the TOML value silently won and --strategy was dropped.
mock_parse_toml.return_value = mock_parse_pyproject_toml

# my-app has deployment_strategy="rolling" in the TOML fixture.
args = mock_args(app_ref=("my-app", None), strategy="recreate")

_deploy(args)

project_root, _ = find_project_root(None)

mock_prepare_ref.assert_called_once_with(
mock_prepare_ref.call_args[0][0],
(f"{project_root / 'src/my_app/inference.py'}", "MyApp"),
AppData(
ref=f"{project_root / 'src/my_app/inference.py'}::MyApp",
auth="shared",
deployment_strategy="recreate",
reset_scale=False,
team=None,
name="my-app",
local_project_root=".",
),
force_env_build=False,
environment_name=None,
)


@patch("fal.cli._utils.find_pyproject_toml", return_value="pyproject.toml")
@patch("fal.cli._utils.parse_pyproject_toml")
@patch("fal.api.deploy.execute_prepared_deployment")
Expand Down
Loading