fastapi-cloud-cli 0.20.0__tar.gz → 0.22.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.20.0 → fastapi_cloud_cli-0.22.0}/PKG-INFO +1 -4
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/README.md +0 -3
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/pyproject.toml +8 -4
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/__init__.py +1 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/cli.py +4 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/__init__.py +2 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/create.py +15 -2
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/apps/update.py +122 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/ci/__init__.py +15 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/ci/print_workflow.py +45 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/command.py +1 -1
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/upload.py +4 -1
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/wait.py +2 -5
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deployments.py +3 -6
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/logout.py +30 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/logs.py +10 -1
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/setup_ci.py +536 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/tokens/__init__.py +15 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/tokens/create.py +182 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/tokens/delete.py +102 -0
- fastapi_cloud_cli-0.22.0/src/fastapi_cloud_cli/commands/tokens/list.py +115 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/api.py +21 -8
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/cli.py +4 -1
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/errors.py +1 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_api_client.py +15 -22
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli.py +58 -1
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_apps.py +165 -0
- fastapi_cloud_cli-0.22.0/tests/test_cli_ci.py +297 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_deploy.py +126 -66
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_deployments.py +5 -5
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_logout.py +23 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_setup_ci.py +177 -17
- fastapi_cloud_cli-0.22.0/tests/test_cli_tokens.py +702 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_logs.py +38 -0
- fastapi_cloud_cli-0.20.0/src/fastapi_cloud_cli/__init__.py +0 -1
- fastapi_cloud_cli-0.20.0/src/fastapi_cloud_cli/commands/logout.py +0 -15
- fastapi_cloud_cli-0.20.0/src/fastapi_cloud_cli/commands/setup_ci.py +0 -366
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/LICENSE +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/add_latest_release_date.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/format.sh +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/lint.sh +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/prepare_release.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/test-cov-html.sh +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/scripts/test.sh +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/__main__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/_flow.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/get.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/link.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/list.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/unlink.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/auth/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/auth/wait.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/archive.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/cloud.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/configure.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/_shared.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/delete.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/get.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/list.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/env/set.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/login.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/teams/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/teams/get.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/whoami.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/config.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/logging.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/py.typed +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/apps.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/auth.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/config.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/dates.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/env.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/execution.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/progress_file.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/sentry.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/utils/version_check.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/__init__.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/conftest.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_archive.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_auth.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_link.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_login.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_teams.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_unlink.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_cli_whoami.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_config.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_dates.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_deploy_utils.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_env_delete.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_env_get.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_env_list.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_env_set.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_prepare_release.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_progress_file.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_sentry.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_utils_apps.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/tests/test_version_check.py +0 -0
- {fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.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.22.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
|
|
@@ -49,9 +49,6 @@ Description-Content-Type: text/markdown
|
|
|
49
49
|
<a href="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/test.yml" target="_blank">
|
|
50
50
|
<img src="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/test.yml/badge.svg" alt="Test">
|
|
51
51
|
</a>
|
|
52
|
-
<a href="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/publish.yml" target="_blank">
|
|
53
|
-
<img src="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/publish.yml/badge.svg" alt="Publish">
|
|
54
|
-
</a>
|
|
55
52
|
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapilabs/fastapi-cloud-cli" target="_blank">
|
|
56
53
|
<img src="https://coverage-badge.samuelcolvin.workers.dev/fastapilabs/fastapi-cloud-cli.svg" alt="Coverage">
|
|
57
54
|
<a href="https://pypi.org/project/fastapi-cloud-cli" target="_blank">
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
<a href="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/test.yml" target="_blank">
|
|
4
4
|
<img src="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/test.yml/badge.svg" alt="Test">
|
|
5
5
|
</a>
|
|
6
|
-
<a href="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/publish.yml" target="_blank">
|
|
7
|
-
<img src="https://github.com/fastapilabs/fastapi-cloud-cli/actions/workflows/publish.yml/badge.svg" alt="Publish">
|
|
8
|
-
</a>
|
|
9
6
|
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapilabs/fastapi-cloud-cli" target="_blank">
|
|
10
7
|
<img src="https://coverage-badge.samuelcolvin.workers.dev/fastapilabs/fastapi-cloud-cli.svg" alt="Coverage">
|
|
11
8
|
<a href="https://pypi.org/project/fastapi-cloud-cli" target="_blank">
|
|
@@ -41,7 +41,7 @@ dependencies = [
|
|
|
41
41
|
"fastar >= 0.10.0",
|
|
42
42
|
"detect-installer>=0.1.0",
|
|
43
43
|
]
|
|
44
|
-
version = "0.
|
|
44
|
+
version = "0.22.0"
|
|
45
45
|
|
|
46
46
|
[project.license]
|
|
47
47
|
text = "MIT"
|
|
@@ -64,9 +64,9 @@ dev = [
|
|
|
64
64
|
"pytest>=7.0.0,<10.0.0",
|
|
65
65
|
"coverage[toml]>=7.2,<8.0",
|
|
66
66
|
"mypy==2.1.0",
|
|
67
|
-
"ruff
|
|
67
|
+
"ruff>=0.15.16",
|
|
68
68
|
"respx==0.23.1",
|
|
69
|
-
"time-machine
|
|
69
|
+
"time-machine>=2.19.0",
|
|
70
70
|
"ty>=0.0.25",
|
|
71
71
|
"zizmor>=1.24.1",
|
|
72
72
|
]
|
|
@@ -170,11 +170,15 @@ keep-runtime-typing = true
|
|
|
170
170
|
|
|
171
171
|
[tool.typos.files]
|
|
172
172
|
extend-exclude = [
|
|
173
|
-
"release-notes.md",
|
|
174
173
|
"uv.lock",
|
|
175
174
|
"coverage/",
|
|
176
175
|
"htmlcov/",
|
|
177
176
|
]
|
|
178
177
|
|
|
178
|
+
[tool.typos.default]
|
|
179
|
+
extend-ignore-re = [
|
|
180
|
+
"@[a-zA-Z0-9](?:-?[a-zA-Z0-9])*",
|
|
181
|
+
]
|
|
182
|
+
|
|
179
183
|
[tool.typos.default.extend-identifiers]
|
|
180
184
|
alls = "alls"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.22.0"
|
|
@@ -8,6 +8,7 @@ from .commands.apps import apps_app
|
|
|
8
8
|
from .commands.apps.link import link_app
|
|
9
9
|
from .commands.apps.unlink import unlink_app
|
|
10
10
|
from .commands.auth import auth_app
|
|
11
|
+
from .commands.ci import ci_app
|
|
11
12
|
from .commands.deploy import deploy
|
|
12
13
|
from .commands.deployments import deployments_app
|
|
13
14
|
from .commands.env import env_app
|
|
@@ -16,6 +17,7 @@ from .commands.logout import logout
|
|
|
16
17
|
from .commands.logs import logs
|
|
17
18
|
from .commands.setup_ci import setup_ci
|
|
18
19
|
from .commands.teams import teams_app
|
|
20
|
+
from .commands.tokens import tokens_app
|
|
19
21
|
from .commands.whoami import whoami
|
|
20
22
|
from .logging import setup_logging
|
|
21
23
|
from .utils.sentry import init_sentry
|
|
@@ -69,8 +71,10 @@ cloud_app.command()(setup_ci)
|
|
|
69
71
|
cloud_app.add_typer(env_app, name="env")
|
|
70
72
|
cloud_app.add_typer(auth_app, name="auth")
|
|
71
73
|
cloud_app.add_typer(apps_app, name="apps")
|
|
74
|
+
cloud_app.add_typer(ci_app, name="ci")
|
|
72
75
|
cloud_app.add_typer(deployments_app, name="deployments")
|
|
73
76
|
cloud_app.add_typer(teams_app, name="teams")
|
|
77
|
+
cloud_app.add_typer(tokens_app, name="tokens")
|
|
74
78
|
|
|
75
79
|
# fastapi [command]
|
|
76
80
|
app.command()(deploy)
|
|
@@ -5,6 +5,7 @@ from fastapi_cloud_cli.commands.apps.get import get_app
|
|
|
5
5
|
from fastapi_cloud_cli.commands.apps.link import link_app
|
|
6
6
|
from fastapi_cloud_cli.commands.apps.list import list_apps
|
|
7
7
|
from fastapi_cloud_cli.commands.apps.unlink import unlink_app
|
|
8
|
+
from fastapi_cloud_cli.commands.apps.update import update_app
|
|
8
9
|
from fastapi_cloud_cli.commands.logs import logs
|
|
9
10
|
|
|
10
11
|
apps_app = typer.Typer(
|
|
@@ -17,5 +18,6 @@ apps_app.command("link")(link_app)
|
|
|
17
18
|
apps_app.command("list")(list_apps)
|
|
18
19
|
apps_app.command("logs")(logs)
|
|
19
20
|
apps_app.command("unlink")(unlink_app)
|
|
21
|
+
apps_app.command("update")(update_app)
|
|
20
22
|
|
|
21
23
|
__all__ = ["apps_app"]
|
{fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/apps/create.py
RENAMED
|
@@ -75,7 +75,10 @@ def create_app(
|
|
|
75
75
|
str | None,
|
|
76
76
|
typer.Option(
|
|
77
77
|
"--directory",
|
|
78
|
-
help=
|
|
78
|
+
help=(
|
|
79
|
+
"Relative app directory containing the pyproject.toml "
|
|
80
|
+
"(for example: backend or webserver)."
|
|
81
|
+
),
|
|
79
82
|
),
|
|
80
83
|
] = None,
|
|
81
84
|
link: Annotated[
|
|
@@ -146,7 +149,17 @@ def create_app(
|
|
|
146
149
|
)
|
|
147
150
|
toolkit.print_line()
|
|
148
151
|
|
|
149
|
-
|
|
152
|
+
try:
|
|
153
|
+
directory = validate_app_directory(directory)
|
|
154
|
+
except ValueError as e:
|
|
155
|
+
toolkit.fail(
|
|
156
|
+
"invalid_input",
|
|
157
|
+
f"Invalid app directory: {e}",
|
|
158
|
+
hint=(
|
|
159
|
+
"Pass a relative app directory such as `backend` or `webserver`; "
|
|
160
|
+
"use --path with --link to choose a local filesystem path."
|
|
161
|
+
),
|
|
162
|
+
)
|
|
150
163
|
|
|
151
164
|
with toolkit.progress(
|
|
152
165
|
title="Creating app",
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Annotated, Any
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
from rich_toolkit import RichToolkit
|
|
7
|
+
|
|
8
|
+
from fastapi_cloud_cli.commands.deploy.archive import validate_app_directory
|
|
9
|
+
from fastapi_cloud_cli.utils.api import APIClient
|
|
10
|
+
from fastapi_cloud_cli.utils.apps import resolve_app_id_or_fail
|
|
11
|
+
from fastapi_cloud_cli.utils.auth import Identity
|
|
12
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
13
|
+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UpdatedApp(BaseModel):
|
|
19
|
+
id: str
|
|
20
|
+
team_id: str
|
|
21
|
+
slug: str
|
|
22
|
+
name: str
|
|
23
|
+
directory: str | None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AppsUpdateOutput(BaseModel):
|
|
27
|
+
app: UpdatedApp
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _update_app(client: APIClient, *, app_id: str, directory: str | None) -> UpdatedApp:
|
|
31
|
+
response = client.patch(
|
|
32
|
+
f"/apps/{app_id}",
|
|
33
|
+
json={"directory": directory},
|
|
34
|
+
)
|
|
35
|
+
response.raise_for_status()
|
|
36
|
+
|
|
37
|
+
return UpdatedApp.model_validate(response.json())
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _render_apps_update_output(data: AppsUpdateOutput, toolkit: RichToolkit) -> None:
|
|
41
|
+
toolkit.print(f"Updated app [bold]{data.app.name}[/bold]", bullet=False)
|
|
42
|
+
toolkit.print(
|
|
43
|
+
f"Directory: [bold]{data.app.directory if data.app.directory is not None else '.'}[/bold]",
|
|
44
|
+
bullet=False,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def update_app(
|
|
49
|
+
app_id: Annotated[
|
|
50
|
+
str | None,
|
|
51
|
+
typer.Argument(
|
|
52
|
+
help="ID of the app to update (defaults to the app linked to the current directory).",
|
|
53
|
+
),
|
|
54
|
+
] = None,
|
|
55
|
+
directory: Annotated[
|
|
56
|
+
str | None,
|
|
57
|
+
typer.Option(
|
|
58
|
+
"--directory",
|
|
59
|
+
help=(
|
|
60
|
+
"Relative app directory containing the pyproject.toml "
|
|
61
|
+
"(for example: src or backend)."
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
] = None,
|
|
65
|
+
json_output: JsonOutputOption = False,
|
|
66
|
+
) -> Any:
|
|
67
|
+
"""
|
|
68
|
+
Update FastAPI Cloud app metadata.
|
|
69
|
+
"""
|
|
70
|
+
identity = Identity()
|
|
71
|
+
|
|
72
|
+
with get_rich_toolkit(json_output=json_output) as toolkit:
|
|
73
|
+
if not identity.is_logged_in():
|
|
74
|
+
toolkit.fail(
|
|
75
|
+
"not_logged_in",
|
|
76
|
+
"No credentials found.",
|
|
77
|
+
hint="Run `fastapi cloud login` or set FASTAPI_CLOUD_TOKEN.",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if directory is None:
|
|
81
|
+
toolkit.fail(
|
|
82
|
+
"missing_required_input",
|
|
83
|
+
"No updates provided.",
|
|
84
|
+
hint="Pass --directory to update the app directory.",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
target_app_id = resolve_app_id_or_fail(
|
|
88
|
+
toolkit,
|
|
89
|
+
app_id=app_id,
|
|
90
|
+
hint="Pass an app ID or run `fastapi cloud apps create --link` first.",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
directory = validate_app_directory(directory)
|
|
95
|
+
except ValueError as e:
|
|
96
|
+
toolkit.fail(
|
|
97
|
+
"invalid_input",
|
|
98
|
+
f"Invalid app directory: {e}",
|
|
99
|
+
hint="Pass a relative app directory such as `src` or `backend`.",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with APIClient() as client:
|
|
103
|
+
with toolkit.progress(
|
|
104
|
+
title="Updating app",
|
|
105
|
+
transient=True,
|
|
106
|
+
) as progress:
|
|
107
|
+
with client.handle_http_errors(
|
|
108
|
+
progress,
|
|
109
|
+
default_message="Error updating app. Please try again later.",
|
|
110
|
+
not_found_message="App not found.",
|
|
111
|
+
toolkit=toolkit,
|
|
112
|
+
):
|
|
113
|
+
app = _update_app(
|
|
114
|
+
client,
|
|
115
|
+
app_id=target_app_id,
|
|
116
|
+
directory=directory,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
toolkit.success(
|
|
120
|
+
AppsUpdateOutput(app=app),
|
|
121
|
+
render_output=_render_apps_update_output,
|
|
122
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from fastapi_cloud_cli.commands.ci.print_workflow import (
|
|
4
|
+
print_workflow as print_workflow_command,
|
|
5
|
+
)
|
|
6
|
+
from fastapi_cloud_cli.commands.setup_ci import setup_ci
|
|
7
|
+
|
|
8
|
+
ci_app = typer.Typer(
|
|
9
|
+
no_args_is_help=True,
|
|
10
|
+
help="Manage CI integration helpers.",
|
|
11
|
+
)
|
|
12
|
+
ci_app.command("print-workflow")(print_workflow_command)
|
|
13
|
+
ci_app.command("setup")(setup_ci)
|
|
14
|
+
|
|
15
|
+
__all__ = ["ci_app"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
from rich_toolkit import RichToolkit
|
|
6
|
+
|
|
7
|
+
from fastapi_cloud_cli.commands.setup_ci import (
|
|
8
|
+
DEFAULT_WORKFLOW_PATH,
|
|
9
|
+
_get_default_branch,
|
|
10
|
+
_get_workflow_content,
|
|
11
|
+
)
|
|
12
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
13
|
+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CIWorkflowOutput(BaseModel):
|
|
17
|
+
filename: str
|
|
18
|
+
content: str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _render_workflow_output(data: CIWorkflowOutput, toolkit: RichToolkit) -> None:
|
|
22
|
+
toolkit.console.print(data.content, markup=False, end="")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def print_workflow(
|
|
26
|
+
branch: Annotated[
|
|
27
|
+
str | None,
|
|
28
|
+
typer.Option(
|
|
29
|
+
"--branch",
|
|
30
|
+
"-b",
|
|
31
|
+
help="Branch that triggers deploys (defaults to the repo's default branch).",
|
|
32
|
+
),
|
|
33
|
+
] = None,
|
|
34
|
+
json_output: JsonOutputOption = False,
|
|
35
|
+
) -> Any:
|
|
36
|
+
"""Prints the GitHub Actions workflow YAML without writing files or secrets."""
|
|
37
|
+
|
|
38
|
+
branch = branch or _get_default_branch()
|
|
39
|
+
workflow = CIWorkflowOutput(
|
|
40
|
+
filename=DEFAULT_WORKFLOW_PATH.name,
|
|
41
|
+
content=_get_workflow_content(branch),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
with get_rich_toolkit(minimal=True, json_output=json_output) as toolkit:
|
|
45
|
+
toolkit.success(workflow, render_output=_render_workflow_output)
|
|
@@ -6,6 +6,7 @@ from httpx import Client
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
from rich_toolkit.progress import Progress
|
|
8
8
|
|
|
9
|
+
from fastapi_cloud_cli.commands.deploy.cloud import CreateDeploymentResponse
|
|
9
10
|
from fastapi_cloud_cli.utils.api import APIClient
|
|
10
11
|
from fastapi_cloud_cli.utils.progress_file import ProgressFile
|
|
11
12
|
|
|
@@ -43,7 +44,7 @@ def _upload_deployment(
|
|
|
43
44
|
deployment_id: str,
|
|
44
45
|
archive_path: Path,
|
|
45
46
|
progress: Progress,
|
|
46
|
-
) ->
|
|
47
|
+
) -> CreateDeploymentResponse:
|
|
47
48
|
archive_size = archive_path.stat().st_size
|
|
48
49
|
archive_size_str = _format_size(archive_size)
|
|
49
50
|
|
|
@@ -88,3 +89,5 @@ def _upload_deployment(
|
|
|
88
89
|
|
|
89
90
|
notify_response.raise_for_status()
|
|
90
91
|
logger.debug("Upload notification sent successfully")
|
|
92
|
+
|
|
93
|
+
return CreateDeploymentResponse.model_validate(notify_response.json())
|
{fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deploy/wait.py
RENAMED
|
@@ -46,7 +46,6 @@ LONG_WAIT_MESSAGES = [
|
|
|
46
46
|
def _verify_deployment(
|
|
47
47
|
toolkit: RichToolkit,
|
|
48
48
|
client: APIClient,
|
|
49
|
-
app_id: str,
|
|
50
49
|
deployment: CreateDeploymentResponse,
|
|
51
50
|
) -> None:
|
|
52
51
|
failed_status: str | None = None
|
|
@@ -57,7 +56,7 @@ def _verify_deployment(
|
|
|
57
56
|
done_emoji="✅",
|
|
58
57
|
) as progress:
|
|
59
58
|
try:
|
|
60
|
-
final_status = client.poll_deployment_status(
|
|
59
|
+
final_status = client.poll_deployment_status(deployment.id)
|
|
61
60
|
except (TimeoutError, TooManyRetriesError, StreamLogError):
|
|
62
61
|
progress.metadata["done_emoji"] = "⚠️"
|
|
63
62
|
progress.current_message = (
|
|
@@ -168,6 +167,4 @@ def _wait_for_deployment(
|
|
|
168
167
|
if build_complete:
|
|
169
168
|
toolkit.print_line()
|
|
170
169
|
|
|
171
|
-
_verify_deployment(
|
|
172
|
-
toolkit=toolkit, client=client, app_id=app_id, deployment=deployment
|
|
173
|
-
)
|
|
170
|
+
_verify_deployment(toolkit=toolkit, client=client, deployment=deployment)
|
{fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/deployments.py
RENAMED
|
@@ -95,10 +95,8 @@ def _get_deployments(
|
|
|
95
95
|
)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def _get_deployment(
|
|
99
|
-
|
|
100
|
-
) -> DeploymentGetOutput:
|
|
101
|
-
response = client.get(f"/apps/{app_id}/deployments/{deployment_id}")
|
|
98
|
+
def _get_deployment(client: APIClient, *, deployment_id: str) -> DeploymentGetOutput:
|
|
99
|
+
response = client.get(f"/deployments/{deployment_id}")
|
|
102
100
|
response.raise_for_status()
|
|
103
101
|
|
|
104
102
|
return DeploymentGetOutput(deployment=Deployment.model_validate(response.json()))
|
|
@@ -344,7 +342,7 @@ def get_deployment(
|
|
|
344
342
|
hint="Run `fastapi cloud login` or set FASTAPI_CLOUD_TOKEN.",
|
|
345
343
|
)
|
|
346
344
|
|
|
347
|
-
|
|
345
|
+
resolve_app_id_or_fail(toolkit, app_id=app_id)
|
|
348
346
|
|
|
349
347
|
with APIClient() as client:
|
|
350
348
|
with toolkit.progress(
|
|
@@ -359,7 +357,6 @@ def get_deployment(
|
|
|
359
357
|
):
|
|
360
358
|
result = _get_deployment(
|
|
361
359
|
client,
|
|
362
|
-
app_id=target_app_id,
|
|
363
360
|
deployment_id=deployment_id,
|
|
364
361
|
)
|
|
365
362
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from rich_toolkit import RichToolkit
|
|
5
|
+
|
|
6
|
+
from fastapi_cloud_cli.utils.auth import delete_auth_config
|
|
7
|
+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
|
|
8
|
+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LogoutOutput(BaseModel):
|
|
12
|
+
logged_out: bool
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _render_logout_output(data: LogoutOutput, toolkit: RichToolkit) -> None:
|
|
16
|
+
toolkit.print_title("FastAPI Cloud")
|
|
17
|
+
toolkit.print_line()
|
|
18
|
+
toolkit.print("You are now logged out!", emoji="👋")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def logout(json_output: JsonOutputOption = False) -> Any:
|
|
22
|
+
"""
|
|
23
|
+
Logout from FastAPI Cloud.
|
|
24
|
+
"""
|
|
25
|
+
with get_rich_toolkit(json_output=json_output) as toolkit:
|
|
26
|
+
delete_auth_config()
|
|
27
|
+
toolkit.success(
|
|
28
|
+
LogoutOutput(logged_out=True),
|
|
29
|
+
render_output=_render_logout_output,
|
|
30
|
+
)
|
{fastapi_cloud_cli-0.20.0 → fastapi_cloud_cli-0.22.0}/src/fastapi_cloud_cli/commands/logs.py
RENAMED
|
@@ -131,6 +131,12 @@ def _handle_stream_log_error(
|
|
|
131
131
|
message = handle_http_error(error.__cause__)
|
|
132
132
|
hint = get_http_error_hint(code)
|
|
133
133
|
|
|
134
|
+
if error.status_code == 400 and hint is None:
|
|
135
|
+
hint = (
|
|
136
|
+
"Try a shorter time range (e.g. `--since 1d`). "
|
|
137
|
+
"Log retention depends on your plan."
|
|
138
|
+
)
|
|
139
|
+
|
|
134
140
|
else:
|
|
135
141
|
code = "api_error"
|
|
136
142
|
message = f"[red]Error:[/] {escape(str(error))}"
|
|
@@ -215,7 +221,10 @@ def logs(
|
|
|
215
221
|
"5m",
|
|
216
222
|
"--since",
|
|
217
223
|
"-s",
|
|
218
|
-
help=
|
|
224
|
+
help=(
|
|
225
|
+
"Show logs since a specific time (e.g., '5m', '1h', '2d'). "
|
|
226
|
+
"Limited by your plan's log retention."
|
|
227
|
+
),
|
|
219
228
|
show_default=True,
|
|
220
229
|
callback=_validate_since,
|
|
221
230
|
),
|