Skip to content

feat: auto-connect jmp shell to existing leases#330

Merged
raballew merged 10 commits intojumpstarter-dev:mainfrom
raballew:006-shell-auto-lease
Mar 18, 2026
Merged

feat: auto-connect jmp shell to existing leases#330
raballew merged 10 commits intojumpstarter-dev:mainfrom
raballew:006-shell-auto-lease

Conversation

@raballew
Copy link
Copy Markdown
Member

@raballew raballew commented Mar 17, 2026

Summary

  • When running jmp shell without --selector or --name, automatically resolve from active leases
  • If exactly one active lease exists for the current client, auto-connect to it
  • If multiple active leases exist and running interactively, display a numbered picker with exporter name, selector, and expiry details
  • Only show the current user's leases, not other clients' leases
  • Clean up RST markup in shell help docstring

Closes #326

Test plan

  • Auto-connects to single active lease without prompting
  • Shows numbered picker with lease details when multiple leases exist (TTY)
  • Errors with guidance when multiple leases exist (non-TTY)
  • Filters out other clients' leases
  • Shows "no active leases found" when user has no leases (even if others do)
  • Existing --lease, --selector, --name, and JMP_LEASE env var still work
  • 10 unit tests passing

🤖 Generated with Claude Code

raballew and others added 5 commits March 17, 2026 18:31
Resolves jumpstarter-dev#326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Only show the current user's leases, not other clients' leases
- Show exporter name, selector, and expiry time for each lease
- Use numbered list with details instead of raw UUIDs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 17, 2026

Deploy Preview for jumpstarter-docs ready!

Name Link
🔨 Latest commit 2944b6f
🔍 Latest deploy log https://app.netlify.com/projects/jumpstarter-docs/deploys/69ba8cb9ec10e80008ae9ecf
😎 Deploy Preview https://deploy-preview-330--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 project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

Automatically discover and connect to active leases when jmp shell is run without a selector or lease. Adds _format_lease_display() and _resolve_lease_from_active_async(), preserves trailing space in hook-warning extraction, and tweaks shell help formatting. (≤50 words)

Changes

Cohort / File(s) Summary
Lease resolution & shell flow
python/packages/jumpstarter-cli/jumpstarter_cli/shell.py
Added _format_lease_display() and async _resolve_lease_from_active_async() to list/filter/select active leases (TTY picker or non-interactive error). Integrated auto-resolution when no selector/exporter/lease provided; preserved trailing space for HOOK_WARNING_PREFIX extraction; minor help-example formatting tweak.
Tests for lease resolution
python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py
Added Lease/LeaseList imports, test helpers (_make_lease, _make_lease_list), dummy config scaffolding, and comprehensive tests covering: no leases, single-lease auto-connect, multi-lease TTY picker and non-TTY error, client-scoped filtering, async list handling, and env-lease usage.

Sequence Diagram

sequenceDiagram
    actor User
    participant Shell
    participant LeaseAPI
    participant TTY
    participant Conn

    User->>Shell: run `jmp shell` (no selector/lease)
    Shell->>LeaseAPI: list_leases(current_client, only_active=True)
    LeaseAPI-->>Shell: LeaseList

    alt No leases
        Shell-->>User: Error + guidance (no active leases found)
    else Single lease
        Shell->>Conn: connect(lease.name)
        Conn-->>User: Connected shell session
    else Multiple leases
        Shell->>TTY: prompt(choices via _format_lease_display)
        TTY-->>Shell: selected_lease
        Shell->>Conn: connect(selected_lease)
        Conn-->>User: Connected shell session
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested reviewers

  • mangelajo

Poem

🐰 I nudge the leases, sniff one or many,
If lone I hop in, if many I tally.
Async I ponder, TTY I ask,
Pick a token or show you the task.
Hooray — shell opens with a soft little dash! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: auto-connect jmp shell to existing leases' directly and clearly summarizes the main change: automatic lease resolution without explicit parameters.
Description check ✅ Passed The description comprehensively outlines the feature, test coverage, and closes the linked issue #326, all of which relate to the changeset.
Linked Issues check ✅ Passed The code changes fully implement all requirements from issue #326: auto-connect for single lease, interactive picker for multiple leases, filtering by current client, and proper error messaging.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing auto-lease resolution: helper functions for lease formatting and resolution, comprehensive tests, and docstring cleanup—nothing extraneous.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@raballew raballew marked this pull request as ready for review March 17, 2026 18:49
Copy link
Copy Markdown
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py (1)

75-90: ⚠️ Potential issue | 🟠 Major

Test masks async bug—mock returns LeaseList directly.

The mock config.list_leases = Mock(return_value=_make_lease_list([])) returns a LeaseList synchronously, but the real list_leases is an async method. This test passes, but production code will fail because _resolve_lease_from_active doesn't await the coroutine.

Once the async issue in shell.py is fixed, update this mock to return an awaitable (e.g., AsyncMock(return_value=...)) to accurately reflect production behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py` around lines
75 - 90, The test uses a synchronous Mock for config.list_leases but the real
method is async and _resolve_lease_from_active (called via shell.callback)
should await it; update the test to use
AsyncMock(return_value=_make_lease_list([])) for config.list_leases (ensure
AsyncMock is imported) so the mock returns an awaitable that matches production
behavior and the async path exercised by shell.callback and
_resolve_lease_from_active.
🧹 Nitpick comments (1)
python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py (1)

136-151: Minor overlap with test_shell_requires_selector_or_name_when_no_leases.

This test covers the same no-leases scenario as lines 75-89 but adds the valuable assertion that list_leases was called with only_active=True. Consider consolidating or keeping both if the explicit parameter assertion is important to maintain separately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py` around lines
136 - 151, The two tests overlap on the "no active leases" scenario; choose to
either consolidate them into one test or keep both but make their different
intent explicit—if keeping both, ensure test_shell_no_leases_shows_guidance
retains the assertion that config.list_leases was called with only_active=True
(config.list_leases.assert_called_once_with(only_active=True)) and modify
test_shell_requires_selector_or_name_when_no_leases to focus solely on
selector/name validation (remove or adjust the duplicate lease-call assertion)
so each test has a single, clear responsibility (refer to
test_shell_no_leases_shows_guidance and
test_shell_requires_selector_or_name_when_no_leases).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell.py`:
- Around line 309-312: The helper _resolve_lease_from_active is calling async
method config.list_leases() synchronously; change it to an async function (async
def _resolve_lease_from_active(...)) and await config.list_leases(...) inside
it, or alternatively keep it sync but run the coroutine via
anyio.run(config.list_leases(...)) before accessing .leases; update callers
(e.g., shell() or move the logic into _shell_with_signal_handling which already
runs in an async context) so they await the new async _resolve_lease_from_active
or call it with anyio.run as appropriate.

---

Outside diff comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py`:
- Around line 75-90: The test uses a synchronous Mock for config.list_leases but
the real method is async and _resolve_lease_from_active (called via
shell.callback) should await it; update the test to use
AsyncMock(return_value=_make_lease_list([])) for config.list_leases (ensure
AsyncMock is imported) so the mock returns an awaitable that matches production
behavior and the async path exercised by shell.callback and
_resolve_lease_from_active.

---

Nitpick comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py`:
- Around line 136-151: The two tests overlap on the "no active leases" scenario;
choose to either consolidate them into one test or keep both but make their
different intent explicit—if keeping both, ensure
test_shell_no_leases_shows_guidance retains the assertion that
config.list_leases was called with only_active=True
(config.list_leases.assert_called_once_with(only_active=True)) and modify
test_shell_requires_selector_or_name_when_no_leases to focus solely on
selector/name validation (remove or adjust the duplicate lease-call assertion)
so each test has a single, clear responsibility (refer to
test_shell_no_leases_shows_guidance and
test_shell_requires_selector_or_name_when_no_leases).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a85ca56-14cf-405a-bc32-545a443c2669

📥 Commits

Reviewing files that changed from the base of the PR and between ec11dc4 and 5267861.

📒 Files selected for processing (3)
  • .gitignore
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py

Comment thread python/packages/jumpstarter-cli/jumpstarter_cli/shell.py Outdated
@mangelajo
Copy link
Copy Markdown
Member

Thanks!, tested and working:

➜  python git:(006-shell-auto-lease) ✗ jmp create lease -l target=qemu --duration 1h
NAME                                  SELECTOR     BEGIN TIME  DURATION  CLIENT    EXPORTER
019d0021-a8f6-7c37-b68e-1ba5d79380f1  target=qemu              1:00:00   majopela
➜  python git:(006-shell-auto-lease) ✗ jmp create lease -l target=qemu --duration 1h
NAME                                  SELECTOR     BEGIN TIME  DURATION  CLIENT    EXPORTER
019d0021-b333-74a6-a1d2-4f2837fcbe09  target=qemu              1:00:00   majopela

➜  python git:(006-shell-auto-lease) ✗ uv run jmp shell
Multiple active leases found:

  1) 019d0021-a8f6-7c37-b68e-1ba5d79380f1
     exporter=virtual-aarch64-4c-8g-01, selector=target=qemu, expires 2026-03-18 10:48
  2) 019d0021-b333-74a6-a1d2-4f2837fcbe09
     exporter=virtual-aarch64-4c-8g-02, selector=target=qemu, expires 2026-03-18 10:48

Select a lease [1-2]: 1
[03/18/2026 09:49:00] INFO     [jumpstarter.client.lease] Waiting for ready connection at /var/folders/j_/9v47_5750_s85_5j4tybsx200000gn/T/jumpstarter-0sswbko7/socket
[03/18/2026 09:49:03] INFO     [jumpstarter_cli.shell] Waiting for beforeLease hook to complete...
python ⚡virtual-aarch64-4c-8g-01 ➤
python ⚡virtual-aarch64-4c-8g-01 ➤
python ⚡virtual-aarch64-4c-8g-01 ➤ exit

➜  python git:(006-shell-auto-lease) ✗ uv run jmp shell
Multiple active leases found:

  1) 019d0021-a8f6-7c37-b68e-1ba5d79380f1
     exporter=virtual-aarch64-4c-8g-01, selector=target=qemu, expires 2026-03-18 10:48
  2) 019d0021-b333-74a6-a1d2-4f2837fcbe09
     exporter=virtual-aarch64-4c-8g-02, selector=target=qemu, expires 2026-03-18 10:48

Select a lease [1-2]: 2
[03/18/2026 09:49:10] INFO     [jumpstarter.client.lease] Waiting for ready connection at /var/folders/j_/9v47_5750_s85_5j4tybsx200000gn/T/jumpstarter-otesqyfn/socket

[03/18/2026 09:49:11] INFO     [jumpstarter_cli.shell] Waiting for beforeLease hook to complete...
python ⚡virtual-aarch64-4c-8g-02 ➤ exit


➜  python git:(006-shell-auto-lease) ✗ jmp delete leases 019d0021-b333-74a6-a1d2-4f2837fcbe09
lease "019d0021-b333-74a6-a1d2-4f2837fcbe09" deleted

➜  python git:(006-shell-auto-lease) ✗ jmp get leases | grep majopela
019d0021-a8f6-7c37-b68e-1ba5d79380f1  target=qemu                                                                                        2026-03-18 09:48:19  1:00:00           majopela         virtual-aarch64-4c-8g-01
➜  python git:(006-shell-auto-lease) ✗ uv run jmp shell
[03/18/2026 09:49:54] INFO     [jumpstarter.client.lease] Waiting for ready connection at /var/folders/j_/9v47_5750_s85_5j4tybsx200000gn/T/jumpstarter-vbuei97r/socket
[03/18/2026 09:49:55] INFO     [jumpstarter_cli.shell] Waiting for beforeLease hook to complete...
python ⚡virtual-aarch64-4c-8g-01 ➤ exit

@mangelajo
Copy link
Copy Markdown
Member

many queued jobs, github seems overwhelmed

Keep auto-lease test variant over upstream's pre-auto-lease validation
test, as the auto-lease behavior supersedes the old check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
python/packages/jumpstarter-cli/jumpstarter_cli/shell.py (1)

384-396: Consider using anyio.run for consistency.

The code uses asyncio.run() for _resolve_lease_from_active_async but anyio.run() for _shell_with_signal_handling. While this works (both complete before the other starts), using anyio.run consistently would align better with the codebase's async framework choice.

♻️ Optional: Use anyio.run for consistency
-                lease_name = asyncio.run(_resolve_lease_from_active_async(config))
+                lease_name = anyio.run(_resolve_lease_from_active_async, config)

Then remove the import asyncio at line 1 if no longer needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell.py` around lines 384 -
396, Replace the asyncio.run call with anyio.run for consistency: call
anyio.run(_resolve_lease_from_active_async, config) instead of asyncio.run(...)
so both asynchronous invocations use anyio; update the call site that currently
invokes asyncio.run for _resolve_lease_from_active_async and then call anyio.run
for _shell_with_signal_handling as before, and if asyncio is no longer used
anywhere in this module remove the asyncio import.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell.py`:
- Around line 384-396: Replace the asyncio.run call with anyio.run for
consistency: call anyio.run(_resolve_lease_from_active_async, config) instead of
asyncio.run(...) so both asynchronous invocations use anyio; update the call
site that currently invokes asyncio.run for _resolve_lease_from_active_async and
then call anyio.run for _shell_with_signal_handling as before, and if asyncio is
no longer used anywhere in this module remove the asyncio import.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cccb7900-74e9-4cdc-b6b5-140bfed42997

📥 Commits

Reviewing files that changed from the base of the PR and between 5267861 and cfe9d37.

📒 Files selected for processing (2)
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py

@raballew
Copy link
Copy Markdown
Member Author

@mangelajo tests seem to be flaky or is this really related to my PR?

Use anyio.run for both async invocations in the shell command,
removing the asyncio dependency from the module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@raballew raballew enabled auto-merge (squash) March 18, 2026 10:39
Copy link
Copy Markdown
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

🧹 Nitpick comments (2)
python/packages/jumpstarter-cli/jumpstarter_cli/shell.py (1)

337-343: Avoid empty () in non-TTY lease summaries.

If _format_lease_display() returns an empty string, the error text currently renders entries like lease-name (). Small polish, but it degrades UX in sparse lease records.

♻️ Proposed tweak
-    lease_summaries = [
-        f"{lease.name} ({_format_lease_display(lease)})" for lease in leases
-    ]
+    lease_summaries = []
+    for lease in leases:
+        info = _format_lease_display(lease)
+        lease_summaries.append(f"{lease.name} ({info})" if info else lease.name)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell.py` around lines 337 -
343, The lease summary list currently always appends " ({...})" even when
_format_lease_display(lease) returns an empty string, producing "lease-name ()";
change the comprehension that builds lease_summaries so it only adds the
parenthesized suffix when the formatted string is non-empty (use
_format_lease_display(lease) once, keep it in a local variable inside the
comprehension or a small helper, and construct either lease.name or
f"{lease.name} ({display})"), then leave the raise click.UsageError message
assembly unchanged.
python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py (1)

156-178: TTY picker path is not actually under test here.

Because anyio.run is mocked, this test never reaches sys.stdin.isatty(), lease listing, or click.prompt. Consider a direct _resolve_lease_from_active_async test with isatty=True and a mocked prompt selection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py` around lines
156 - 178, The test mocks anyio.run so the TTY picker path never executes;
instead directly test the async resolver _resolve_lease_from_active_async with
sys.stdin.isatty patched to return True and with the lease listing and
click.prompt patched to simulate the interactive selection; replace the current
test_shell_multi_lease_tty_picker flow by calling
_resolve_lease_from_active_async (awaiting it via anyio.run or
pytest.mark.asyncio) while patching jumpstarter_cli.shell.sys.stdin.isatty to
True, patching the lease list provider to return multiple leases, and patching
click.prompt to return the chosen lease name (e.g., "lease-b") and assert the
resolver returns that name and exits/returns expected values instead of relying
on the mocked anyio.run call path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py`:
- Around line 156-178: The test mocks anyio.run so the TTY picker path never
executes; instead directly test the async resolver
_resolve_lease_from_active_async with sys.stdin.isatty patched to return True
and with the lease listing and click.prompt patched to simulate the interactive
selection; replace the current test_shell_multi_lease_tty_picker flow by calling
_resolve_lease_from_active_async (awaiting it via anyio.run or
pytest.mark.asyncio) while patching jumpstarter_cli.shell.sys.stdin.isatty to
True, patching the lease list provider to return multiple leases, and patching
click.prompt to return the chosen lease name (e.g., "lease-b") and assert the
resolver returns that name and exits/returns expected values instead of relying
on the mocked anyio.run call path.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell.py`:
- Around line 337-343: The lease summary list currently always appends "
({...})" even when _format_lease_display(lease) returns an empty string,
producing "lease-name ()"; change the comprehension that builds lease_summaries
so it only adds the parenthesized suffix when the formatted string is non-empty
(use _format_lease_display(lease) once, keep it in a local variable inside the
comprehension or a small helper, and construct either lease.name or
f"{lease.name} ({display})"), then leave the raise click.UsageError message
assembly unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1b6373b-09c8-42c1-858a-25c76abf3720

📥 Commits

Reviewing files that changed from the base of the PR and between cfe9d37 and c900de2.

📒 Files selected for processing (2)
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py

Comment thread python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py
Avoid displaying "lease-name ()" when lease has no metadata.
Rewrite tests to exercise _resolve_lease_from_active_async directly
instead of mocking anyio.run.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py (1)

76-90: Consider consolidating the two no-lease tests.

Both tests assert the same user-facing failure path; combining them would reduce maintenance noise.

♻️ Optional consolidation sketch
-def test_shell_requires_selector_or_name_when_no_leases():
+def test_shell_requires_selector_or_name_when_no_leases():
     config = Mock(spec=ClientConfigV1Alpha1)
     config.metadata = type("Metadata", (), {"name": "test-client"})()
     config.list_leases = AsyncMock(return_value=_make_lease_list([]))
     with pytest.raises(click.UsageError, match="no active leases found"):
         shell.callback.__wrapped__.__wrapped__(
             config=config,
             command=(),
             lease_name=None,
             selector=None,
             exporter_name=None,
             duration=timedelta(minutes=1),
             exporter_logs=False,
             acquisition_timeout=None,
         )
+    config.list_leases.assert_called_once_with(only_active=True)
-
-
-def test_shell_no_leases_shows_guidance():
-    ...

Also applies to: 138-154

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py` around lines
76 - 90, Consolidate the duplicate "no active leases" tests by merging the other
test (around lines 138-154) into a single parametrized test so both input
variations assert the same UsageError; update
test_shell_requires_selector_or_name_when_no_leases (which calls
shell.callback.__wrapped__.__wrapped__) to use pytest.mark.parametrize over the
differing inputs (e.g., different combinations of
selector/lease_name/exporter_name) and remove the redundant test, ensuring the
AsyncMock for config.list_leases returns _make_lease_list([]) and the
pytest.raises(match="no active leases found") assertion remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py`:
- Around line 76-90: Consolidate the duplicate "no active leases" tests by
merging the other test (around lines 138-154) into a single parametrized test so
both input variations assert the same UsageError; update
test_shell_requires_selector_or_name_when_no_leases (which calls
shell.callback.__wrapped__.__wrapped__) to use pytest.mark.parametrize over the
differing inputs (e.g., different combinations of
selector/lease_name/exporter_name) and remove the redundant test, ensuring the
AsyncMock for config.list_leases returns _make_lease_list([]) and the
pytest.raises(match="no active leases found") assertion remains.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d667cccf-348b-46e2-b677-26ec63791020

📥 Commits

Reviewing files that changed from the base of the PR and between c900de2 and 2944b6f.

📒 Files selected for processing (2)
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell.py
  • python/packages/jumpstarter-cli/jumpstarter_cli/shell_test.py

@raballew raballew merged commit 4e55d73 into jumpstarter-dev:main Mar 18, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

jmp shell (without info) should open existing lease

2 participants