fastapi-cloud-cli 0.23.0__tar.gz → 0.24.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/PKG-INFO +2 -1
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/pyproject.toml +3 -2
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/__init__.py +1 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/cli.py +2 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/create.py +6 -2
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/list.py +7 -48
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/__init__.py +13 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/providers/__init__.py +11 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/providers/list.py +144 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/__init__.py +19 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/connect.py +155 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/disconnect.py +250 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/get.py +230 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/list.py +123 -0
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/commands/integrations/resources/providers.py +10 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/api.py +24 -1
- fastapi_cloud_cli-0.24.0/src/fastapi_cloud_cli/utils/teams.py +83 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/__init__.py +0 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/providers/__init__.py +0 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/providers/test_list.py +284 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/resources/__init__.py +0 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/resources/test_connect.py +221 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/resources/test_disconnect.py +363 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/resources/test_get.py +297 -0
- fastapi_cloud_cli-0.24.0/tests/integrations/resources/test_list.py +257 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_api_client.py +26 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_deploy_utils.py +12 -0
- fastapi_cloud_cli-0.23.0/src/fastapi_cloud_cli/__init__.py +0 -1
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/LICENSE +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/README.md +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/add_latest_release_date.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/format.sh +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/lint.sh +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/prepare_release.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/test-cov-html.sh +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/scripts/test.sh +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/__main__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/_flow.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/get.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/link.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/unlink.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/update.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/auth/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/auth/wait.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/ci/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/ci/print_workflow.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/archive.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/cloud.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/command.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/configure.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/upload.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deploy/wait.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/deployments.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/_shared.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/delete.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/get.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/list.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/env/set.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/login.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/logout.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/logs.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/setup_ci.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/teams/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/teams/get.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/tokens/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/tokens/create.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/tokens/delete.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/tokens/list.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/whoami.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/config.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/logging.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/py.typed +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/apps.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/auth.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/cli.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/config.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/dates.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/env.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/errors.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/execution.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/progress_file.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/sentry.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/utils/version_check.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/__init__.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/conftest.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_archive.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_auth.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_apps.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_ci.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_deploy.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_deployments.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_link.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_login.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_logout.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_setup_ci.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_teams.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_tokens.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_unlink.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_cli_whoami.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_config.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_dates.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_env_delete.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_env_get.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_env_list.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_env_set.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_logs.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_prepare_release.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_progress_file.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_sentry.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_utils_apps.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/test_version_check.py +0 -0
- {fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi-cloud-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
4
4
|
Summary: Deploy and manage FastAPI Cloud apps from the command line 🚀
|
|
5
5
|
Author-Email: Patrick Arminio <patrick@fastapilabs.com>
|
|
6
6
|
License: MIT
|
|
@@ -40,6 +40,7 @@ Requires-Dist: pydantic[email]>=2.12.0; python_version >= "3.14"
|
|
|
40
40
|
Requires-Dist: sentry-sdk>=2.20.0
|
|
41
41
|
Requires-Dist: fastar>=0.10.0
|
|
42
42
|
Requires-Dist: detect-installer>=0.1.0
|
|
43
|
+
Requires-Dist: agent-detector>=1.1.0
|
|
43
44
|
Provides-Extra: standard
|
|
44
45
|
Requires-Dist: uvicorn[standard]>=0.15.0; extra == "standard"
|
|
45
46
|
Description-Content-Type: text/markdown
|
|
@@ -40,8 +40,9 @@ dependencies = [
|
|
|
40
40
|
"sentry-sdk >= 2.20.0",
|
|
41
41
|
"fastar >= 0.10.0",
|
|
42
42
|
"detect-installer>=0.1.0",
|
|
43
|
+
"agent-detector>=1.1.0",
|
|
43
44
|
]
|
|
44
|
-
version = "0.
|
|
45
|
+
version = "0.24.0"
|
|
45
46
|
|
|
46
47
|
[project.license]
|
|
47
48
|
text = "MIT"
|
|
@@ -63,7 +64,7 @@ dev = [
|
|
|
63
64
|
"prek>=0.2.24,<1.0.0",
|
|
64
65
|
"pytest>=7.0.0,<10.0.0",
|
|
65
66
|
"coverage[toml]>=7.2,<8.0",
|
|
66
|
-
"mypy==2.
|
|
67
|
+
"mypy==2.3.0",
|
|
67
68
|
"ruff>=0.15.16",
|
|
68
69
|
"respx==0.23.1",
|
|
69
70
|
"time-machine>=2.19.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.24.0"
|
|
@@ -12,6 +12,7 @@ from .commands.ci import ci_app
|
|
|
12
12
|
from .commands.deploy import deploy
|
|
13
13
|
from .commands.deployments import deployments_app
|
|
14
14
|
from .commands.env import env_app
|
|
15
|
+
from .commands.integrations import integrations_app
|
|
15
16
|
from .commands.login import login
|
|
16
17
|
from .commands.logout import logout
|
|
17
18
|
from .commands.logs import logs
|
|
@@ -73,6 +74,7 @@ cloud_app.add_typer(auth_app, name="auth")
|
|
|
73
74
|
cloud_app.add_typer(apps_app, name="apps")
|
|
74
75
|
cloud_app.add_typer(ci_app, name="ci")
|
|
75
76
|
cloud_app.add_typer(deployments_app, name="deployments")
|
|
77
|
+
cloud_app.add_typer(integrations_app, name="integrations")
|
|
76
78
|
cloud_app.add_typer(teams_app, name="teams")
|
|
77
79
|
cloud_app.add_typer(tokens_app, name="tokens")
|
|
78
80
|
|
{fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/create.py
RENAMED
|
@@ -6,7 +6,6 @@ import typer
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
from rich_toolkit import RichToolkit
|
|
8
8
|
|
|
9
|
-
from fastapi_cloud_cli.commands.apps.list import _prompt_for_team
|
|
10
9
|
from fastapi_cloud_cli.commands.deploy.archive import (
|
|
11
10
|
_get_app_name,
|
|
12
11
|
validate_app_directory,
|
|
@@ -16,6 +15,7 @@ from fastapi_cloud_cli.utils.apps import AppConfig, write_app_config
|
|
|
16
15
|
from fastapi_cloud_cli.utils.auth import Identity
|
|
17
16
|
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
18
17
|
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
18
|
+
from fastapi_cloud_cli.utils.teams import select_team
|
|
19
19
|
|
|
20
20
|
logger = logging.getLogger(__name__)
|
|
21
21
|
|
|
@@ -130,7 +130,11 @@ def create_app(
|
|
|
130
130
|
hint="Pass --team-id to choose a team.",
|
|
131
131
|
)
|
|
132
132
|
|
|
133
|
-
team =
|
|
133
|
+
team = select_team(
|
|
134
|
+
toolkit,
|
|
135
|
+
client,
|
|
136
|
+
empty_hint="Create a team before listing apps.",
|
|
137
|
+
)
|
|
134
138
|
team_id = team.id
|
|
135
139
|
toolkit.print_line()
|
|
136
140
|
|
{fastapi_cloud_cli-0.23.0 → fastapi_cloud_cli-0.24.0}/src/fastapi_cloud_cli/commands/apps/list.py
RENAMED
|
@@ -6,13 +6,13 @@ from pydantic import BaseModel, Field
|
|
|
6
6
|
from rich.table import Table
|
|
7
7
|
from rich.text import Text
|
|
8
8
|
from rich_toolkit import RichToolkit
|
|
9
|
-
from rich_toolkit.menu import Option
|
|
10
9
|
|
|
11
10
|
from fastapi_cloud_cli.config import Settings
|
|
12
11
|
from fastapi_cloud_cli.utils.api import APIClient
|
|
13
12
|
from fastapi_cloud_cli.utils.auth import Identity
|
|
14
|
-
from fastapi_cloud_cli.utils.cli import
|
|
13
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
15
14
|
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
15
|
+
from fastapi_cloud_cli.utils.teams import Team, select_team
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
@@ -31,12 +31,6 @@ class App(BaseModel):
|
|
|
31
31
|
updated_at: str | None = None
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
class Team(BaseModel):
|
|
35
|
-
id: str
|
|
36
|
-
slug: str
|
|
37
|
-
name: str
|
|
38
|
-
|
|
39
|
-
|
|
40
34
|
class AppsListAPIResponse(BaseModel):
|
|
41
35
|
data: list[App]
|
|
42
36
|
count: int
|
|
@@ -84,15 +78,6 @@ def _get_apps_list_table(
|
|
|
84
78
|
return table
|
|
85
79
|
|
|
86
80
|
|
|
87
|
-
def _get_teams(client: APIClient) -> list[Team]:
|
|
88
|
-
response = client.get("/teams/")
|
|
89
|
-
response.raise_for_status()
|
|
90
|
-
|
|
91
|
-
data = response.json()["data"]
|
|
92
|
-
|
|
93
|
-
return [Team.model_validate(team) for team in data]
|
|
94
|
-
|
|
95
|
-
|
|
96
81
|
def _get_team(client: APIClient, team_id: str) -> Team:
|
|
97
82
|
response = client.get(f"/teams/{team_id}")
|
|
98
83
|
response.raise_for_status()
|
|
@@ -149,36 +134,6 @@ def _render_apps_list_output(data: AppsListOutput, toolkit: RichToolkit) -> None
|
|
|
149
134
|
)
|
|
150
135
|
|
|
151
136
|
|
|
152
|
-
def _prompt_for_team(toolkit: FastAPIRichToolkit, client: APIClient) -> Team:
|
|
153
|
-
with toolkit.progress(
|
|
154
|
-
title="Fetching teams",
|
|
155
|
-
transient=True,
|
|
156
|
-
) as progress:
|
|
157
|
-
with client.handle_http_errors(
|
|
158
|
-
progress,
|
|
159
|
-
default_message="Error fetching teams. Please try again later.",
|
|
160
|
-
toolkit=toolkit,
|
|
161
|
-
):
|
|
162
|
-
teams = _get_teams(client)
|
|
163
|
-
|
|
164
|
-
if not teams:
|
|
165
|
-
toolkit.fail(
|
|
166
|
-
"missing_required_input",
|
|
167
|
-
"No teams found.",
|
|
168
|
-
hint="Create a team before listing apps.",
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
return toolkit.ask(
|
|
172
|
-
"Select the team:",
|
|
173
|
-
options=[
|
|
174
|
-
Option({"name": team.name, "value": team})
|
|
175
|
-
for team in sorted(teams, key=lambda team: team.name.lower())
|
|
176
|
-
],
|
|
177
|
-
allow_filtering=True,
|
|
178
|
-
bullet=False,
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
|
|
182
137
|
def list_apps(
|
|
183
138
|
team_id: Annotated[
|
|
184
139
|
str | None,
|
|
@@ -229,7 +184,11 @@ def list_apps(
|
|
|
229
184
|
hint="Pass --team-id to choose a team.",
|
|
230
185
|
)
|
|
231
186
|
|
|
232
|
-
team =
|
|
187
|
+
team = select_team(
|
|
188
|
+
toolkit,
|
|
189
|
+
client,
|
|
190
|
+
empty_hint="Create a team before listing apps.",
|
|
191
|
+
)
|
|
233
192
|
team_id = team.id
|
|
234
193
|
team_slug = team.slug
|
|
235
194
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from fastapi_cloud_cli.commands.integrations.providers import providers_app
|
|
4
|
+
from fastapi_cloud_cli.commands.integrations.resources import resources_app
|
|
5
|
+
|
|
6
|
+
integrations_app = typer.Typer(
|
|
7
|
+
no_args_is_help=True,
|
|
8
|
+
help="Manage third-party integrations.",
|
|
9
|
+
)
|
|
10
|
+
integrations_app.add_typer(providers_app, name="providers")
|
|
11
|
+
integrations_app.add_typer(resources_app, name="resources")
|
|
12
|
+
|
|
13
|
+
__all__ = ["integrations_app"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from fastapi_cloud_cli.commands.integrations.providers.list import list_providers
|
|
4
|
+
|
|
5
|
+
providers_app = typer.Typer(
|
|
6
|
+
no_args_is_help=True,
|
|
7
|
+
help="Manage integration providers for a team.",
|
|
8
|
+
)
|
|
9
|
+
providers_app.command("list")(list_providers)
|
|
10
|
+
|
|
11
|
+
__all__ = ["providers_app"]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from typing import Annotated, Any, Literal
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from rich.table import Table
|
|
6
|
+
from rich.text import Text
|
|
7
|
+
from rich_toolkit import RichToolkit
|
|
8
|
+
|
|
9
|
+
from fastapi_cloud_cli.utils.api import APIClient
|
|
10
|
+
from fastapi_cloud_cli.utils.auth import Identity
|
|
11
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
12
|
+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
13
|
+
from fastapi_cloud_cli.utils.teams import resolve_team_id
|
|
14
|
+
|
|
15
|
+
ProviderStatus = Literal["available", "coming_soon", "connected"]
|
|
16
|
+
|
|
17
|
+
STATUS_LABELS: dict[ProviderStatus, str] = {
|
|
18
|
+
"available": "not connected",
|
|
19
|
+
"coming_soon": "coming soon",
|
|
20
|
+
"connected": "connected",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ConnectedIntegration(BaseModel):
|
|
25
|
+
id: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class IntegrationProvider(BaseModel):
|
|
29
|
+
id: str
|
|
30
|
+
name: str
|
|
31
|
+
status: ProviderStatus
|
|
32
|
+
connected_integration: ConnectedIntegration | None = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ProvidersListAPIResponse(BaseModel):
|
|
36
|
+
data: list[IntegrationProvider]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProvidersListOutput(BaseModel):
|
|
40
|
+
team_id: str
|
|
41
|
+
providers: list[IntegrationProvider]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_providers(client: APIClient, *, team_id: str) -> list[IntegrationProvider]:
|
|
45
|
+
response = client.get(f"/teams/{team_id}/integrations")
|
|
46
|
+
response.raise_for_status()
|
|
47
|
+
|
|
48
|
+
return ProvidersListAPIResponse.model_validate(response.json()).data
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _get_providers_table(providers: list[IntegrationProvider]) -> Table:
|
|
52
|
+
table = Table.grid(padding=(0, 2), pad_edge=False)
|
|
53
|
+
table.add_column("Name", no_wrap=True)
|
|
54
|
+
table.add_column("Status", no_wrap=True)
|
|
55
|
+
table.add_column("Integration ID", no_wrap=True, overflow="ignore")
|
|
56
|
+
table.add_row(
|
|
57
|
+
Text("Name", style="bold"),
|
|
58
|
+
Text("Status", style="bold"),
|
|
59
|
+
Text("Integration ID", style="bold"),
|
|
60
|
+
)
|
|
61
|
+
table.add_row("", "", "")
|
|
62
|
+
|
|
63
|
+
for provider in providers:
|
|
64
|
+
connected_integration = provider.connected_integration
|
|
65
|
+
table.add_row(
|
|
66
|
+
Text(provider.name),
|
|
67
|
+
Text(
|
|
68
|
+
STATUS_LABELS[provider.status],
|
|
69
|
+
style="green" if provider.status == "connected" else "dim",
|
|
70
|
+
),
|
|
71
|
+
Text(connected_integration.id if connected_integration else "-"),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return table
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _render_providers_list_output(
|
|
78
|
+
data: ProvidersListOutput,
|
|
79
|
+
toolkit: RichToolkit,
|
|
80
|
+
) -> None:
|
|
81
|
+
toolkit.print_title("integrations")
|
|
82
|
+
toolkit.print_line()
|
|
83
|
+
|
|
84
|
+
if not data.providers:
|
|
85
|
+
toolkit.print("No integration providers available.", bullet=False)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
toolkit.print(_get_providers_table(data.providers), bullet=False)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def list_providers(
|
|
92
|
+
team_id: Annotated[
|
|
93
|
+
str | None,
|
|
94
|
+
typer.Option(
|
|
95
|
+
"--team-id",
|
|
96
|
+
help=(
|
|
97
|
+
"ID of the team whose integration providers should be listed. "
|
|
98
|
+
"Defaults to the linked app's team."
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
] = None,
|
|
102
|
+
json_output: JsonOutputOption = False,
|
|
103
|
+
) -> Any:
|
|
104
|
+
"""
|
|
105
|
+
List integration providers and their connection status for a team.
|
|
106
|
+
"""
|
|
107
|
+
identity = Identity()
|
|
108
|
+
|
|
109
|
+
with get_rich_toolkit(json_output=json_output) as toolkit:
|
|
110
|
+
if not identity.is_logged_in():
|
|
111
|
+
toolkit.fail(
|
|
112
|
+
"not_logged_in",
|
|
113
|
+
"No credentials found.",
|
|
114
|
+
hint="Run `fastapi cloud login` or set FASTAPI_CLOUD_TOKEN.",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
with APIClient() as client:
|
|
118
|
+
team_id = resolve_team_id(
|
|
119
|
+
toolkit,
|
|
120
|
+
client,
|
|
121
|
+
team_id=team_id,
|
|
122
|
+
empty_hint="Create a team before listing integration providers.",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
with (
|
|
126
|
+
toolkit.progress(
|
|
127
|
+
title="Fetching integration providers",
|
|
128
|
+
transient=True,
|
|
129
|
+
) as progress,
|
|
130
|
+
client.handle_http_errors(
|
|
131
|
+
progress,
|
|
132
|
+
default_message=(
|
|
133
|
+
"Error fetching integration providers. Please try again later."
|
|
134
|
+
),
|
|
135
|
+
not_found_message="Team not found.",
|
|
136
|
+
toolkit=toolkit,
|
|
137
|
+
),
|
|
138
|
+
):
|
|
139
|
+
providers = _get_providers(client, team_id=team_id)
|
|
140
|
+
|
|
141
|
+
toolkit.success(
|
|
142
|
+
ProvidersListOutput(team_id=team_id, providers=providers),
|
|
143
|
+
render_output=_render_providers_list_output,
|
|
144
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from fastapi_cloud_cli.commands.integrations.resources.connect import connect_resource
|
|
4
|
+
from fastapi_cloud_cli.commands.integrations.resources.disconnect import (
|
|
5
|
+
disconnect_resource,
|
|
6
|
+
)
|
|
7
|
+
from fastapi_cloud_cli.commands.integrations.resources.get import get_resource
|
|
8
|
+
from fastapi_cloud_cli.commands.integrations.resources.list import list_resources
|
|
9
|
+
|
|
10
|
+
resources_app = typer.Typer(
|
|
11
|
+
no_args_is_help=True,
|
|
12
|
+
help="Manage resources connected to an app.",
|
|
13
|
+
)
|
|
14
|
+
resources_app.command("connect")(connect_resource)
|
|
15
|
+
resources_app.command("disconnect")(disconnect_resource)
|
|
16
|
+
resources_app.command("get")(get_resource)
|
|
17
|
+
resources_app.command("list")(list_resources)
|
|
18
|
+
|
|
19
|
+
__all__ = ["resources_app"]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Annotated, Any
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
from rich.text import Text
|
|
7
|
+
from rich_toolkit import RichToolkit
|
|
8
|
+
|
|
9
|
+
from fastapi_cloud_cli.commands.apps.list import (
|
|
10
|
+
App,
|
|
11
|
+
_get_app,
|
|
12
|
+
_get_app_dashboard_url,
|
|
13
|
+
_get_team,
|
|
14
|
+
)
|
|
15
|
+
from fastapi_cloud_cli.config import Settings
|
|
16
|
+
from fastapi_cloud_cli.utils.api import APIClient
|
|
17
|
+
from fastapi_cloud_cli.utils.apps import resolve_app_id_or_fail
|
|
18
|
+
from fastapi_cloud_cli.utils.auth import Identity
|
|
19
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
20
|
+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ResourceConnectOutput(BaseModel):
|
|
26
|
+
app_id: str
|
|
27
|
+
connect_url: str
|
|
28
|
+
app_name: Annotated[str, Field(exclude=True)]
|
|
29
|
+
browser_opened: Annotated[bool, Field(exclude=True)]
|
|
30
|
+
app_id_was_provided: Annotated[bool, Field(exclude=True)]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_resource_connect_url(
|
|
34
|
+
app: App,
|
|
35
|
+
*,
|
|
36
|
+
team_slug: str,
|
|
37
|
+
settings: Settings,
|
|
38
|
+
) -> str:
|
|
39
|
+
app_dashboard_url = _get_app_dashboard_url(
|
|
40
|
+
app,
|
|
41
|
+
team_slug=team_slug,
|
|
42
|
+
settings=settings,
|
|
43
|
+
)
|
|
44
|
+
return f"{app_dashboard_url}/integrations/connect"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _render_resource_connect_output(
|
|
48
|
+
data: ResourceConnectOutput,
|
|
49
|
+
toolkit: RichToolkit,
|
|
50
|
+
) -> None:
|
|
51
|
+
toolkit.print_title("connect resource")
|
|
52
|
+
toolkit.print_line()
|
|
53
|
+
|
|
54
|
+
if data.browser_opened:
|
|
55
|
+
toolkit.print(
|
|
56
|
+
f"Opened the integration setup for [bold]{data.app_name}[/bold] in your browser.",
|
|
57
|
+
emoji="🔌",
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
toolkit.print(
|
|
61
|
+
f"Open the integration setup for [bold]{data.app_name}[/bold] in your browser:",
|
|
62
|
+
emoji="🔌",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
toolkit.print(Text(data.connect_url, style=f"link {data.connect_url}"))
|
|
66
|
+
toolkit.print_line()
|
|
67
|
+
|
|
68
|
+
list_command = "fastapi cloud integrations resources list"
|
|
69
|
+
if data.app_id_was_provided:
|
|
70
|
+
list_command = f"{list_command} --app-id {data.app_id}"
|
|
71
|
+
|
|
72
|
+
toolkit.print(
|
|
73
|
+
f"When the connection is complete, run [bold]{list_command}[/bold] to view it.",
|
|
74
|
+
emoji="💡",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def connect_resource(
|
|
79
|
+
app_id: Annotated[
|
|
80
|
+
str | None,
|
|
81
|
+
typer.Option(
|
|
82
|
+
"--app-id",
|
|
83
|
+
help="ID of the app to connect a provider resource to.",
|
|
84
|
+
),
|
|
85
|
+
] = None,
|
|
86
|
+
no_open: Annotated[
|
|
87
|
+
bool,
|
|
88
|
+
typer.Option(
|
|
89
|
+
"--no-open",
|
|
90
|
+
help="Do not open the browser automatically.",
|
|
91
|
+
),
|
|
92
|
+
] = False,
|
|
93
|
+
json_output: JsonOutputOption = False,
|
|
94
|
+
) -> Any:
|
|
95
|
+
"""
|
|
96
|
+
Open FastAPI Cloud to connect a provider resource to an app.
|
|
97
|
+
"""
|
|
98
|
+
identity = Identity()
|
|
99
|
+
|
|
100
|
+
with get_rich_toolkit(json_output=json_output) as toolkit:
|
|
101
|
+
if not identity.is_logged_in():
|
|
102
|
+
toolkit.fail(
|
|
103
|
+
"not_logged_in",
|
|
104
|
+
"No credentials found.",
|
|
105
|
+
hint="Run `fastapi cloud login` or set FASTAPI_CLOUD_TOKEN.",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
app_id_was_provided = app_id is not None
|
|
109
|
+
app_id = resolve_app_id_or_fail(toolkit, app_id=app_id)
|
|
110
|
+
|
|
111
|
+
with APIClient() as client:
|
|
112
|
+
with (
|
|
113
|
+
toolkit.progress(title="Fetching app", transient=True) as progress,
|
|
114
|
+
client.handle_http_errors(
|
|
115
|
+
progress,
|
|
116
|
+
default_message="Error fetching app. Please try again later.",
|
|
117
|
+
not_found_message="App not found.",
|
|
118
|
+
toolkit=toolkit,
|
|
119
|
+
),
|
|
120
|
+
):
|
|
121
|
+
app = _get_app(client, app_id)
|
|
122
|
+
|
|
123
|
+
with (
|
|
124
|
+
toolkit.progress(title="Fetching team", transient=True) as progress,
|
|
125
|
+
client.handle_http_errors(
|
|
126
|
+
progress,
|
|
127
|
+
default_message="Error fetching team. Please try again later.",
|
|
128
|
+
not_found_message="Team not found.",
|
|
129
|
+
toolkit=toolkit,
|
|
130
|
+
),
|
|
131
|
+
):
|
|
132
|
+
team = _get_team(client, app.team_id)
|
|
133
|
+
|
|
134
|
+
connect_url = _get_resource_connect_url(
|
|
135
|
+
app,
|
|
136
|
+
team_slug=team.slug,
|
|
137
|
+
settings=Settings.get(),
|
|
138
|
+
)
|
|
139
|
+
browser_opened = False
|
|
140
|
+
|
|
141
|
+
if not json_output and not no_open:
|
|
142
|
+
launch_result = typer.launch(connect_url)
|
|
143
|
+
logger.debug("Launch command result: %s", launch_result)
|
|
144
|
+
browser_opened = launch_result == 0
|
|
145
|
+
|
|
146
|
+
toolkit.success(
|
|
147
|
+
ResourceConnectOutput(
|
|
148
|
+
app_id=app.id,
|
|
149
|
+
app_name=app.name,
|
|
150
|
+
connect_url=connect_url,
|
|
151
|
+
browser_opened=browser_opened,
|
|
152
|
+
app_id_was_provided=app_id_was_provided,
|
|
153
|
+
),
|
|
154
|
+
render_output=_render_resource_connect_output,
|
|
155
|
+
)
|