feat: passthrough extra args for adk deploy cloud_run as Cloud Run args

Merge https://github.com/google/adk-python/pull/2544

The command `adk deploy cloud_run` supports limited `gcloud run deploy` args 😢.

Which makes the command fine for simple deployments...

It should support all current and future Cloud Run deployment args for the command to be widely adopted.

This can easily be done by passing through all extra args passed to `adk deploy cloud_run` to gcloud...

This PR assumes any extra args/flags passed after `AGENT_PATH` are gcloud flags.

## Example

```sh
# ADK flags
adk deploy cloud_run \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
$AGENT_PATH \
# Use the -- separator for gcloud args
-- \
--min-instances=2 \
--no-allow-unauthenticated
```

This gives full Cloud Run feature support to ADK users 🤖 🚀

## Test Plan

To test you can just build locally or pip install feature branch directly:

```
uv venv
uv pip install git+https://github.com/jackwotherspoon/adk-python.git
```

Deploy to Cloud Run using additional arguments following `AGENT_PATH`, such as `--min-instance=2` or `--description="Cloud Run test"`:

```sh
uv run adk deploy cloud_run \
--project=$GOOGLE_CLOUD_PROJECT \
--region=$GOOGLE_CLOUD_LOCATION \
--with_ui \
$AGENT_PATH \
-- \
--labels=test-label=adk \
--min-instances=2
```

You can click on the Cloud Run service after deployment and check the service yaml, you should see the additional label etc.

<img width="1612" height="622" alt="image" src="https://github.com/user-attachments/assets/596a260a-0052-460b-9642-c18900ccf7c9" />

Fixes https://github.com/google/adk-python/issues/2351

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2544 from jackwotherspoon:main 184a4d73f8dbe6f565ff92cf1c1fe69bb163de5e
PiperOrigin-RevId: 799252544
This commit is contained in:
Jack Wotherspoon
2025-08-25 13:45:21 -07:00
committed by Copybara-Service
parent 2b2f0b52d8
commit 6806deaf88
5 changed files with 451 additions and 23 deletions
@@ -636,3 +636,76 @@ def test_to_gke_happy_path(
# 4. Verify cleanup
assert str(rmtree_recorder.get_last_call_args()[0]) == str(tmp_path)
# Label merging tests
@pytest.mark.parametrize(
"extra_gcloud_args, expected_labels",
[
# No user labels - should only have default ADK label
(None, "created-by=adk"),
([], "created-by=adk"),
# Single user label
(["--labels=env=test"], "created-by=adk,env=test"),
# Multiple user labels in same argument
(
["--labels=env=test,team=myteam"],
"created-by=adk,env=test,team=myteam",
),
# User labels mixed with other args
(
["--memory=1Gi", "--labels=env=test", "--cpu=1"],
"created-by=adk,env=test",
),
# Multiple --labels arguments
(
["--labels=env=test", "--labels=team=myteam"],
"created-by=adk,env=test,team=myteam",
),
# Labels with other passthrough args
(
["--timeout=300", "--labels=env=prod", "--max-instances=10"],
"created-by=adk,env=prod",
),
],
)
def test_cloud_run_label_merging(
monkeypatch: pytest.MonkeyPatch,
agent_dir: Callable[[bool, bool], Path],
tmp_path: Path,
extra_gcloud_args: list[str] | None,
expected_labels: str,
) -> None:
"""Test that user labels are properly merged with the default ADK label."""
src_dir = agent_dir(False, False)
run_recorder = _Recorder()
monkeypatch.setattr(subprocess, "run", run_recorder)
monkeypatch.setattr(shutil, "rmtree", lambda x: None)
# Execute the function under test
cli_deploy.to_cloud_run(
agent_folder=str(src_dir),
project="test-project",
region="us-central1",
service_name="test-service",
app_name="test-app",
temp_folder=str(tmp_path),
port=8080,
trace_to_cloud=False,
with_ui=False,
log_level="info",
verbosity="info",
adk_version="1.0.0",
extra_gcloud_args=tuple(extra_gcloud_args) if extra_gcloud_args else None,
)
# Verify that the gcloud command was called
assert len(run_recorder.calls) == 1
gcloud_args = run_recorder.get_last_call_args()[0]
# Find the labels argument
labels_idx = gcloud_args.index("--labels")
actual_labels = gcloud_args[labels_idx + 1]
assert actual_labels == expected_labels