Skip to content

Commit

Permalink
Add prefect cloud open to open current workspace in browser from CLI (
Browse files Browse the repository at this point in the history
  • Loading branch information
zzstoatzz authored Jan 3, 2024
1 parent b9e3578 commit 6008849
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
30 changes: 30 additions & 0 deletions src/prefect/cli/cloud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,36 @@ async def logout():
exit_with_success("Logged out from Prefect Cloud.")


@cloud_app.command()
async def open():
"""
Open the Prefect Cloud UI in the browser.
"""
confirm_logged_in()

current_profile = prefect.context.get_settings_context().profile
if current_profile is None:
exit_with_error(
"There is no current profile set - set one with `prefect profile create"
" <name>` and `prefect profile use <name>`."
)

current_workspace = get_current_workspace(
await prefect.get_cloud_client().read_workspaces()
)
if current_workspace is None:
exit_with_error(
"There is no current workspace set - set one with `prefect cloud workspace"
" set --workspace <workspace>`."
)

ui_url = current_workspace.ui_url()

await run_sync_in_worker_thread(webbrowser.open_new_tab, ui_url)

exit_with_success(f"Opened {current_workspace.handle!r} in browser.")


@workspace_app.command()
async def ls():
"""List available workspaces."""
Expand Down
12 changes: 11 additions & 1 deletion src/prefect/client/schemas/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
raise_on_name_with_banned_characters,
)
from prefect.client.schemas.schedules import SCHEDULE_TYPES
from prefect.settings import PREFECT_CLOUD_API_URL
from prefect.settings import PREFECT_CLOUD_API_URL, PREFECT_CLOUD_UI_URL
from prefect.utilities.collections import AutoEnum, listrepr
from prefect.utilities.names import generate_slug

Expand Down Expand Up @@ -777,6 +777,16 @@ def api_url(self) -> str:
f"/workspaces/{self.workspace_id}"
)

def ui_url(self) -> str:
"""
Generate the UI URL for accessing this workspace
"""
return (
f"{PREFECT_CLOUD_UI_URL.value()}"
f"/account/{self.account_id}"
f"/workspace/{self.workspace_id}"
)

def __hash__(self):
return hash(self.handle)

Expand Down
66 changes: 66 additions & 0 deletions tests/cli/test_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -1454,3 +1454,69 @@ def test_webhook_methods_with_invalid_uuid():
["cloud", "webhook", cmd, bad_webhook_id],
expected_code=2,
)


def test_open_current_workspace_in_browser_success(mock_webbrowser, respx_mock):
foo_workspace = gen_test_workspace(account_handle="test", workspace_handle="foo")

save_profiles(
ProfilesCollection(
[
Profile(
name="logged-in-profile",
settings={
PREFECT_API_URL: foo_workspace.api_url(),
PREFECT_API_KEY: "foo",
},
)
],
active="logged-in-profile",
)
)

respx_mock.get(PREFECT_CLOUD_API_URL.value() + "/me/workspaces").mock(
return_value=httpx.Response(
status.HTTP_200_OK,
json=[foo_workspace.dict(json_compatible=True)],
)
)

with use_profile("logged-in-profile"):
invoke_and_assert(
["cloud", "open"],
expected_code=0,
expected_output_contains=f"Opened {foo_workspace.handle!r} in browser.",
)

mock_webbrowser.open_new_tab.assert_called_with(foo_workspace.ui_url())


def test_open_current_workspace_in_browser_failure_no_workspace_set(respx_mock):
save_profiles(
ProfilesCollection(
[
Profile(
name="logged-in-profile",
settings={
PREFECT_API_URL: "https://api.prefect.io",
PREFECT_API_KEY: "foo",
},
)
],
active="logged-in-profile",
)
)

respx_mock.get(PREFECT_CLOUD_API_URL.value() + "/me/workspaces").mock(
return_value=httpx.Response(
status.HTTP_200_OK,
json=[],
)
)

with use_profile("logged-in-profile"):
invoke_and_assert(
["cloud", "open"],
expected_code=1,
expected_output_contains="There is no current workspace set - set one with",
)

0 comments on commit 6008849

Please sign in to comment.