Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Comments

kubectl style cli#338

Merged
NickCao merged 6 commits intomainfrom
client-svc-lease
Mar 20, 2025
Merged

kubectl style cli#338
NickCao merged 6 commits intomainfrom
client-svc-lease

Conversation

@NickCao
Copy link
Collaborator

@NickCao NickCao commented Mar 11, 2025

See jumpstarter-dev/jumpstarter-protocol#17

Summary by CodeRabbit

  • New Features

    • Introduced new CLI commands for creating, retrieving, deleting, and updating leases and exporters.
    • Added enhanced configuration options and selector-based filtering for more intuitive management and clearer output.
  • Refactor

    • Replaced legacy commands with a streamlined, consolidated CLI structure.
    • Improved parameter handling and error management to deliver a more robust user experience.

@NickCao NickCao marked this pull request as draft March 11, 2025 18:13
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2025

Walkthrough

This pull request overhauls the CLI commands in the Jumpstarter client. It removes the old list_client_exporters and client_lease commands and replaces them with new commands: create, get, delete, and update. In addition, new supporting files (such as common.py, create.py, delete.py, get.py, and update.py) have been introduced to handle configuration options, parameter types, and command logic. Changes in client configuration and Kubernetes lease models have also been applied to ensure consistency with the new command structure.

Changes

File(s) Change Summary
packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py
Removed legacy commands (list_client_exporters, client_lease) and updated client_shell signature and logic to use new decorators/options.
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py
packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py
Added new files implementing commands for resource creation, deletion, retrieval, and update with corresponding CLI command functions and parameter handling.
packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py Updated exception decorators to include @wraps for preserving function metadata.
packages/jumpstarter/jumpstarter/config/client.py Enhanced ClientConfigV1Alpha1: modified list_leases (and async version) to accept filters; added methods for create_lease, delete_lease, and update_lease calling their async counterparts.
packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py Modified get_reason and make_lease_row to handle new selector structure (match_labels instead of direct dictionary access).
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py
Introduced new class V1Alpha1LeaseSelector (with field match_labels) and updated lease spec handling in both source and tests to encapsulate selector logic.
packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py Updated test cases to use V1Alpha1LeaseSelector instead of a plain dictionary for selector data.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant CLI as CreateLease Command
    participant Config as ClientConfig
    U->>CLI: Run "create lease" with selector & duration
    CLI->>Config: Call create_lease(selector, duration)
    Config->>Config: Validate input and process lease creation
    Config-->>CLI: Return lease details
    CLI-->>U: Output formatted lease information
Loading

Possibly related PRs

  • jumpstarter-dev/jumpstarter#293: Modifies the client_lease command structure and error handling, directly aligning with the CLI command transitions in this PR.

Suggested reviewers

  • mangelajo
  • bennyz

Poem

I'm a rabbit with a code-filled heart,
Hopping through changes, making a fresh start.
Old commands gone, new ones in play,
Carrot commands now brighten our day.
I nibble on code bits with cheerful delight,
Bounding through commits into the night!
🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@netlify
Copy link

netlify bot commented Mar 11, 2025

Deploy Preview for jumpstarter-docs ready!

Name Link
🔨 Latest commit fa18287
🔍 Latest deploy log https://app.netlify.com/sites/jumpstarter-docs/deploys/67dc22d91b8f5f0008820ff5
😎 Deploy Preview https://deploy-preview-338--jumpstarter-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@NickCao NickCao marked this pull request as ready for review March 12, 2025 15:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (17)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1)

19-21: Consider handling malformed selector inputs

The current implementation will fail if a selector term doesn't contain "=" character. Consider adding error handling for malformed inputs.

def selector_to_labels(selector: str):
    # TODO: support complex selectors (e.g. !=)
-    return dict([term.split("=") for term in selector.split(",")])
+    labels = {}
+    for term in selector.split(","):
+        if "=" not in term:
+            raise ValueError(f"Invalid selector format: {term}. Expected format: key=value")
+        key, value = term.split("=", 1)
+        labels[key] = value
+    return labels
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

26-39: Consider adding confirmation for bulk deletion

When using the --all flag, multiple leases can be deleted without confirmation. Consider adding a confirmation prompt to prevent accidental deletion.

elif all:
    leases = config.list_leases()
+    lease_names = []
    for lease in leases.leases:
        if lease.client == config.metadata.name:
-            names.append(lease.name)
+            lease_names.append(lease.name)
+    
+    if not lease_names:
+        click.echo("No leases found for the current client")
+        return
+    
+    click.echo(f"You are about to delete {len(lease_names)} lease(s): {', '.join(lease_names)}")
+    if not click.confirm("Do you want to continue?"):
+        click.echo("Operation cancelled")
+        return
+    
+    names.extend(lease_names)
packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (2)

18-27: Add examples of duration format in help text

The command requires a duration parameter but doesn't specify the expected format in the help text.

@update.command(name="lease")
@opt_context
@click.argument("name")
-@click.option("--duration", "duration", type=str, required=True)
+@click.option("--duration", "duration", type=str, required=True, 
+             help="Duration in format accepted by pydantic's timedelta (e.g., '1d', '24h', '86400s')")
@opt_output_all
@handle_exceptions

44-51: Consider enhancing selector formatting in table output

The current implementation joins selector key-value pairs with commas, which could be ambiguous if values contain commas. Consider using a different delimiter or format.

{
    "NAME": lease.name,
-    "SELECTOR": ",".join("{}={}".format(k, v) for (k, v) in lease.selector.match_labels.items()),
+    "SELECTOR": ";".join("{}={}".format(k, v) for (k, v) in lease.selector.match_labels.items()) if lease.selector.match_labels else "<none>",
    "DURATION": str(lease.duration.total_seconds()),
    "CLIENT": lease.client,
    "EXPORTER": lease.exporter,
}
packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (1)

32-36: Consider reordering commands for clarity.
Currently, commands are registered in the sequence “create, get, delete, update, config.” For a more intuitive flow, you might place “update” before “delete” (e.g., CRUD order).

- client.add_command(create)
- client.add_command(get)
- client.add_command(delete)
- client.add_command(update)
- client.add_command(config)
+ client.add_command(create)
+ client.add_command(get)
+ client.add_command(update)
+ client.add_command(delete)
+ client.add_command(config)
packages/jumpstarter-cli-client/jumpstarter_cli_client/config.py (4)

30-30: Function name mismatch with subcommand name.
For consistency, consider renaming create_client_config to match the “create” subcommand.

- @config.command("create", short_help="Create a client config.")
- def create_client_config(...):
+ @config.command("create", short_help="Create a client config.")
+ def create(...):

125-125: Function name mismatch with subcommand name.
Consider renaming delete_client_config to match the “delete” subcommand.

- @config.command("delete", short_help="Delete a client config.")
- def delete_client_config(...):
+ @config.command("delete", short_help="Delete a client config.")
+ def delete(...):

137-137: Function name mismatch with subcommand name.
Consider renaming list_client_configs to match the “list” subcommand.

- @config.command("list", short_help="List available client configurations.")
- def list_client_configs(...):
+ @config.command("list", short_help="List available client configurations.")
+ def list(...):

171-171: Function name mismatch with subcommand name.
Consider renaming use_client_config to match the “use” subcommand.

- @config.command("use", short_help="Select the current client config.")
- def use_client_config(...):
+ @config.command("use", short_help="Select the current client config.")
+ def use(...):
packages/jumpstarter/jumpstarter/client/grpc.py (1)

70-89: Deserialization logic for Lease.
The exporter field is set to an empty string if absent. Consider using None to indicate missing exporter more clearly.

-            exporter = ""
+            exporter = None
packages/jumpstarter/jumpstarter/config/client.py (7)

86-93: Consider avoiding the built-in filter name.
Using filter as a parameter name overshadows the built-in function filter. Although not critical, renaming it (e.g., filter_expr) might improve clarity.

 def list_leases(
     self,
     page_size: int | None = None,
     page_token: str | None = None,
-    filter: str | None = None,
+    filter_expr: str | None = None,
 ):
     with start_blocking_portal() as portal:
-        return portal.call(self.list_leases_async, page_size, page_token, filter)
+        return portal.call(self.list_leases_async, page_size, page_token, filter_expr)

95-102: Optionally handle exceptions or validation for selector and duration.
While the synchronous method simply delegates to create_lease_async, consider validating parameters here or catching known exceptions to provide more user-friendly feedback before raising.


103-109: Ensure consistent error handling.
Like the create_lease pattern, consider either returning a status or error message after the delete request completes, or continuing to rely solely on exceptions.


110-112: Add type annotation for name.
For clarity and consistency with other methods, annotate name: str in the signature.

-def update_lease(self, name, duration: timedelta):
+def update_lease(self, name: str, duration: timedelta):
     with start_blocking_portal() as portal:
         return portal.call(self.update_lease_async, name, duration)

135-149: Validate the selector format to prevent ValueError.
Assess whether selector might be empty or missing an = character. Currently, term.split("=") can trigger errors. You may gracefully handle malformed selectors or log a clear error.

 match_labels = dict([term.split("=") for term in selector.split(",")])
+if "" in match_labels.keys():
+    # Provide a user-friendly error or ignore blank terms
+    ...

179-190: Consider renaming filter to avoid overshadowing the built-in.
As with list_leases, renaming it (e.g., filter_expr) can prevent confusion.


191-194: Add a type annotation for the name argument.
For consistency with delete_lease_async and other methods, use name: str.

-async def update_lease_async(self, name, duration: timedelta):
+async def update_lease_async(self, name: str, duration: timedelta):
     svc = ClientService(channel=await self.channel())
     with translate_grpc_exceptions():
         return await svc.UpdateLease(namespace=self.metadata.namespace, name=name, duration=duration)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc63e79 and 9fc7258.

📒 Files selected for processing (27)
  • .github/workflows/e2e.yaml (1 hunks)
  • docs/source/cli/clients.md (1 hunks)
  • docs/source/config/cli.md (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_test.py (3 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/config.py (4 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter-protocol/jumpstarter_protocol/__init__.py (0 hunks)
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/client_pb2.py (1 hunks)
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/client_pb2_grpc.py (1 hunks)
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/client_pb2.py (0 hunks)
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/client_pb2_grpc.py (0 hunks)
  • packages/jumpstarter/conftest.py (0 hunks)
  • packages/jumpstarter/jumpstarter/client/grpc.py (4 hunks)
  • packages/jumpstarter/jumpstarter/client/lease.py (5 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (6 hunks)
  • packages/jumpstarter/jumpstarter/config/exporter_test.py (0 hunks)
  • packages/jumpstarter/jumpstarter/listener_test.py (0 hunks)
  • pyproject.toml (1 hunks)
💤 Files with no reviewable changes (8)
  • packages/jumpstarter/jumpstarter/config/exporter_test.py
  • packages/jumpstarter-protocol/jumpstarter_protocol/init.py
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/client_pb2.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
  • packages/jumpstarter/jumpstarter/listener_test.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
  • packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/client_pb2_grpc.py
  • packages/jumpstarter/conftest.py
🧰 Additional context used
🪛 Ruff (0.8.2)
packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/client_pb2.py

25-25: Module level import not at top of file

(E402)


25-25: google.api.annotations_pb2 imported but unused

Remove unused import: google.api.annotations_pb2

(F401)


26-26: Module level import not at top of file

(E402)


26-26: google.api.client_pb2 imported but unused

Remove unused import: google.api.client_pb2

(F401)


27-27: Module level import not at top of file

(E402)


27-27: google.api.field_behavior_pb2 imported but unused

Remove unused import: google.api.field_behavior_pb2

(F401)


28-28: Module level import not at top of file

(E402)


28-28: google.api.resource_pb2 imported but unused

Remove unused import: google.api.resource_pb2

(F401)


29-29: Module level import not at top of file

(E402)


29-29: google.protobuf.duration_pb2 imported but unused

Remove unused import: google.protobuf.duration_pb2

(F401)


30-30: Module level import not at top of file

(E402)


30-30: google.protobuf.empty_pb2 imported but unused

Remove unused import: google.protobuf.empty_pb2

(F401)


31-31: Module level import not at top of file

(E402)


31-31: google.protobuf.field_mask_pb2 imported but unused

Remove unused import: google.protobuf.field_mask_pb2

(F401)


32-32: Module level import not at top of file

(E402)


32-32: google.protobuf.timestamp_pb2 imported but unused

Remove unused import: google.protobuf.timestamp_pb2

(F401)


33-33: Module level import not at top of file

(E402)


33-33: ...v1.kubernetes_pb2 imported but unused

Remove unused import: ...v1.kubernetes_pb2

(F401)


36-36: Line too long (6089 > 120)

(E501)


43-43: Line too long (265 > 120)

(E501)


49-49: Line too long (159 > 120)

(E501)


65-65: Line too long (121 > 120)

(E501)


69-69: Line too long (142 > 120)

(E501)


71-71: Line too long (130 > 120)

(E501)


73-73: Line too long (136 > 120)

(E501)


81-81: Line too long (124 > 120)

(E501)


83-83: Line too long (130 > 120)

(E501)


91-91: Line too long (131 > 120)

(E501)


101-101: Line too long (127 > 120)

(E501)


103-103: Line too long (159 > 120)

(E501)


105-105: Line too long (163 > 120)

(E501)


107-107: Line too long (154 > 120)

(E501)


109-109: Line too long (158 > 120)

(E501)


111-111: Line too long (181 > 120)

(E501)


113-113: Line too long (182 > 120)

(E501)


115-115: Line too long (154 > 120)

(E501)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: pytest-matrix (3.13)
🔇 Additional comments (64)
packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (2)

16-17: Preserve Metadata in Async Exception Decorator
Adding @wraps(func) to the async decorator is a best practice because it retains the original function's metadata (name, docstring, etc.), which aids in debugging and introspection.


33-34: Preserve Metadata in Blocking Exception Decorator
The use of @wraps(func) for the synchronous decorator similarly ensures that the wrapped function keeps its original identity—this is beneficial for logging and testing.

pyproject.toml (1)

70-72: Extend Typos Configuration Properly
The addition of the [tool.typos.default.extend-words] section with ser = "ser" is a purposeful improvement to prevent false positives from the typo-checker. This small enhancement aligns well with our overall configuration strategy.

.github/workflows/e2e.yaml (1)

19-21: Update Workflow to Use Lease-Specific References
The update replacing the action version and parameter (switching from main to client-svc-lease) ensures that the E2E tests run against the correct branch/reference. This change properly aligns the workflow with the new lease-related methods under the client service.

docs/source/cli/clients.md (1)

82-89: Document Updated Client Configuration Command
The documentation now correctly refers to the new command jmp client config create my-client. The link reference and command example align with the revised CLI structure, providing clear guidance to the user.

docs/source/config/cli.md (1)

96-118: Reflect Updated Client Configuration Commands
The documentation updates here clearly illustrate the new client configuration commands for switching (jmp client config use <name>), listing (jmp client config list), and deletion (jmp client config delete <name>). This update enhances consistency with the consolidated command group and improves user understanding.

packages/jumpstarter-cli-client/jumpstarter_cli_client/client_test.py (2)

15-16: Command structure updated for better organization

The commands have been standardized to use a hierarchical structure with "config" as the main command group and actions like "create", "list", "use", and "delete" as subcommands. This makes the CLI more intuitive and aligned with modern CLI design practices.


36-37: Consistent command restructuring throughout tests

All command invocations have been updated to follow the new hierarchical structure. The test assertions remain unchanged, preserving the test functionality while adapting to the new command format.

Also applies to: 56-56, 62-62, 68-68, 72-72, 78-78, 82-82

packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (2)

8-16: Well-defined CLI options for context and selector

The defined options follow good CLI design practices with clear help text for the selector option, which will improve user experience.


24-34: Robust context loading with clear error messaging

The implementation correctly handles both explicit context and default client context, with appropriate error messaging when no valid context is available.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (2)

8-13: Well-structured command group for resource deletion

The command structure follows good CLI design practices with a clear hierarchy and descriptive docstring.


15-24: Comprehensive decorator setup for lease deletion command

The command is well-decorated with options for context, output formatting, and exception handling.

packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (2)

11-16: Clear command group structure for resource updates

The command structure follows good CLI design practices with a clear hierarchy and descriptive docstring.


35-53: Comprehensive output formatting options

The implementation supports multiple output formats (JSON, YAML, name-only, table) with appropriate formatting for each, providing good flexibility for users.

packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (4)

16-21: LGTM - Clean command group definition

The command group is well-structured with clear documentation on its purpose.


23-53: LGTM - Well-documented lease creation command

The command is properly decorated with required options and includes comprehensive documentation with practical examples, making it user-friendly.


54-57: LGTM - Good parameter validation

The code correctly loads the context and validates the duration parameter using TypeAdapter, ensuring that input is properly handled before proceeding.


58-79: LGTM - Comprehensive output formatting

The output handling is well-implemented with support for multiple formats (JSON, YAML, NAME, and tabular), giving users flexibility in how they consume the command output.

packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (3)

6-6: LGTM - Updated imports

Appropriate imports from the common module to support the updated function signature and implementation.


12-16: LGTM - Improved function signature and options

The command has been updated to use context and selector pattern, which is more consistent with the other commands in the CLI.


18-24: LGTM - Simplified lease acquisition

Clean implementation that uses the context loading pattern and creates a lease with the selector-based metadata filter.

packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (4)

7-13: LGTM - Well-defined selector option

The selector option has a clear help message explaining its purpose and usage format.


15-20: LGTM - Clear command group definition

The command group is well-structured with appropriate documentation.


22-53: LGTM - Comprehensive exporters command

The command has proper parameter handling and output formatting with support for multiple output types. The tabular output includes the essential information (name and labels).


55-87: LGTM - Well-implemented leases command

The command follows the same pattern as the exporters command, maintaining consistency throughout the CLI. The tabular output includes the relevant lease information.

packages/jumpstarter/jumpstarter/client/lease.py (5)

35-35: LGTM - Added namespace parameter

The namespace field addition supports the updated lease service operations.


48-48: LGTM - ClientService initialization

Good initialization of the ClientService using the existing channel.


52-62: LGTM - Simplified duration handling

The code now uses timedelta directly instead of converting through Protocol Buffers, making the implementation cleaner. The lease creation has been updated to use the ClientService.


99-99: LGTM - Updated lease retrieval

Correctly updated to use the ClientService's GetLease method with the namespace parameter.


133-133: LGTM - Updated lease deletion

Correctly updated to use the ClientService's DeleteLease method with the namespace parameter.

packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (1)

9-13: Restructured imports align with the new CLI approach.
No issues found, and the changes are consistent with the refactored command structure.

packages/jumpstarter-cli-client/jumpstarter_cli_client/config.py (1)

23-28: Adoption of a new command group “config.”
The new grouped CLI approach improves maintainability and organization of related commands.

packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/client_pb2.py (1)

1-143: Auto-generated Protobuf file.
Manual edits might be overwritten. It’s recommended to exclude this file from lint checks due to typical style warnings in generated code.

🧰 Tools
🪛 Ruff (0.8.2)

25-25: Module level import not at top of file

(E402)


25-25: google.api.annotations_pb2 imported but unused

Remove unused import: google.api.annotations_pb2

(F401)


26-26: Module level import not at top of file

(E402)


26-26: google.api.client_pb2 imported but unused

Remove unused import: google.api.client_pb2

(F401)


27-27: Module level import not at top of file

(E402)


27-27: google.api.field_behavior_pb2 imported but unused

Remove unused import: google.api.field_behavior_pb2

(F401)


28-28: Module level import not at top of file

(E402)


28-28: google.api.resource_pb2 imported but unused

Remove unused import: google.api.resource_pb2

(F401)


29-29: Module level import not at top of file

(E402)


29-29: google.protobuf.duration_pb2 imported but unused

Remove unused import: google.protobuf.duration_pb2

(F401)


30-30: Module level import not at top of file

(E402)


30-30: google.protobuf.empty_pb2 imported but unused

Remove unused import: google.protobuf.empty_pb2

(F401)


31-31: Module level import not at top of file

(E402)


31-31: google.protobuf.field_mask_pb2 imported but unused

Remove unused import: google.protobuf.field_mask_pb2

(F401)


32-32: Module level import not at top of file

(E402)


32-32: google.protobuf.timestamp_pb2 imported but unused

Remove unused import: google.protobuf.timestamp_pb2

(F401)


33-33: Module level import not at top of file

(E402)


33-33: ...v1.kubernetes_pb2 imported but unused

Remove unused import: ...v1.kubernetes_pb2

(F401)


36-36: Line too long (6089 > 120)

(E501)


43-43: Line too long (265 > 120)

(E501)


49-49: Line too long (159 > 120)

(E501)


65-65: Line too long (121 > 120)

(E501)


69-69: Line too long (142 > 120)

(E501)


71-71: Line too long (130 > 120)

(E501)


73-73: Line too long (136 > 120)

(E501)


81-81: Line too long (124 > 120)

(E501)


83-83: Line too long (130 > 120)

(E501)


91-91: Line too long (131 > 120)

(E501)


101-101: Line too long (127 > 120)

(E501)


103-103: Line too long (159 > 120)

(E501)


105-105: Line too long (163 > 120)

(E501)


107-107: Line too long (154 > 120)

(E501)


109-109: Line too long (158 > 120)

(E501)


111-111: Line too long (181 > 120)

(E501)


113-113: Line too long (182 > 120)

(E501)


115-115: Line too long (154 > 120)

(E501)

packages/jumpstarter/jumpstarter/client/grpc.py (21)

4-4: Addition of timedelta import.
This is appropriate for handling lease durations in the new methods.


7-7: Expanded protobuf imports.
These are essential for the lease functionality (duration and field masking).


9-9: Import of kubernetes_pb2.
Needed for the LabelSelector type references in lease operations.


10-10: Import of client_pb2 and client_pb2_grpc.
Enables the new gRPC stubs and messages for lease management.


14-21: Refactored parse_identifier for dynamic resource type validation.
This single function consolidates logic for clients, exporters, and leases efficiently.


25-26: Dedicated function for parsing client identifiers.
A straightforward wrapper around parse_identifier for “clients.”


29-30: Dedicated function for parsing exporter identifiers.
Consistent with the approach used for client resources.


33-34: Dedicated function for parsing lease identifiers.
Further reduces duplication, ensuring the “leases” kind is enforced.


48-56: Introduction of Lease model.
Defines a Pydantic model for lease data with relevant fields. Looks correct for the new lease feature.


57-60: Custom Pydantic model configuration.
Allowing arbitrary types and float-based timedelta serialization is a valid design choice.


62-65: Serializer for selector field.
Converts LabelSelector to a dictionary, simplifying JSON output.


66-69: Serializer for conditions field.
Transforms each protobuf Condition into a dictionary for JSON consistency.


90-95: JSON and YAML dump methods for Lease.
Providing multiple export formats is beneficial. No issues found.


115-118: Introduction of LeaseList model.
Mirrors the ExporterList structure, enabling consolidated list functionality for leases.


119-124: Deserialization logic for LeaseList.
Aggregates multiple lease entries and stores the next page token as expected.


126-131: Export methods for LeaseList.
Enables easy JSON/YAML output with consistent formatting.


167-173: GetLease method in ClientService.
Fetches a single lease by name. This implementation appears correct.


175-191: ListLeases method in ClientService.
Lists leases with pagination and optional filtering. Matches the established pattern for listing.


193-213: CreateLease method in ClientService.
Constructs the creation request using durations and label selectors. Straightforward code flow.


214-237: UpdateLease method in ClientService.
Applies a field mask for partial updates, focusing on duration. Good approach.


238-243: DeleteLease method in ClientService.
Implements a direct gRPC call for lease removal. Looks clear.

packages/jumpstarter/jumpstarter/config/client.py (4)

3-3: Import looks good.
No immediate concerns regarding importing timedelta from datetime. This addition aligns with the new lease duration functionality.


150-157: No return value from delete_lease_async.
This is fine if you intend deletion to be a fire-and-forget call. Otherwise, consider returning a status or confirmation message.


197-199: Release lease method updated correctly.
Switching from a controller reference to ClientService is a consistent approach with the other methods.


218-218: Reusing the passed lease_name.
Passing lease_name to the Lease constructor aligns well with the new approach. Ensure that external code expects this naming behavior.

packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/client_pb2_grpc.py (6)

1-3: Auto-generated file header recognized.
This file is likely generated by the gRPC Python plugin. Avoid manual edits unless absolutely necessary.


5-7: Protobuf imports appear standard.
All imports for protobuf messages seem correctly referenced.


9-52: ClientServiceStub class is correctly generated.
No concerns; standard gRPC stub definitions are in place.


55-99: ClientServiceServicer is unimplemented.
Methods raise NotImplementedError, which is acceptable if the server-side functionality is not yet ready.


101-143: add_ClientServiceServicer_to_server method setup is correct.
The registration of RPC method handlers appears consistent with best practices.


145-337: ClientService static methods are standard experimental gRPC calls.
No issues. If you plan to implement them, ensure the service addresses are correct and integrated properly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/config.py (1)

16-99: Consider updating function names to match command names

While the CLI reorganization is well-implemented, there's a minor inconsistency between function names and their associated commands. For example, the create_exporter_config function is now associated with the create command. Consider renaming these functions to match their command names for better code maintainability.

- def create_exporter_config(alias, namespace, name, endpoint, token, output: PathOutputType):
+ def create(alias, namespace, name, endpoint, token, output: PathOutputType):

- def delete_exporter_config(alias, output: PathOutputType):
+ def delete(alias, output: PathOutputType):

- def edit_exporter_config(alias):
+ def edit(alias):

- def list_exporter_configs(output: OutputType):
+ def list(output: OutputType):
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3af8433 and 1b029e6.

📒 Files selected for processing (3)
  • packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/__init__.py (2 hunks)
  • packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/config.py (4 hunks)
  • packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_test.py (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: e2e
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-dev .devfile/Containerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-utils Dockerfile.utils)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
🔇 Additional comments (13)
packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_test.py (6)

15-16: Command structure update looks good

The command format has been updated to follow a more structured, hierarchical approach with config create instead of the previous flat command structure. This change is consistent with the broader CLI restructuring mentioned in the PR summary.


34-35: Consistent command structure in duplicate test case

The duplicate exporter test case correctly uses the same updated command structure, maintaining consistency throughout the test suite.


51-51: Interactive test properly updated

The interactive test correctly uses the new command structure while maintaining the same input format. This ensures that both interactive and non-interactive modes are properly tested with the new command hierarchy.


56-56: List command properly updated

The command to list exporters has been updated to use the new hierarchical structure, ensuring consistency with the other command changes.


62-62: Delete command properly updated

The command for deleting exporters has been updated to match the new command structure. The test still validates the same behavior as before.


66-66: List command consistently updated

The second list command is also properly updated, maintaining consistency across the test file.

packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/__init__.py (2)

7-7: Good module organization

Importing the config command from a dedicated module improves code organization and maintains separation of concerns. This aligns with the command restructuring approach seen in the test file.


22-22: Properly registered config command

The config command is correctly added to the exporter command group. This restructuring consolidates related commands (create, list, delete) under a common namespace, improving the CLI's organization and discoverability.

packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/config.py (5)

16-21: Good command grouping structure implementation

Adding a dedicated command group for config-related operations improves the CLI organization and creates a more intuitive hierarchical command structure. The descriptive docstring clearly communicates the purpose of this command group.


23-23: Command refactoring looks good

Changing from a standalone command to a subcommand under the 'config' group simplifies the command structure. Users will now use config create instead of create-config.


51-51: Command refactoring looks good

The delete command has been properly refactored under the config group. This change is consistent with the overall CLI reorganization pattern.


65-65: Command refactoring looks good

The edit command has been properly refactored under the config group, maintaining consistency with the other command changes.


76-76: Command refactoring looks good

The list command has been properly refactored under the config group, completing the consistent reorganization of all configuration commands.

@NickCao NickCao marked this pull request as draft March 13, 2025 17:10
@NickCao NickCao force-pushed the client-svc-lease branch 4 times, most recently from 935eae6 to 19cb070 Compare March 17, 2025 14:51
@NickCao NickCao marked this pull request as ready for review March 17, 2025 15:39
@NickCao NickCao changed the title Use Lease related methods under client service kubectl style cli Mar 17, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (13)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (2)

27-29: Enhance selector_to_labels for error handling and edge cases.

The current implementation could be more robust in handling edge cases like empty selectors, malformed selectors, or selectors without equals signs.

def selector_to_labels(selector: str):
    # TODO: support complex selectors (e.g. !=)
-    return dict([term.split("=") for term in selector.split(",")])
+    if not selector:
+        return {}
+    
+    labels = {}
+    for term in selector.split(","):
+        if not term:
+            continue
+        if "=" not in term:
+            raise ValueError(f"Invalid selector term: {term}. Expected format: key=value")
+        key, value = term.split("=", 1)  # Split on first equals sign only
+        labels[key] = value
+    return labels

48-58: Enhance DurationParamType with more descriptive error messages.

The current error message doesn't provide users with guidance on expected duration formats.

def convert(self, value, param, ctx):
    if isinstance(value, timedelta):
        return value

    try:
        return TypeAdapter(timedelta).validate_python(value)
    except ValueError:
-        self.fail(f"{value!r} is not a valid duration", param, ctx)
+        self.fail(
+            f"{value!r} is not a valid duration. "
+            f"Expected formats: '1d', '3h', '30m', '1d12h', etc.", 
+            param, 
+            ctx
+        )
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

27-42: Clarify behavior when multiple options are provided.
Currently, if both --all and name or selector are supplied, the code processes only the first condition. Consider validating these arguments or clarifying that giving more than one option is not supported.

packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (2)

15-45: Provide feedback when no exporters are found.
If exporters.exporters is empty, consider displaying a user-friendly message (e.g., "No exporters found") to inform the user rather than printing nothing or an empty table.


47-78: Provide feedback when no leases are found.
If leases.leases is empty, consider echoing a message like "No leases found" so users know the command completed successfully but returned zero resources.

packages/jumpstarter/jumpstarter/config/client.py (8)

86-89: Validate filters and confirm usage.
The list_leases method accepts a filter parameter but does not enforce or validate its usage. Consider checking for non-empty strings or clarifying whether an empty filter is allowed.


90-97: Consider input validation for lease creation.
Check for negative or zero durations or empty selectors before creating a lease. Doing so helps avoid unintended lease configurations.


98-104: Ensure name is validated for deletion.
If name is empty or invalid, the call may fail with a less descriptive error. Validating name upfront could improve user feedback.


105-107: Reinforce parameter checks for lease updates.
Similar to lease creation, ensure duration is valid (not negative) and that name meets any required constraints.


128-139: Add error handling for invalid arguments in create_lease_async.
Since selector and duration directly govern lease creation, consider additional validation or specialized error messages.


140-146: Surface lease-not-found scenarios with clearer exception handling.
A specific lease-not-found flow would help provide a better error message than a generic exception, guiding the user to correct the lease name.


168-172: Confirm correct filter usage for list_leases_async.
Unclear if a None or empty string is accepted as a valid filter. Consider clarifying or validating to avoid ambiguous server-side behavior.


173-176: Validate inputs for update_lease_async.
Similar to creation, consider verifying lease existence and ensuring duration is positive, improving reliability and user feedback.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b029e6 and ec2ca29.

📒 Files selected for processing (12)
  • .github/workflows/e2e.yaml (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (4 hunks)
💤 Files with no reviewable changes (2)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/e2e.yaml
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/init.py
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-utils Dockerfile.utils)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
🔇 Additional comments (11)
packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (2)

23-28: Implement user-friendly duration validation error handling.

The implementation uses a custom DURATION type but doesn't provide additional error handling or clear guidance on expected duration formats when validation fails.

While the DurationParamType in common.py does catch ValueError and provide a basic error message, consider adding:

  1. A more descriptive error message with examples of valid formats
  2. Documentation in the help text for the duration option
-@click.option("--duration", "duration", type=DURATION, required=True)
+@click.option("--duration", "duration", type=DURATION, required=True, 
+              help="Duration of the lease (e.g., '1d', '3h', '30m', '1d12h')")

28-49: LGTM: Well-structured command implementation.

The implementation of the update_lease command follows a consistent pattern with other CLI commands, providing appropriate output formatting options and error handling.

packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1)

32-46: LGTM: Well-designed ClientParamType parameter type.

The implementation handles different input scenarios appropriately, including conversion from existing objects, loading from configuration files, and falling back to default configurations.

packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (4)

6-6: LGTM: Clean implementation of imports from common module.

The import statement brings in the necessary decorators and utility functions from the common module, which improves code organization.


13-15: LGTM: Good use of common decorators for configuration and selector.

Replacing direct parameter handling with decorators from the common module simplifies the code and ensures consistent behavior across commands.


16-16: LGTM: Updated function signature is cleaner and more specific.

The new signature with config, selector: str, lease_name parameters is clearer and more intuitive than the previous version.


21-23: LGTM: Simplified lease acquisition with MetadataFilter.

The updated implementation simplifies lease acquisition by leveraging the common selector_to_labels function for converting the selector string to labels.

packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (3)

22-52: LGTM: Comprehensive command documentation and structure.

The command implementation provides excellent documentation including a clear description, explanation of use cases, and practical examples.


25-25: Implement user-friendly duration validation error handling.

Similar to the update command, the duration option would benefit from more descriptive help text explaining the expected formats.

-@click.option("--duration", "duration", type=DURATION, required=True)
+@click.option("--duration", "duration", type=DURATION, required=True, 
+              help="Duration of the lease (e.g., '1d', '3h', '30m', '1d12h')")

54-74: LGTM: Clean implementation with consistent output formatting.

The implementation follows the established pattern for output formatting, providing flexible options (JSON, YAML, NAME, or tabular) based on user preference.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

44-50: Non-existent lease handling duplicated comment.
This logic does not account for the case when the lease does not exist. Although exceptions will be translated by @handle_exceptions, providing a custom, user-friendly message (e.g., "Lease not found") could improve user experience.

@NickCao
Copy link
Collaborator Author

NickCao commented Mar 17, 2025

e2e side changes: jumpstarter-dev/jumpstarter-e2e#9

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (2)

44-50: Add confirmation prompt for dangerous operations

Deletion is a potentially dangerous operation, especially when using --all or selectors that might match multiple leases. Consider adding a confirmation prompt unless a --force flag is provided.

@delete.command(name="leases")
@opt_config
@click.argument("name", required=False)
@opt_selector
@click.option("--all", "all", is_flag=True)
+@click.option("--force", "force", is_flag=True, help="Skip confirmation prompt")
@opt_output_name_only
@handle_exceptions
-def delete_leases(config, name: str, selector: str | None, all: bool, output: OutputType):
+def delete_leases(config, name: str, selector: str | None, all: bool, force: bool, output: OutputType):
    # ...
    
    # Add before the deletion loop
+    if not force and len(names) > 1:
+        click.confirm(f"Are you sure you want to delete {len(names)} leases?", abort=True)
+    elif not force and len(names) == 1:
+        click.confirm(f"Are you sure you want to delete lease '{names[0]}'?", abort=True)

50-50: Use f-strings for improved readability

Consider using f-strings instead of the old-style string formatting for better readability.

-                click.echo('lease "{}" deleted'.format(name))
+                click.echo(f'lease "{name}" deleted')
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e10765a and a2bc435.

📒 Files selected for processing (17)
  • .github/workflows/e2e.yaml (1 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py (9 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py (4 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (4 hunks)
💤 Files with no reviewable changes (2)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
✅ Files skipped from review due to trivial changes (1)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py
🚧 Files skipped from review as they are similar to previous changes (12)
  • .github/workflows/e2e.yaml
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/init.py
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/init.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py
  • packages/jumpstarter/jumpstarter/config/client.py
🧰 Additional context used
🧬 Code Definitions (1)
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (3)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1) (1)
  • selector_to_labels (27:29)
packages/jumpstarter/jumpstarter/common/utils.py (1) (1)
  • launch_shell (83:104)
packages/jumpstarter/jumpstarter/config/client.py (1) (1)
  • lease (64:67)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: e2e
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-dev .devfile/Containerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-utils Dockerfile.utils)
🔇 Additional comments (6)
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (3)

6-6: Improved imports with reusable components

The addition of decorator imports from a common module demonstrates good code organization and reusability. The selector_to_labels utility function centralizes label parsing logic, which helps maintain consistency across the codebase.


12-16: Good refactoring using decorators

The refactoring to use decorators @opt_config and @opt_selector_simple improves code organization by moving the parameter handling logic outside the function body. This follows the principle of separation of concerns and makes the code more maintainable.


21-23: Improved lease creation with structured metadata filtering

The lease creation logic has been improved by using a more structured approach with MetadataFilter and the selector_to_labels function. This change makes the code more robust and easier to understand.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (3)

15-25: Good command structure with clear documentation

The command structure follows CLI best practices with a clear hierarchy and good documentation. The use of decorators for common functionality keeps the code DRY and maintainable.


29-42: Good implementation of multiple selection methods

The implementation provides three flexible ways to select leases (by name, selector, or all), with appropriate validation to ensure at least one method is specified.


44-50: Non-existent lease handling needed

The current implementation doesn't handle cases where a lease doesn't exist. This can lead to confusing error messages for users.

Consider adding specific error handling for non-existent leases. Let's check how lease deletion is implemented:

#!/bin/bash
# Check how delete_lease is implemented
rg "def delete_lease" -A 10

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

44-50: ⚠️ Potential issue

Non-existent Lease Handling Needed

Although exception handling is applied via the @handle_exceptions decorator, the deletion flow does not specifically distinguish when a lease doesn't exist. This can lead to a generic exception without a clear, user-friendly message.

Consider updating the deletion logic to verify if a lease exists before attempting deletion, or catch and handle the specific exception for non-existent leases:

 for name in names:
-    config.delete_lease(name=name)
+    try:
+        config.delete_lease(name=name)
+        match output:
+            case OutputMode.NAME:
+                click.echo(name)
+            case _:
+                click.echo('lease "{}" deleted'.format(name))
+    except Exception as e:
+        if "not found" in str(e).lower():
+            click.echo('lease "{}" not found'.format(name), err=True)
+        else:
+            raise
-    match output:
-        case OutputMode.NAME:
-            click.echo(name)
-        case _:
-            click.echo('lease "{}" deleted'.format(name))
🧹 Nitpick comments (2)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (2)

29-42: Consider improving the error message clarity

The error message uses "NAME" to refer to the positional argument, which doesn't match how a user would typically see it in help documentation or usage examples.

-        raise click.ClickException("One of NAME, --selector or --all must be specified")
+        raise click.ClickException("One of <lease_name>, --selector or --all must be specified")

36-41: Consider adding a confirmation prompt for destructive operations

When using the --all flag, multiple leases could be deleted at once without any confirmation. This could be risky, especially in production environments.

Consider adding a confirmation prompt for destructive operations, especially when using --all:

 elif all:
     leases = config.list_leases(filter=None)
+    count = 0
     for lease in leases.leases:
         if lease.client == config.metadata.name:
             names.append(lease.name)
+            count += 1
+    
+    if count > 0 and not click.confirm(f"Are you sure you want to delete {count} leases?"):
+        click.echo("Operation cancelled")
+        return
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2bc435 and cfd59ba.

📒 Files selected for processing (17)
  • .github/workflows/e2e.yaml (1 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py (9 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py (4 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (4 hunks)
💤 Files with no reviewable changes (2)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
🚧 Files skipped from review as they are similar to previous changes (13)
  • .github/workflows/e2e.yaml
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/init.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/init.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py
  • packages/jumpstarter/jumpstarter/config/client.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: e2e
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-utils Dockerfile.utils)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-dev .devfile/Containerfile)
🔇 Additional comments (6)
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (3)

6-6: Improved import organization using dedicated common module

The new import from .common brings in helper functions and decorators that standardize parameter handling across CLI commands, enhancing consistency and reducing code duplication.


12-16: Well-structured decorator pattern for parameter handling

The function now uses @opt_config and @opt_selector_simple decorators which standardize how configuration and selector parameters are handled. This approach:

  1. Reduces boilerplate code in each command implementation
  2. Ensures consistent parameter handling across commands
  3. Makes the function signature clearer

The use of decorators is a good practice for CLI applications as it centralizes common parameter processing logic.


16-27: Improved lease management with context managers

The updated implementation:

  1. Uses a cleaner context manager pattern for lease management
  2. Centralizes label handling through the selector_to_labels function
  3. Focuses on the core functionality (spawning a shell) rather than configuration handling

This refactoring aligns with the "kubectl style CLI" objective, making the code more maintainable and consistent with modern CLI patterns.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (3)

8-14: Good command group structure following CLI conventions

The command group organization with delete as the main command and subcommands for specific resources follows well-established CLI conventions (similar to kubectl, git, etc.). This structure allows for intuitive command navigation and future extensibility to delete other resource types.


15-22: Well-structured command with appropriate decorators

The command definition:

  1. Uses a consistent naming convention (leases rather than legacy lease)
  2. Leverages decorators for common parameter handling
  3. Supports multiple selection methods (by name, selector, or all)
  4. Includes output formatting options

This structure aligns well with the kubectl-style CLI pattern and promotes code reuse through decorators.


46-50: Good use of pattern matching for output formatting

The use of Python 3.10+ pattern matching for output formatting makes the code clean and easy to understand. It also provides a clear path for adding additional output modes in the future.

Note: Ensure that your project's minimum Python version requirement is documented if you're using Python 3.10+ features.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

44-46: ⚠️ Potential issue

Improve handling of non-existent leases.

The function doesn't handle the scenario where a lease doesn't exist, which was already flagged in a previous review.

Add explicit error handling for non-existent leases:

    for name in names:
-        config.delete_lease(name=name)
+        try:
+            config.delete_lease(name=name)
+        except Exception as e:
+            if "not found" in str(e).lower():
+                click.echo(f'Error: Lease "{name}" not found', err=True)
+                continue
+            raise
        match output:
🧹 Nitpick comments (5)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (2)

27-29: Implement the TODO for complex selector support.

The current implementation only supports simple equality checks. As noted in the TODO comment, supporting more complex selectors would enhance functionality.

Consider implementing support for inequality operators as mentioned in the TODO:

def selector_to_labels(selector: str):
    # TODO: support complex selectors (e.g. !=)
-    return dict([term.split("=") for term in selector.split(",")])
+    result = {}
+    for term in selector.split(","):
+        if "!=" in term:
+            key, value = term.split("!=", 1)
+            result[key] = {"operator": "!=", "value": value}
+        elif "==" in term:
+            key, value = term.split("==", 1)
+            result[key] = {"operator": "==", "value": value}
+        elif "=" in term:
+            key, value = term.split("=", 1)
+            result[key] = {"operator": "=", "value": value}
+    return result

55-58: Improve error messaging for duration validation.

The current error message for invalid duration inputs is not very helpful for users.

Enhance the error message with examples of valid formats:

        try:
            return TypeAdapter(timedelta).validate_python(value)
        except ValueError:
-            self.fail(f"{value!r} is not a valid duration", param, ctx)
+            self.fail(f"{value!r} is not a valid duration. Examples of valid formats: '1d', '2h30m', '90s'", param, ctx)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (3)

15-22: Consider aligning command name with function name.

The function name delete_leases does not match the command name "leases", which could lead to confusion in maintenance.

Either rename the function to match the command name or update the command name to match the function:

-@delete.command(name="leases")
+@delete.command(name="lease")
def delete_leases(config, name: str, selector: str | None, all: bool, output: OutputType):

or

@delete.command(name="leases")
-def delete_leases(config, name: str, selector: str | None, all: bool, output: OutputType):
+def leases(config, name: str, selector: str | None, all: bool, output: OutputType):

29-41: Consider optimizing lease filtering.

The current implementation fetches all leases and then filters them in memory, which might not be efficient for large numbers of leases.

Consider passing the filter to the backend service to reduce data transfer and processing:

    elif selector:
-        leases = config.list_leases(filter=selector)
-        for lease in leases.leases:
-            if lease.client == config.metadata.name:
-                names.append(lease.name)
+        leases = config.list_leases(filter=f"{selector},client={config.metadata.name}")
+        names.extend([lease.name for lease in leases.leases])
    elif all:
-        leases = config.list_leases(filter=None)
-        for lease in leases.leases:
-            if lease.client == config.metadata.name:
-                names.append(lease.name)
+        leases = config.list_leases(filter=f"client={config.metadata.name}")
+        names.extend([lease.name for lease in leases.leases])

46-50: Enhanced output formatting could improve UX.

The current output formatting is limited to either the name or a simple deletion message.

Consider adding more comprehensive output options, such as JSON or YAML format for programmatic consumption:

        match output:
            case OutputMode.NAME:
                click.echo(name)
+            case OutputMode.JSON:
+                click.echo(json.dumps({"name": name, "status": "deleted"}))
+            case OutputMode.YAML:
+                click.echo(yaml.dump({"name": name, "status": "deleted"}))
            case _:
                click.echo('lease "{}" deleted'.format(name))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfd59ba and d837d39.

📒 Files selected for processing (17)
  • .github/workflows/e2e.yaml (1 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py (9 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py (4 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (4 hunks)
💤 Files with no reviewable changes (2)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • .github/workflows/e2e.yaml
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/init.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/init.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • packages/jumpstarter/jumpstarter/config/client.py
🧰 Additional context used
🧬 Code Definitions (3)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1)
packages/jumpstarter/jumpstarter/config/client.py (2) (2)
  • ClientConfigV1Alpha1 (38-309)
  • load (255-260)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (2)
packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (1) (1)
  • handle_exceptions (30-44)
packages/jumpstarter/jumpstarter/config/client.py (4) (4)
  • delete (303-309)
  • list_leases (87-89)
  • lease (65-68)
  • delete_lease (99-104)
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (2)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1) (1)
  • selector_to_labels (27-29)
packages/jumpstarter/jumpstarter/config/client.py (1) (1)
  • lease (65-68)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: e2e
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-utils Dockerfile.utils)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
🔇 Additional comments (8)
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (3)

20-22: Well-structured selector class addition.

The introduction of V1Alpha1LeaseSelector with match_labels field properly aligns with Kubernetes API conventions, where selectors typically have a matchLabels property.


27-27: Appropriate type update for selector field.

Changing the selector field type from a direct dictionary to the structured V1Alpha1LeaseSelector class improves type safety and makes the code more maintainable.


75-75: Updated from_dict implementation for new selector structure.

The from_dict method has been properly updated to handle the new selector structure, ensuring backward compatibility with existing data.

packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (2)

11-16: Good option definition with clear help text.

The opt_selector option is well-defined, with clear help text explaining the supported operators and format.


18-24: Clear distinction between selector options.

Making opt_selector_simple required and limiting its operation to equality checks only is a good design choice that helps prevent user errors.

packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (2)

13-14: Effective use of decorator pattern.

Using the @opt_config and @opt_selector_simple decorators simplifies the function signature and makes the code more maintainable.


21-23: Clean implementation of selector conversion.

The use of selector_to_labels(selector) to convert the selector string into a dictionary for the metadata filter is clean and maintainable.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1)

8-13: Clear group command structure.

The delete command group is well-defined with clear docstring explaining its purpose.

Copy link
Member

@kirkbrauer kirkbrauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@NickCao NickCao enabled auto-merge March 20, 2025 14:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (1)

75-75: Add error handling for missing dictionary keys.

The current implementation assumes that dict["spec"]["selector"]["matchLabels"] will always exist, but this could raise a KeyError if any part of this path is missing. Consider adding defensive error handling.

-                selector=V1Alpha1LeaseSelector(match_labels=dict["spec"]["selector"]["matchLabels"]),
+                selector=V1Alpha1LeaseSelector(
+                    match_labels=dict["spec"].get("selector", {}).get("matchLabels", {})
+                ),
packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1)

38-48: Consider enhancing lease representation in table output.

The duration is currently displayed as total seconds, which may not be the most user-friendly format. Consider converting it to a more readable format like "1d 2h 30m" for better readability.

-                    "DURATION": str(lease.duration.total_seconds()),
+                    "DURATION": str(lease.duration),
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1)

27-29: Implement more robust selector parsing.

The current implementation has a TODO to support complex selectors. As noted, it only handles simple equality selectors and would fail on more complex expressions.

Consider implementing support for additional operators as mentioned in the TODO:

def selector_to_labels(selector: str):
    # TODO: support complex selectors (e.g. !=)
-    return dict([term.split("=") for term in selector.split(",")])
+    if not selector:
+        return {}
+    
+    result = {}
+    terms = selector.split(",")
+    for term in terms:
+        if "=" not in term:
+            continue
+        key, value = term.split("=", 1)
+        result[key] = value
+    return result
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d837d39 and fa18287.

📒 Files selected for processing (16)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py (9 hunks)
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py (2 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py (0 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py (1 hunks)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (1 hunks)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (3 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (2 hunks)
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py (4 hunks)
  • packages/jumpstarter/jumpstarter/config/client.py (4 hunks)
💤 Files with no reviewable changes (2)
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_lease.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/client_exporter.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/init.py
  • packages/jumpstarter-cli-admin/jumpstarter_cli_admin/print.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/init.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/create.py
  • packages/jumpstarter-kubernetes/jumpstarter_kubernetes/test_leases.py
  • packages/jumpstarter-cli-client/jumpstarter_cli_client/get.py
  • packages/jumpstarter/jumpstarter/config/client.py
🧰 Additional context used
🧠 Learnings (1)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1)
Learnt from: NickCao
PR: jumpstarter-dev/jumpstarter#338
File: packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py:39-43
Timestamp: 2025-03-20T13:50:36.218Z
Learning: In click/asyncclick, when a parameter is not provided (None), the conversion function is skipped entirely rather than being called with None. The `isinstance(value, bool)` check in ClientParamType is used as a workaround to handle cases where no client configuration is explicitly provided.
🧬 Code Definitions (3)
packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (2)
packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (1) (1)
  • selector_to_labels (27-29)
packages/jumpstarter/jumpstarter/config/client.py (1) (1)
  • lease (65-68)
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (1)
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/json.py (1) (1)
  • JsonBaseModel (5-14)
packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (2)
packages/jumpstarter-cli-common/jumpstarter_cli_common/exceptions.py (1) (1)
  • handle_exceptions (30-44)
packages/jumpstarter/jumpstarter/config/client.py (4) (4)
  • delete (303-309)
  • list_leases (87-89)
  • lease (65-68)
  • delete_lease (99-104)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: e2e
  • GitHub Check: pytest-matrix (3.12)
  • GitHub Check: pytest-matrix (3.11)
  • GitHub Check: pytest-matrix (3.13)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter Dockerfile)
  • GitHub Check: build-and-push-image (jumpstarter-dev/jumpstarter-devspace .devfile/Containerfile.client)
🔇 Additional comments (12)
packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py (2)

20-22: Good addition of the structured V1Alpha1LeaseSelector class.

The introduction of this class aligns with Kubernetes API conventions, where selectors typically have a matchLabels field. This provides better type safety and clearer structure than the previous dictionary approach.


27-27: LGTM on updating the selector field type.

Properly updating the field type to use the new V1Alpha1LeaseSelector class maintains type consistency throughout the codebase.

packages/jumpstarter-cli-client/jumpstarter_cli_client/update.py (2)

1-49: LGTM! Clean implementation of the update lease command.

The implementation follows the kubectl-style CLI pattern with proper command structure, argument handling, and output formatting options. The code is well-organized with clear separation between command definition and execution logic.


23-29: Duration validation is improved with error handling.

The implementation now uses the custom DURATION type which includes error handling for invalid duration formats as defined in common.py.

packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py (2)

32-46: Use of boolean check for default config is well-reasoned.

As noted in the retrieved learning, the isinstance(value, bool) check is necessary because click skips the conversion function entirely when a parameter is not provided (None).


48-59: LGTM! Good error handling in DurationParamType.

The implementation properly handles validation errors and provides clear error messages when invalid duration formats are encountered.

packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py (3)

6-6: LGTM! Clean import of common utilities.

Efficiently imports the necessary decorators and functions from the common module.


13-16: LGTM! Properly applied new command structure.

The function signature has been effectively updated to use the new command structure with @opt_config and @opt_selector_simple decorators, simplifying the implementation by encapsulating configuration and selector handling.


21-23: LGTM! Correctly uses the new selector handling.

The implementation properly uses selector_to_labels(selector) for label filtering, aligning with the new approach to selector handling.

packages/jumpstarter-cli-client/jumpstarter_cli_client/delete.py (3)

1-51: LGTM! Well-structured delete command implementation.

The implementation follows the kubectl-style CLI pattern with a clear group and subcommand structure. The code provides flexible options for specifying which leases to delete (by name, selector, or all) and handles output formatting appropriately.


27-42: LGTM! Clear and robust parameter handling.

The code correctly prioritizes different specification methods and raises a clear error message when none are provided. The logic for filtering leases by the current client is particularly valuable.


44-50: Add explicit handling for non-existent leases.

The current implementation doesn't specifically handle the case where a lease doesn't exist, which could result in generic error messages.

Consider adding explicit handling:

    for name in names:
-        config.delete_lease(name=name)
+        try:
+            config.delete_lease(name=name)
+            match output:
+                case OutputMode.NAME:
+                    click.echo(name)
+                case _:
+                    click.echo('lease "{}" deleted'.format(name))
+        except Exception as e:
+            if "not found" in str(e).lower():
+                click.echo('lease "{}" not found'.format(name), err=True)
+            else:
+                raise
-        match output:
-            case OutputMode.NAME:
-                click.echo(name)
-            case _:
-                click.echo('lease "{}" deleted'.format(name))

@NickCao NickCao merged commit c119d30 into main Mar 20, 2025
18 checks passed
@NickCao NickCao deleted the client-svc-lease branch March 20, 2025 14:26
@mangelajo mangelajo added this to the 0.6.0 milestone May 8, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 13, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants