-
Notifications
You must be signed in to change notification settings - Fork 26
AEnv CLI support instance create/get/list/delete and system_url/owner config #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Summary of ChangesHello @JacksonMei, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly expands the AEnv command-line interface by introducing a comprehensive set of commands for managing environment instances. It enables users to perform full lifecycle operations such as creating, inspecting, listing, and deleting instances directly from the CLI, thereby streamlining the interaction with the AEnv system. The changes involve both new CLI implementation and corresponding backend API and controller modifications to support these new capabilities. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces CLI support for managing AEnv instances, including create, get, list, and delete operations. The changes span both the Python CLI and the Go backend services. My review focuses on improving configuration handling consistency in the CLI, addressing a performance issue in the list command, and correcting potentially misleading data in the API response. Overall, the changes are a great addition, and with a few adjustments, they will be even more robust and efficient.
| elif output == "table": | ||
| # Prepare table data | ||
| table_data = [] | ||
| for instance in instances_list: | ||
| instance_id = instance.get("id", "") | ||
| if not instance_id: | ||
| continue | ||
|
|
||
| # Try to get detailed info for each instance | ||
| detailed_info = _get_instance_from_api(system_url, instance_id) | ||
|
|
||
| # Use detailed info if available, otherwise use list data | ||
| if detailed_info: | ||
| env_info = detailed_info.get("env") or {} | ||
| else: | ||
| env_info = instance.get("env") or {} | ||
|
|
||
| env_name = env_info.get("name") if env_info else None | ||
| env_version = env_info.get("version") if env_info else None | ||
|
|
||
| # If env is None, try to extract from instance ID | ||
| if not env_name and instance_id: | ||
| parts = instance_id.split("-") | ||
| if len(parts) >= 2: | ||
| env_name = parts[0] | ||
|
|
||
| # Get IP from detailed info or list data | ||
| if detailed_info: | ||
| ip = detailed_info.get("ip") or "" | ||
| else: | ||
| ip = instance.get("ip") or "" | ||
|
|
||
| if not ip: | ||
| ip = "-" | ||
|
|
||
| # Get status from detailed info or list data | ||
| status = ( | ||
| detailed_info.get("status") | ||
| if detailed_info | ||
| else instance.get("status") or "-" | ||
| ) | ||
|
|
||
| # Get created_at from list data | ||
| created_at = instance.get("created_at") or "-" | ||
|
|
||
| table_data.append( | ||
| { | ||
| "Instance ID": instance_id, | ||
| "Environment": env_name or "-", | ||
| "Version": env_version or "-", | ||
| "Status": status, | ||
| "IP": ip, | ||
| "Created At": created_at, | ||
| } | ||
| ) | ||
|
|
||
| if table_data: | ||
| console.print(tabulate(table_data, headers="keys", tablefmt="grid")) | ||
| else: | ||
| console.print("📭 No running instances found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of list_instances makes an additional API call (_get_instance_from_api) for each instance returned by the initial list call. This is an example of an N+1 query problem and can lead to significant performance issues when there are many instances. The backend has been updated to include detailed information in the list response, so these extra calls are unnecessary. You should refactor this to process the data from the initial list response directly.
elif output == "table":
# Prepare table data
table_data = []
for instance_data in instances_list:
instance_id = instance_data.get("id", "")
if not instance_id:
continue
env_info = instance_data.get("env") or {}
env_name = env_info.get("name")
env_version = env_info.get("version")
# Fallback for older API versions or if env block is missing
if not env_name and instance_id:
parts = instance_id.split("-")
if len(parts) >= 2:
env_name = parts[0]
table_data.append(
{
"Instance ID": instance_id,
"Environment": env_name or "-",
"Version": env_version or "-",
"Status": instance_data.get("status", "-"),
"IP": instance_data.get("ip") or "-",
"Created At": instance_data.get("created_at") or "-",
}
)
if table_data:
console.print(tabulate(table_data, headers="keys", tablefmt="grid"))
else:
console.print("📭 No running instances found")
aenv/src/cli/cmds/instance.py
Outdated
| def _get_system_url() -> str: | ||
| """Get AEnv system URL from environment variable or config.""" | ||
| system_url = os.getenv("AENV_SYSTEM_URL") | ||
| if not system_url: | ||
| system_url = "http://localhost:8080" | ||
| return _make_api_url(system_url, port=8080) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring for _get_system_url mentions that it gets the URL from environment variables or config, but the implementation only checks the environment variable AENV_SYSTEM_URL. This is inconsistent with other parts of the CLI, like _get_api_headers, which do check the configuration file. To ensure consistent behavior, this function should also retrieve the system URL from the CLI configuration. This will allow users to configure the system URL in one central place.
| def _get_system_url() -> str: | |
| """Get AEnv system URL from environment variable or config.""" | |
| system_url = os.getenv("AENV_SYSTEM_URL") | |
| if not system_url: | |
| system_url = "http://localhost:8080" | |
| return _make_api_url(system_url, port=8080) | |
| def _get_system_url() -> str: | |
| """Get AEnv system URL from environment variable or config.""" | |
| config_manager = get_config_manager() | |
| hub_config = config_manager.get_hub_config() | |
| system_url = hub_config.get("hub_backend") or os.getenv("AENV_SYSTEM_URL") | |
| if not system_url: | |
| system_url = "http://localhost:8080" | |
| return _make_api_url(system_url, port=8080) |
aenv/src/cli/cmds/instance.py
Outdated
| # Get API key from env if not provided | ||
| if not api_key: | ||
| api_key = os.getenv("AENV_API_KEY") | ||
|
|
||
| # Get system URL from env if not provided | ||
| if not system_url: | ||
| system_url = os.getenv("AENV_SYSTEM_URL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for retrieving the API key and system URL only considers command-line options and environment variables, but it omits checking the CLI configuration file. This is inconsistent with how other configurations are handled (e.g., in _get_api_headers). For a better user experience and more consistent configuration management, you should also check the configuration file for these values.
| # Get API key from env if not provided | |
| if not api_key: | |
| api_key = os.getenv("AENV_API_KEY") | |
| # Get system URL from env if not provided | |
| if not system_url: | |
| system_url = os.getenv("AENV_SYSTEM_URL") | |
| # Get API key from config/env if not provided | |
| config_manager = get_config_manager() | |
| hub_config = config_manager.get_hub_config() | |
| if not api_key: | |
| api_key = hub_config.get("api_key") or os.getenv("AENV_API_KEY") | |
| # Get system URL from config/env if not provided | |
| if not system_url: | |
| system_url = hub_config.get("hub_backend") or os.getenv("AENV_SYSTEM_URL") |
aenv/src/cli/cmds/instance.py
Outdated
| # Get API key from env if not provided | ||
| if not api_key: | ||
| api_key = os.getenv("AENV_API_KEY") | ||
|
|
||
| # Get system URL from env if not provided | ||
| if not system_url: | ||
| system_url = os.getenv("AENV_SYSTEM_URL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the create command, the logic for retrieving the API key and system URL here only considers command-line options and environment variables, but it omits checking the CLI configuration file. For consistency and better configuration management, you should also check the configuration file for these values.
| # Get API key from env if not provided | |
| if not api_key: | |
| api_key = os.getenv("AENV_API_KEY") | |
| # Get system URL from env if not provided | |
| if not system_url: | |
| system_url = os.getenv("AENV_SYSTEM_URL") | |
| # Get API key from config/env if not provided | |
| config_manager = get_config_manager() | |
| hub_config = config_manager.get_hub_config() | |
| if not api_key: | |
| api_key = hub_config.get("api_key") or os.getenv("AENV_API_KEY") | |
| # Get system URL from config/env if not provided | |
| if not system_url: | |
| system_url = hub_config.get("hub_backend") or os.getenv("AENV_SYSTEM_URL") |
| createdAtStr := podData.CreatedAt.Format("2006-01-02 15:04:05") | ||
| nowStr := time.Now().Format("2006-01-02 15:04:05") | ||
|
|
||
| instances[i] = &models.EnvInstance{ | ||
| ID: podData.ID, | ||
| Env: env, | ||
| Status: podData.Status, | ||
| CreatedAt: createdAtStr, | ||
| UpdatedAt: nowStr, | ||
| IP: podData.IP, | ||
| TTL: podData.TTL, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting UpdatedAt to time.Now() is misleading, as it reflects the time of the API call rather than when the resource was last modified. This can cause confusion for clients of the API. Since the pod data from the controller does not seem to provide an update timestamp, it would be more accurate and less confusing to set UpdatedAt to the same value as CreatedAt.
| createdAtStr := podData.CreatedAt.Format("2006-01-02 15:04:05") | |
| nowStr := time.Now().Format("2006-01-02 15:04:05") | |
| instances[i] = &models.EnvInstance{ | |
| ID: podData.ID, | |
| Env: env, | |
| Status: podData.Status, | |
| CreatedAt: createdAtStr, | |
| UpdatedAt: nowStr, | |
| IP: podData.IP, | |
| TTL: podData.TTL, | |
| } | |
| // Format CreatedAt time | |
| createdAtStr := podData.CreatedAt.Format("2006-01-02 15:04:05") | |
| instances[i] = &models.EnvInstance{ | |
| ID: podData.ID, | |
| Env: env, | |
| Status: podData.Status, | |
| CreatedAt: createdAtStr, | |
| UpdatedAt: createdAtStr, | |
| IP: podData.IP, | |
| TTL: podData.TTL, | |
| } |
lanmaoxinqing
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
No description provided.