Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions src/fastapi_cloud_cli/commands/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from rich_toolkit.menu import Option
from typing_extensions import Annotated

from fastapi_cloud_cli.commands.login import login
from fastapi_cloud_cli.utils.api import APIClient
from fastapi_cloud_cli.utils.apps import AppConfig, get_app_config, write_app_config
from fastapi_cloud_cli.utils.auth import is_logged_in
Expand Down Expand Up @@ -550,10 +551,33 @@ def deploy(

with get_rich_toolkit() as toolkit:
if not is_logged_in():
logger.debug("User not logged in, showing waitlist form")
_waitlist_form(toolkit)
logger.debug("User not logged in, prompting for login or waitlist")

raise typer.Exit(1)
toolkit.print_title("Welcome to FastAPI Cloud!", tag="FastAPI")
toolkit.print_line()

toolkit.print(
"You need to be logged in to deploy to FastAPI Cloud.",
tag="info",
)
toolkit.print_line()

choice = toolkit.ask(
"What would you like to do?",
tag="auth",
options=[
Option({"name": "Login to my existing account", "value": "login"}),
Option({"name": "Join the waiting list", "value": "waitlist"}),
],
)

toolkit.print_line()

if choice == "login":
login()
else:
_waitlist_form(toolkit)
raise typer.Exit(1)

toolkit.print_title("Starting deployment", tag="FastAPI")
toolkit.print_line()
Expand Down
65 changes: 63 additions & 2 deletions tests/test_cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,63 @@ def _get_random_deployment(


@pytest.mark.respx(base_url=settings.base_api_url)
def test_shows_waitlist_form_when_not_logged_in(
def test_chooses_login_option_when_not_logged_in(
logged_out_cli: None, tmp_path: Path, respx_mock: respx.MockRouter
) -> None:
steps = [*"[email protected]", Keys.ENTER, Keys.RIGHT_ARROW, Keys.ENTER, Keys.ENTER]
steps = [Keys.ENTER]

respx_mock.post(
"/login/device/authorization", data={"client_id": settings.client_id}
).mock(
return_value=Response(
200,
json={
"verification_uri_complete": "http://test.com",
"verification_uri": "http://test.com",
"user_code": "1234",
"device_code": "5678",
},
)
)
respx_mock.post(
"/login/device/token",
data={
"device_code": "5678",
"client_id": settings.client_id,
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
},
).mock(return_value=Response(200, json={"access_token": "test_token_1234"}))

with changing_dir(tmp_path), patch(
"rich_toolkit.container.getchar"
) as mock_getchar, patch(
"fastapi_cloud_cli.commands.login.typer.launch"
) as mock_launch:
mock_getchar.side_effect = steps

result = runner.invoke(app, ["deploy"])

assert "Welcome to FastAPI Cloud!" in result.output
assert "What would you like to do?" in result.output
assert "Login to my existing account" in result.output
assert "Join the waiting list" in result.output
assert "Now you are logged in!" in result.output
assert mock_launch.called


@pytest.mark.respx(base_url=settings.base_api_url)
def test_chooses_waitlist_option_when_not_logged_in(
logged_out_cli: None, tmp_path: Path, respx_mock: respx.MockRouter
) -> None:
steps = [
Keys.DOWN_ARROW,
Keys.ENTER,
*"[email protected]",
Keys.ENTER,
Keys.RIGHT_ARROW,
Keys.ENTER,
Keys.ENTER,
]

respx_mock.post(
"/users/waiting-list",
Expand All @@ -87,6 +140,10 @@ def test_shows_waitlist_form_when_not_logged_in(
result = runner.invoke(app, ["deploy"])

assert result.exit_code == 1
assert "Welcome to FastAPI Cloud!" in result.output
assert "What would you like to do?" in result.output
assert "Login to my existing account" in result.output
assert "Join the waiting list" in result.output
assert "We're currently in private beta" in result.output
assert "Let's go! Thanks for your interest in FastAPI Cloud! 🚀" in result.output

Expand All @@ -96,6 +153,8 @@ def test_shows_waitlist_form_when_not_logged_in_longer_flow(
logged_out_cli: None, tmp_path: Path, respx_mock: respx.MockRouter
) -> None:
steps = [
Keys.DOWN_ARROW, # Select "Join the waiting list"
Keys.ENTER,
*"[email protected]",
Keys.ENTER,
Keys.ENTER,
Expand Down Expand Up @@ -767,6 +826,8 @@ def test_shows_error_for_invalid_waitlist_form_data(
logged_out_cli: None, tmp_path: Path, respx_mock: respx.MockRouter
) -> None:
steps = [
Keys.DOWN_ARROW, # Select "Join the waiting list"
Keys.ENTER,
*"[email protected]",
Keys.ENTER,
Keys.ENTER, # Choose to provide more information
Expand Down
1 change: 1 addition & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def changing_dir(directory: Union[str, Path]) -> Generator[None, None, None]:

class Keys:
RIGHT_ARROW = "\x1b[C"
DOWN_ARROW = "\x1b[B"
ENTER = "\r"
CTRL_C = "\x03"
TAB = "\t"