mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
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
166 lines
5.3 KiB
Python
166 lines
5.3 KiB
Python
# Copyright 2025 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Unit tests to check if any Click options and method parameters mismatch."""
|
|
|
|
import inspect
|
|
from typing import MutableMapping
|
|
from typing import Optional
|
|
|
|
import click
|
|
from google.adk.cli.cli_tools_click import cli_api_server
|
|
from google.adk.cli.cli_tools_click import cli_create_cmd
|
|
from google.adk.cli.cli_tools_click import cli_deploy_agent_engine
|
|
from google.adk.cli.cli_tools_click import cli_deploy_cloud_run
|
|
from google.adk.cli.cli_tools_click import cli_deploy_gke
|
|
from google.adk.cli.cli_tools_click import cli_eval
|
|
from google.adk.cli.cli_tools_click import cli_run
|
|
from google.adk.cli.cli_tools_click import cli_web
|
|
from google.adk.cli.cli_tools_click import deploy
|
|
from google.adk.cli.cli_tools_click import main
|
|
|
|
|
|
def _get_command_by_name(
|
|
commands: MutableMapping[str, click.Command], name
|
|
) -> Optional[click.Command]:
|
|
"""Return the command object with the given name from a commands dict."""
|
|
return next((cmd for cmd in commands.values() if cmd.name == name), None)
|
|
|
|
|
|
def _get_click_options(command) -> set[str]:
|
|
"""Extract Click option names from a command."""
|
|
options = []
|
|
for param in command.params:
|
|
if isinstance(param, (click.Option, click.Argument)):
|
|
options.append(param.name)
|
|
return set(options)
|
|
|
|
|
|
def _get_method_parameters(func) -> set[str]:
|
|
"""Extract parameter names from a method signature."""
|
|
sig = inspect.signature(func)
|
|
return set(sig.parameters.keys())
|
|
|
|
|
|
def _check_options_in_parameters(
|
|
command,
|
|
func,
|
|
command_name,
|
|
ignore_params: Optional[set[str]] = None,
|
|
):
|
|
"""Check if all Click options are present in method parameters."""
|
|
click_options = _get_click_options(command)
|
|
method_params = _get_method_parameters(func)
|
|
|
|
if ignore_params:
|
|
click_options -= ignore_params
|
|
method_params -= ignore_params
|
|
|
|
option_only = click_options - method_params
|
|
parameter_only = method_params - click_options
|
|
|
|
assert click_options == method_params, f"""\
|
|
Click options and method parameters do not match for command: `{command_name}`.
|
|
Click options: {click_options}
|
|
Method parameters: {method_params}
|
|
Options only: {option_only}
|
|
Parameters only: {parameter_only}
|
|
"""
|
|
|
|
|
|
def test_adk_create():
|
|
"""Test that cli_create_cmd has all required parameters."""
|
|
create_command = _get_command_by_name(main.commands, "create")
|
|
|
|
assert create_command is not None, "Create command not found"
|
|
_check_options_in_parameters(
|
|
create_command, cli_create_cmd.callback, "create"
|
|
)
|
|
|
|
|
|
def test_adk_run():
|
|
"""Test that cli_run has all required parameters."""
|
|
run_command = _get_command_by_name(main.commands, "run")
|
|
|
|
assert run_command is not None, "Run command not found"
|
|
_check_options_in_parameters(run_command, cli_run.callback, "run")
|
|
|
|
|
|
def test_adk_eval():
|
|
"""Test that cli_eval has all required parameters."""
|
|
eval_command = _get_command_by_name(main.commands, "eval")
|
|
|
|
assert eval_command is not None, "Eval command not found"
|
|
_check_options_in_parameters(eval_command, cli_eval.callback, "eval")
|
|
|
|
|
|
def test_adk_web():
|
|
"""Test that cli_web has all required parameters."""
|
|
web_command = _get_command_by_name(main.commands, "web")
|
|
|
|
assert web_command is not None, "Web command not found"
|
|
_check_options_in_parameters(
|
|
web_command, cli_web.callback, "web", ignore_params={"verbose"}
|
|
)
|
|
|
|
|
|
def test_adk_api_server():
|
|
"""Test that cli_api_server has all required parameters."""
|
|
api_server_command = _get_command_by_name(main.commands, "api_server")
|
|
|
|
assert api_server_command is not None, "API server command not found"
|
|
_check_options_in_parameters(
|
|
api_server_command,
|
|
cli_api_server.callback,
|
|
"api_server",
|
|
ignore_params={"verbose"},
|
|
)
|
|
|
|
|
|
def test_adk_deploy_cloud_run():
|
|
"""Test that cli_deploy_cloud_run has all required parameters."""
|
|
cloud_run_command = _get_command_by_name(deploy.commands, "cloud_run")
|
|
|
|
assert cloud_run_command is not None, "Cloud Run deploy command not found"
|
|
_check_options_in_parameters(
|
|
cloud_run_command,
|
|
cli_deploy_cloud_run.callback,
|
|
"deploy cloud_run",
|
|
ignore_params={"verbose", "ctx"},
|
|
)
|
|
|
|
|
|
def test_adk_deploy_agent_engine():
|
|
"""Test that cli_deploy_agent_engine has all required parameters."""
|
|
agent_engine_command = _get_command_by_name(deploy.commands, "agent_engine")
|
|
|
|
assert (
|
|
agent_engine_command is not None
|
|
), "Agent Engine deploy command not found"
|
|
_check_options_in_parameters(
|
|
agent_engine_command,
|
|
cli_deploy_agent_engine.callback,
|
|
"deploy agent_engine",
|
|
)
|
|
|
|
|
|
def test_adk_deploy_gke():
|
|
"""Test that cli_deploy_gke has all required parameters."""
|
|
gke_command = _get_command_by_name(deploy.commands, "gke")
|
|
|
|
assert gke_command is not None, "GKE deploy command not found"
|
|
_check_options_in_parameters(
|
|
gke_command, cli_deploy_gke.callback, "deploy gke"
|
|
)
|