Skip to content

Commit cefb341

Browse files
committed
Revert "Revert "truss push: Make published deployments the default (#2178)"…"
This reverts commit 550e85e.
1 parent 03da245 commit cefb341

File tree

10 files changed

+589
-54
lines changed

10 files changed

+589
-54
lines changed

smoketests/test_chains.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def test_itest_chain_publish(prepare) -> None:
181181
tmpdir, truss_rc_path, remote = prepare
182182

183183
chain_src = CHAINS_ROOT / "tests" / "itest_chain" / "itest_chain.py"
184-
command = f"truss chains push {chain_src} --publish --name=itest_publish --no-wait"
184+
command = f"truss chains push {chain_src} --name=itest_publish --no-wait"
185185

186186
stdout, stderr = run_command(truss_rc_path, command)
187187
if stderr:

truss-chains/tests/test_chain_upload_end_to_end.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ def test_push_chain_with_all_parameters_including_disable_chain_download(
146146
"--name",
147147
"custom_chain_name",
148148
"--disable-chain-download",
149-
"--publish",
150149
"--no-promote",
151150
"--environment",
152151
"test_env",

truss-chains/truss_chains/deployment/deployment_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def push(
230230
if has_engine_builder_chainlets and not options.publish:
231231
raise public_types.ChainsDeploymentError(
232232
"This chain contains engine builder chainlets. Development models are "
233-
"not supportd, push with `--publish`."
233+
"not supportd, push as a published deployment."
234234
)
235235
return _create_baseten_chain(
236236
options,
@@ -614,7 +614,7 @@ def __init__(
614614
dev_version = b10_core.get_dev_version(self._remote_provider.api, model_name)
615615
if not dev_version:
616616
raise b10_errors.RemoteError(
617-
"No development model found. Run `truss push` then try again."
617+
"No development model found. Run `truss push --watch` then try again."
618618
)
619619

620620
def _patch(self) -> None:

truss/cli/chains_commands.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ def _create_chains_table(service) -> Tuple[rich.table.Table, List[str]]:
152152
)
153153
@click.option(
154154
"--publish/--no-publish",
155-
default=False,
156-
help="Create chainlets as published deployments.",
155+
default=None, # Use None to detect if explicitly passed
156+
help="[DEPRECATED] Published deployments are now the default. Use --watch for development deployments.",
157157
)
158158
@click.option(
159159
"--promote/--no-promote",
@@ -166,7 +166,7 @@ def _create_chains_table(service) -> Tuple[rich.table.Table, List[str]]:
166166
required=False,
167167
help=(
168168
"Deploy the chain as a published deployment to the specified environment."
169-
"If specified, --publish is implied and the supplied value of --promote will be ignored."
169+
"If specified, publish is implied and the supplied value of --promote will be ignored."
170170
),
171171
)
172172
@click.option(
@@ -180,8 +180,7 @@ def _create_chains_table(service) -> Tuple[rich.table.Table, List[str]]:
180180
help=(
181181
"Watches the chains source code and applies live patches. Using this option "
182182
"will wait for the chain to be deployed (i.e. `--wait` flag is applied), "
183-
"before starting to watch for changes. This option required the deployment "
184-
"to be a development deployment (i.e. `--no-promote` and `--no-publish`."
183+
"before starting to watch for changes."
185184
),
186185
)
187186
@click.option(
@@ -227,8 +226,7 @@ def _create_chains_table(service) -> Tuple[rich.table.Table, List[str]]:
227226
type=str,
228227
required=False,
229228
help=(
230-
"Name of the deployment created by the publish. Can only be used "
231-
"in combination with '--publish' or '--promote'."
229+
"Name of the deployment created by the publish. Can be used with '--promote' as well."
232230
),
233231
)
234232
@click.option(
@@ -245,7 +243,7 @@ def push_chain(
245243
source: Path,
246244
entrypoint: Optional[str],
247245
name: Optional[str],
248-
publish: bool,
246+
publish: Optional[bool],
249247
promote: bool,
250248
wait: bool,
251249
watch: bool,
@@ -279,11 +277,37 @@ def push_chain(
279277
raise ValueError(
280278
"When using `--watch`, the deployment cannot be published or promoted."
281279
)
280+
if environment:
281+
raise ValueError(
282+
"Cannot use --watch with --environment. Watch mode requires a development deployment."
283+
)
284+
# --watch implies development deployment
285+
publish = False
282286
if not wait:
283287
console.print(
284288
"'--watch' is used. Will wait for deployment before watching files."
285289
)
286290
wait = True
291+
else:
292+
if publish is True:
293+
console.print(
294+
"[DEPRECATED] The --publish flag is deprecated. Published deployments are now the default.",
295+
style="yellow",
296+
)
297+
elif publish is False:
298+
console.print(
299+
"[DEPRECATED] The --no-publish flag is deprecated. Use --watch for development deployments.",
300+
style="yellow",
301+
)
302+
# Keep publish=False for backwards compatibility
303+
304+
# Default to published
305+
if publish is None:
306+
publish = True
307+
console.print(
308+
"Deploying as a published deployment. Use --watch for a development deployment.",
309+
style="green",
310+
)
287311

288312
if promote and environment:
289313
promote_warning = (

truss/cli/cli.py

Lines changed: 118 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Optional, cast
88

99
import rich_click as click
10+
from rich import console as rich_console
1011
from rich import progress
1112

1213
import truss
@@ -35,7 +36,7 @@
3536
get_dev_version_from_versions,
3637
)
3738
from truss.remote.baseten.remote import BasetenRemote
38-
from truss.remote.baseten.service import BasetenService
39+
from truss.remote.baseten.service import BasetenService, URLConfig
3940
from truss.remote.remote_factory import USER_TRUSSRC_PATH, RemoteFactory
4041
from truss.trt_llm.config_checks import (
4142
has_no_tags_trt_llm_builder,
@@ -89,6 +90,32 @@ def _get_truss_from_directory(
8990
return load(truss_dir, config_path=config_path)
9091

9192

93+
def _start_watch_mode(
94+
target_directory: str,
95+
model_name: str,
96+
remote_provider: BasetenRemote,
97+
resolved_model: dict,
98+
resolved_versions: list,
99+
console: "rich_console.Console",
100+
error_console: "rich_console.Console",
101+
) -> None:
102+
if not os.path.isfile(target_directory):
103+
remote_provider.sync_truss_to_dev_version_with_model(
104+
resolved_model, resolved_versions, target_directory, console, error_console
105+
)
106+
else:
107+
# These imports are delayed, to handle pydantic v1 envs gracefully.
108+
from truss_chains.deployment import deployment_client
109+
110+
deployment_client.watch_model(
111+
source=Path(target_directory),
112+
model_name=model_name,
113+
remote_provider=remote_provider,
114+
console=console,
115+
error_console=error_console,
116+
)
117+
118+
92119
### Top-level & utility commands. ######################################################
93120

94121

@@ -430,6 +457,7 @@ def run_python(script, target_directory):
430457
required=False,
431458
default=False,
432459
help=(
460+
"[DEPRECATED] Published deployments are now the default."
433461
"Push the truss as a published deployment. If no production "
434462
"deployment exists, promote the truss to production "
435463
"after deploy completes."
@@ -452,7 +480,7 @@ def run_python(script, target_directory):
452480
required=False,
453481
help=(
454482
"Push the truss as a published deployment to the specified environment."
455-
"If specified, --publish is implied and the supplied value of --promote will be ignored."
483+
"If specified, publish is implied and the supplied value of --promote will be ignored."
456484
),
457485
)
458486
@click.option(
@@ -485,8 +513,8 @@ def run_python(script, target_directory):
485513
type=str,
486514
required=False,
487515
help=(
488-
"Name of the deployment created by the push. Can only be "
489-
"used in combination with --publish or --promote."
516+
"Name of the deployment created by the push. Cannot be "
517+
"used with --watch (development deployments)."
490518
),
491519
)
492520
@click.option(
@@ -544,6 +572,18 @@ def run_python(script, target_directory):
544572
required=False,
545573
help="JSON string of metadata key-value pairs.",
546574
)
575+
@click.option(
576+
"--watch",
577+
"watch_after_push",
578+
is_flag=True,
579+
required=False,
580+
default=False,
581+
help=(
582+
"Deploy as a development model and watch for changes. "
583+
"Waits for deployment to complete, then starts watching for code changes "
584+
"to apply live patches. Cannot be used with --promote, --environment, or --tail."
585+
),
586+
)
547587
@common.common_options()
548588
def push(
549589
target_directory: str,
@@ -565,13 +605,44 @@ def push(
565605
deploy_timeout_minutes: Optional[int] = None,
566606
provided_team_name: Optional[str] = None,
567607
metadata: Optional[str] = None,
608+
watch_after_push: bool = False,
568609
) -> None:
569610
"""
570611
Pushes a truss to a TrussRemote.
571612
572613
TARGET_DIRECTORY: A Truss directory. If none, use current directory.
573614
574615
"""
616+
617+
if publish:
618+
console.print(
619+
"[DEPRECATED] The --publish flag is deprecated. Published deployments are now the default.",
620+
style="yellow",
621+
)
622+
623+
# Handle --watch flag: deploys as development and then watches
624+
if watch_after_push:
625+
if promote:
626+
raise click.UsageError(
627+
"Cannot use --watch with --promote. Watch mode runs a development deployment."
628+
)
629+
if environment:
630+
raise click.UsageError(
631+
"Cannot use --watch with --environment. Watch mode runs a development deployment."
632+
)
633+
if tail:
634+
raise click.UsageError("Cannot use --watch with --tail.")
635+
# Development deployment for watch mode
636+
publish = False
637+
wait = True
638+
else:
639+
# Default is now published deployment
640+
publish = True
641+
console.print(
642+
"Deploying as a published deployment. Use --watch for a development deployment.",
643+
style="green",
644+
)
645+
575646
tr = _get_truss_from_directory(target_directory=target_directory, config=config)
576647

577648
if tr.spec.config.resources.instance_type:
@@ -586,7 +657,7 @@ def push(
586657
and not promote
587658
):
588659
raise click.UsageError(
589-
"Truss with gRPC transport cannot be used as a development deployment. Please rerun the command with --publish or --promote."
660+
"Truss with gRPC transport cannot be used as a development deployment. Remove --watch to deploy as a published model."
590661
)
591662

592663
if not remote:
@@ -609,7 +680,7 @@ def push(
609680
effective_team_name = provided_team_name or RemoteFactory.get_remote_team(
610681
remote
611682
)
612-
_, team_id = resolve_model_team_name(
683+
team_name, team_id = resolve_model_team_name(
613684
remote_provider=remote_provider,
614685
provided_team_name=effective_team_name,
615686
existing_model_name=model_name,
@@ -662,7 +733,7 @@ def push(
662733
# trt-llm engine builder checks
663734
if uses_trt_llm_builder(tr):
664735
if not publish:
665-
live_reload_disabled_text = "Development mode is currently not supported for trusses using TRT-LLM build flow, push as a published model using --publish"
736+
live_reload_disabled_text = "Development mode is currently not supported for trusses using TRT-LLM build flow. Remove --watch to deploy as a published model."
666737
console.print(live_reload_disabled_text, style="red")
667738
sys.exit(1)
668739

@@ -720,8 +791,7 @@ def push(
720791
| iterate quickly during the deployment process. |
721792
| |
722793
| When you are ready to publish your deployed model as a new deployment, |
723-
| pass '--publish' to the 'truss push' command. To monitor changes to your model and |
724-
| rapidly iterate, run the 'truss watch' command. |
794+
| run 'truss push' without --watch. |
725795
| |
726796
|---------------------------------------------------------------------------------------|
727797
"""
@@ -741,8 +811,6 @@ def push(
741811
if wait:
742812
start_time = time.time()
743813
with console.status("[bold green]Deploying...") as status:
744-
# Poll for the deployment status until we have reached. Either ACTIVE,
745-
# or a non-deploying status (in which case the deployment has failed).
746814
for deployment_status in service.poll_deployment_status():
747815
if (
748816
timeout_seconds is not None
@@ -757,7 +825,7 @@ def push(
757825

758826
if deployment_status == ACTIVE_STATUS:
759827
console.print("Deployment succeeded.", style="bold green")
760-
return
828+
break
761829

762830
if deployment_status not in DEPLOYING_STATUSES:
763831
console.print(
@@ -766,6 +834,27 @@ def push(
766834
)
767835
sys.exit(1)
768836

837+
# If --watch was used, start watching after deploy success
838+
if watch_after_push:
839+
if not isinstance(remote_provider, BasetenRemote):
840+
raise click.UsageError(
841+
f"Watch mode is not supported for remote provider type: {type(remote_provider).__name__}"
842+
)
843+
bt_remote = cast(BasetenRemote, remote_provider)
844+
console.print("Starting watch mode...", style="bold blue")
845+
resolved_model, versions = resolve_model_for_watch(
846+
bt_remote, model_name, provided_team_name=team_name
847+
)
848+
_start_watch_mode(
849+
target_directory=target_directory,
850+
model_name=model_name,
851+
remote_provider=bt_remote,
852+
resolved_model=resolved_model,
853+
resolved_versions=versions,
854+
console=console,
855+
error_console=error_console,
856+
)
857+
769858
elif tail and isinstance(service, BasetenService):
770859
bt_remote = cast(BasetenRemote, remote_provider)
771860
log_watcher = ModelDeploymentLogWatcher(
@@ -862,31 +951,29 @@ def watch(
862951
# Verify dev version exists
863952
dev_version = get_dev_version_from_versions(versions)
864953
if not dev_version:
865-
console.print("❌ No development model found. Run `truss push` then try again.")
954+
console.print(
955+
"❌ No development model found. Run `truss push --watch` then try again."
956+
)
866957
sys.exit(1)
867958

868959
# Use model_id to get service (no additional resolution needed)
869-
service = remote_provider.get_service(model_identifier=ModelId(model_id))
960+
dev_version_id = dev_version["id"]
961+
logs_url = URLConfig.model_logs_url(
962+
remote_provider.remote_url, model_id, dev_version_id
963+
)
870964
console.print(
871-
f"🪵 View logs for your deployment at {common.format_link(service.logs_url)}"
965+
f"🪵 View logs for your development model at {common.format_link(logs_url)}"
872966
)
873967

874-
if not os.path.isfile(target_directory):
875-
# Pass the resolved model to avoid re-resolution
876-
remote_provider.sync_truss_to_dev_version_with_model(
877-
resolved_model, versions, target_directory, console, error_console
878-
)
879-
else:
880-
# These imports are delayed, to handle pydantic v1 envs gracefully.
881-
from truss_chains.deployment import deployment_client
882-
883-
deployment_client.watch_model(
884-
source=Path(target_directory),
885-
model_name=model_name,
886-
remote_provider=remote_provider,
887-
console=console,
888-
error_console=error_console,
889-
)
968+
_start_watch_mode(
969+
target_directory=target_directory,
970+
model_name=model_name,
971+
remote_provider=remote_provider,
972+
resolved_model=resolved_model,
973+
resolved_versions=versions,
974+
console=console,
975+
error_console=error_console,
976+
)
890977

891978

892979
### Image commands. ####################################################################

0 commit comments

Comments
 (0)