Skip to content

Commit 74b224e

Browse files
authored
Add output mode to commands to output json (#27)
* Add output mode to commands to output json * Add e2e deploy test * Add cleanup and delete agent workspace * Cleanup e2e test * Add full JSON output mode
1 parent f3faef7 commit 74b224e

File tree

7 files changed

+1015
-81
lines changed

7 files changed

+1015
-81
lines changed

gradient_adk/cli/agent/deployment/deploy_service.py

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(
5959
s3_uploader: S3Uploader | None = None,
6060
polling_interval_sec: float = 10.0,
6161
max_polling_time_sec: float = 600.0, # 10 minutes
62+
quiet: bool = False,
6263
):
6364
"""Initialize the deploy service.
6465
@@ -68,12 +69,14 @@ def __init__(
6869
s3_uploader: S3 uploader for uploading files (defaults to HttpxS3Uploader)
6970
polling_interval_sec: How often to poll for release status
7071
max_polling_time_sec: Maximum time to wait for deployment
72+
quiet: If True, suppress progress output (for JSON output mode)
7173
"""
7274
self.client = client
7375
self.zip_creator = zip_creator or DirectoryZipCreator()
7476
self.s3_uploader = s3_uploader or HttpxS3Uploader()
7577
self.polling_interval_sec = polling_interval_sec
7678
self.max_polling_time_sec = max_polling_time_sec
79+
self.quiet = quiet
7780

7881
async def deploy_agent(
7982
self,
@@ -109,9 +112,8 @@ async def deploy_agent(
109112
ValueError: If source directory doesn't exist
110113
Exception: If deployment fails
111114
"""
112-
print(
113-
"Starting agent deployment...",
114-
)
115+
if not self.quiet:
116+
print("Starting agent deployment...")
115117

116118
#: Check if workspace and deployment exist
117119
workspace_exists, deployment_exists = await self._check_existing_resources(
@@ -192,15 +194,17 @@ async def _check_existing_resources(
192194
agent_workspace_name=agent_workspace_name,
193195
agent_deployment_name=agent_deployment_name,
194196
)
195-
logger.info(
196-
f"Deployment '{agent_deployment_name}' exists - will create new release"
197-
)
197+
if not self.quiet:
198+
logger.info(
199+
f"Deployment '{agent_deployment_name}' exists - will create new release"
200+
)
198201
return True, True
199202
except DOAPIClientError as e:
200203
if e.status_code == 404:
201-
logger.info(
202-
f"Deployment '{agent_deployment_name}' does not exist - will create new"
203-
)
204+
if not self.quiet:
205+
logger.info(
206+
f"Deployment '{agent_deployment_name}' does not exist - will create new"
207+
)
204208
return True, False
205209
raise
206210

@@ -401,10 +405,9 @@ async def _poll_release_status(self, release_uuid: str) -> None:
401405
Raises:
402406
Exception: If deployment fails or times out
403407
"""
404-
import sys
405-
406-
print(f"Monitoring deployment progress (UUID: {release_uuid})...")
407-
print() # Add blank line for better formatting
408+
if not self.quiet:
409+
print(f"Monitoring deployment progress (UUID: {release_uuid})...")
410+
print() # Add blank line for better formatting
408411

409412
start_time = time.time()
410413
last_status = None
@@ -442,7 +445,8 @@ def format_elapsed(seconds: float) -> str:
442445

443446
# Check timeout
444447
if elapsed > self.max_polling_time_sec:
445-
print("\r" + " " * 80 + "\r", end="") # Clear line
448+
if not self.quiet:
449+
print("\r" + " " * 80 + "\r", end="") # Clear line
446450
raise Exception(
447451
f"Deployment timed out after {self.max_polling_time_sec}s"
448452
)
@@ -461,7 +465,8 @@ def format_elapsed(seconds: float) -> str:
461465

462466
# Log status changes (clear line first to avoid glitches)
463467
if current_status != last_status:
464-
print("\r" + " " * 80 + "\r", end="", flush=True) # Clear line
468+
if not self.quiet:
469+
print("\r" + " " * 80 + "\r", end="", flush=True) # Clear line
465470
logger.debug(
466471
f"Release status changed to: {current_status.value if hasattr(current_status, 'value') else current_status}"
467472
)
@@ -471,43 +476,46 @@ def format_elapsed(seconds: float) -> str:
471476

472477
# Check terminal states
473478
if current_status == ReleaseStatus.RELEASE_STATUS_RUNNING:
474-
print("\r" + " " * 80 + "\r", end="") # Clear line
475-
print(
476-
f"✅ Deployment completed successfully! [{format_elapsed(elapsed)}]"
477-
)
479+
if not self.quiet:
480+
print("\r" + " " * 80 + "\r", end="") # Clear line
481+
print(
482+
f"✅ Deployment completed successfully! [{format_elapsed(elapsed)}]"
483+
)
478484
return
479485

480486
if current_status == ReleaseStatus.RELEASE_STATUS_FAILED:
481-
print("\r" + " " * 80 + "\r", end="") # Clear line
487+
if not self.quiet:
488+
print("\r" + " " * 80 + "\r", end="") # Clear line
482489
error_msg = release.error_msg or "Unknown error"
483490
raise Exception(
484491
f"Deployment failed due to release status being failed: {error_msg}"
485492
)
486493

487-
# Update spinner and display (every iteration for smooth animation)
488-
if current_status:
489-
emoji, message = status_display.get(
490-
current_status,
491-
(
492-
"⚙️",
494+
# Update spinner and display (every iteration for smooth animation) - only in non-quiet mode
495+
if not self.quiet:
496+
if current_status:
497+
emoji, message = status_display.get(
498+
current_status,
493499
(
494-
current_status.value
495-
if hasattr(current_status, "value")
496-
else str(current_status)
500+
"⚙️",
501+
(
502+
current_status.value
503+
if hasattr(current_status, "value")
504+
else str(current_status)
505+
),
497506
),
498-
),
499-
)
500-
else:
501-
emoji, message = ("⚙️", "Starting")
507+
)
508+
else:
509+
emoji, message = ("⚙️", "Starting")
502510

503-
spinner = spinner_chars[spinner_index % len(spinner_chars)]
504-
elapsed_str = format_elapsed(elapsed)
511+
spinner = spinner_chars[spinner_index % len(spinner_chars)]
512+
elapsed_str = format_elapsed(elapsed)
505513

506-
# Print status line with spinner
507-
status_line = f"{spinner} {emoji} {message}... [{elapsed_str}]"
508-
print(f"\r{status_line}", end="", flush=True)
514+
# Print status line with spinner
515+
status_line = f"{spinner} {emoji} {message}... [{elapsed_str}]"
516+
print(f"\r{status_line}", end="", flush=True)
509517

510518
spinner_index += 1
511519

512520
# Short sleep for smooth animation (0.1 seconds)
513-
await asyncio.sleep(0.1)
521+
await asyncio.sleep(0.1)

gradient_adk/cli/agent/deployment/validation.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ValidationError(Exception):
1616

1717

1818
def validate_agent_entrypoint(
19-
source_dir: Path, entrypoint_file: str, verbose: bool = False
19+
source_dir: Path, entrypoint_file: str, verbose: bool = False, quiet: bool = False
2020
) -> None:
2121
"""
2222
Validate that the agent can run successfully in a fresh environment.
@@ -28,14 +28,16 @@ def validate_agent_entrypoint(
2828
source_dir: Directory containing the agent source code
2929
entrypoint_file: Relative path to the entrypoint file (e.g., "main.py")
3030
verbose: Whether to print verbose validation output
31+
quiet: Whether to suppress all output (for JSON mode)
3132
3233
Raises:
3334
ValidationError: If validation fails
3435
"""
35-
print(
36-
f"🔍 Validating agent can run before deployment... (skip this step with --skip-validation)"
37-
)
38-
if verbose:
36+
if not quiet:
37+
print(
38+
f"🔍 Validating agent can run before deployment... (skip this step with --skip-validation)"
39+
)
40+
if verbose and not quiet:
3941
print(f"🔍 Validating agent before deployment...")
4042
print(f" Source: {source_dir}")
4143
print(f" Entrypoint: {entrypoint_file}")
@@ -280,4 +282,4 @@ def should_exclude(path: Path) -> bool:
280282
print(f" Copied: {item.name}")
281283
except Exception as e:
282284
if verbose:
283-
print(f" Warning: Failed to copy {item.name}: {e}")
285+
print(f" Warning: Failed to copy {item.name}: {e}")

0 commit comments

Comments
 (0)