reflex-hosting-cli 0.1.64__tar.gz → 0.1.66__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.
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/PKG-INFO +1 -1
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/utils/hosting.py +22 -4
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/cli.py +44 -58
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/gcp.py +32 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/.gitignore +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/README.md +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/pyproject.toml +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/__init__.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/cli.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/__init__.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/base.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/compiler.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/hosting.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/core/__init__.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/core/config.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/deployments.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/utils/__init__.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/utils/console.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/utils/dependency.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/utils/exceptions.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/__init__.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/apps.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/deployments.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/project.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/secrets.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/utils.py +0 -0
- {reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/vmtypes_regions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reflex-hosting-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.66
|
|
4
4
|
Summary: Reflex Hosting CLI
|
|
5
5
|
Author-email: Nikhil Rao <nikhil@reflex.dev>, Alek Petuskey <alek@reflex.dev>
|
|
6
6
|
Maintainer-email: Simon Young <simon@reflex.dev>, Khaleel Al-Adhami <khaleel@reflex.dev>
|
|
@@ -1078,6 +1078,20 @@ def select_project(project: str, token: str | None = None) -> str:
|
|
|
1078
1078
|
return f"{project} is now selected."
|
|
1079
1079
|
|
|
1080
1080
|
|
|
1081
|
+
def normalize_project_id(value: Any) -> str | None:
|
|
1082
|
+
"""Normalize a project ID value, treating empty/whitespace strings and non-strings as None.
|
|
1083
|
+
|
|
1084
|
+
Args:
|
|
1085
|
+
value: The raw project ID value from config, CLI args, or hosting.json.
|
|
1086
|
+
|
|
1087
|
+
Returns:
|
|
1088
|
+
The stripped project ID, or None if the value is missing or blank.
|
|
1089
|
+
"""
|
|
1090
|
+
if isinstance(value, str) and value.strip():
|
|
1091
|
+
return value.strip()
|
|
1092
|
+
return None
|
|
1093
|
+
|
|
1094
|
+
|
|
1081
1095
|
def get_selected_project() -> str | None:
|
|
1082
1096
|
"""Retrieve the currently selected project ID.
|
|
1083
1097
|
|
|
@@ -1088,10 +1102,10 @@ def get_selected_project() -> str | None:
|
|
|
1088
1102
|
try:
|
|
1089
1103
|
with constants.Hosting.HOSTING_JSON.open() as config_file:
|
|
1090
1104
|
hosting_config = json.load(config_file)
|
|
1091
|
-
return hosting_config.get("project")
|
|
1105
|
+
return normalize_project_id(hosting_config.get("project"))
|
|
1092
1106
|
except Exception as ex:
|
|
1093
1107
|
console.debug(
|
|
1094
|
-
f"Unable to
|
|
1108
|
+
f"Unable to read selected project from {constants.Hosting.HOSTING_JSON} due to: {ex}"
|
|
1095
1109
|
)
|
|
1096
1110
|
return None
|
|
1097
1111
|
|
|
@@ -1970,14 +1984,18 @@ def authenticate_on_browser() -> tuple[str, dict[str, Any]]:
|
|
|
1970
1984
|
constants.Hosting.HOSTING_SERVICE_UI, f"/cli/login?request_id={request_id}"
|
|
1971
1985
|
)
|
|
1972
1986
|
|
|
1973
|
-
console.print(f"Opening {auth_url} ...")
|
|
1974
|
-
|
|
1975
1987
|
if not is_valid_url(constants.Hosting.HOSTING_SERVICE_UI):
|
|
1976
1988
|
console.error(
|
|
1977
1989
|
f"Invalid hosting URL: {constants.Hosting.HOSTING_SERVICE_UI}. Ensure the URL is in the correct format and includes a valid scheme"
|
|
1978
1990
|
)
|
|
1979
1991
|
raise click.exceptions.Exit(1)
|
|
1980
1992
|
|
|
1993
|
+
console.print(
|
|
1994
|
+
f"Opening {auth_url} ... By connecting your account, you agree to "
|
|
1995
|
+
"Reflex Cloud [Terms of Service] and [Privacy Policy].",
|
|
1996
|
+
markup=False,
|
|
1997
|
+
)
|
|
1998
|
+
|
|
1981
1999
|
if not webbrowser.open(auth_url):
|
|
1982
2000
|
console.warn(
|
|
1983
2001
|
f"Unable to automatically open the browser. Please go to {auth_url} to authenticate."
|
|
@@ -28,7 +28,8 @@ def login(
|
|
|
28
28
|
loglevel: The log level to use.
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
31
|
-
Information about the logged in user
|
|
31
|
+
Information about the newly logged in user or empty dict if already
|
|
32
|
+
logged in.
|
|
32
33
|
|
|
33
34
|
Raises:
|
|
34
35
|
SystemExit: If the command fails.
|
|
@@ -42,7 +43,7 @@ def login(
|
|
|
42
43
|
access_token, validated_info = hosting.authenticated_token()
|
|
43
44
|
if access_token:
|
|
44
45
|
console.print("You already logged in.")
|
|
45
|
-
return
|
|
46
|
+
return {}
|
|
46
47
|
|
|
47
48
|
# If not already logged in, open a browser window/tab to the login page.
|
|
48
49
|
access_token, validated_info = hosting.authenticate_on_browser()
|
|
@@ -179,19 +180,24 @@ def deploy(
|
|
|
179
180
|
if not description:
|
|
180
181
|
description = config.get("description", None)
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
project_id = hosting.normalize_project_id(project_id)
|
|
184
|
+
|
|
183
185
|
if project_name and not project_id:
|
|
184
186
|
result = hosting.search_project(
|
|
185
187
|
project_name, client=authenticated_client, interactive=interactive
|
|
186
188
|
)
|
|
187
|
-
project_id = result.get("id") if result else None
|
|
189
|
+
project_id = hosting.normalize_project_id(result.get("id")) if result else None
|
|
190
|
+
|
|
191
|
+
selected_project_id = hosting.get_selected_project()
|
|
188
192
|
|
|
193
|
+
validated_project: dict[str, Any] | None = None
|
|
189
194
|
try:
|
|
190
|
-
|
|
195
|
+
if not project_id:
|
|
196
|
+
project_id = selected_project_id
|
|
191
197
|
if project_id:
|
|
192
|
-
hosting.get_project(
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
validated_project = hosting.get_project(
|
|
199
|
+
project_id, client=authenticated_client
|
|
200
|
+
)
|
|
195
201
|
except httpx.HTTPStatusError as ex:
|
|
196
202
|
try:
|
|
197
203
|
console.error(ex.response.json().get("detail"))
|
|
@@ -209,9 +215,7 @@ def deploy(
|
|
|
209
215
|
try:
|
|
210
216
|
if app_name and not app_id:
|
|
211
217
|
search_project_id = project_id
|
|
212
|
-
if
|
|
213
|
-
search_project_id = hosting.get_selected_project()
|
|
214
|
-
elif interactive and not project:
|
|
218
|
+
if interactive and not project:
|
|
215
219
|
search_project_id = None
|
|
216
220
|
|
|
217
221
|
app = hosting.search_app(
|
|
@@ -230,16 +234,13 @@ def deploy(
|
|
|
230
234
|
raise click.exceptions.Exit(1) from ex
|
|
231
235
|
|
|
232
236
|
if app and interactive and not project and not app_id:
|
|
233
|
-
default_project_id =
|
|
237
|
+
default_project_id = selected_project_id
|
|
234
238
|
app_project_id = app.get("project_id")
|
|
235
239
|
|
|
236
240
|
if app_project_id and (
|
|
237
241
|
not default_project_id or app_project_id != default_project_id
|
|
238
242
|
):
|
|
239
|
-
|
|
240
|
-
app_project_id, client=authenticated_client
|
|
241
|
-
)
|
|
242
|
-
app_project_name = app_project.get("name", "Unknown")
|
|
243
|
+
app_project_name = (app.get("project") or {}).get("name") or app_project_id
|
|
243
244
|
if (
|
|
244
245
|
console.ask(
|
|
245
246
|
f"Deploy to app '{app['name']}' in project '{app_project_name}'?",
|
|
@@ -262,55 +263,40 @@ def deploy(
|
|
|
262
263
|
)
|
|
263
264
|
== "y"
|
|
264
265
|
):
|
|
265
|
-
# Check if we need confirmation for deploying to non-default project
|
|
266
266
|
if not project:
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
default_project_id = hosting.get_default_project(
|
|
278
|
-
authenticated_client
|
|
267
|
+
needs_confirmation = not selected_project_id or (
|
|
268
|
+
project_id and project_id != selected_project_id
|
|
269
|
+
)
|
|
270
|
+
if needs_confirmation:
|
|
271
|
+
if project_id:
|
|
272
|
+
project_display_name = (
|
|
273
|
+
(
|
|
274
|
+
validated_project.get("name")
|
|
275
|
+
if validated_project
|
|
276
|
+
else None
|
|
279
277
|
)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
default_project_id, client=authenticated_client
|
|
283
|
-
)
|
|
284
|
-
project_name = default_project.get(
|
|
285
|
-
"name", "Default Project"
|
|
286
|
-
)
|
|
287
|
-
else:
|
|
288
|
-
project_name = "Default Project"
|
|
289
|
-
except Exception:
|
|
290
|
-
project_name = "Unknown"
|
|
291
|
-
|
|
292
|
-
if (
|
|
293
|
-
console.ask(
|
|
294
|
-
f"Create and deploy app '{app_name}' in project '{project_name}'?",
|
|
295
|
-
choices=["y", "n"],
|
|
296
|
-
default="y",
|
|
278
|
+
or project_name
|
|
279
|
+
or project_id
|
|
297
280
|
)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
elif project_id and project_id != default_project_id:
|
|
303
|
-
try:
|
|
304
|
-
target_project = hosting.get_project(
|
|
305
|
-
project_id, client=authenticated_client
|
|
281
|
+
else:
|
|
282
|
+
project_display_name = "your default project"
|
|
283
|
+
fallback_project_id = hosting.get_default_project(
|
|
284
|
+
authenticated_client
|
|
306
285
|
)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
286
|
+
if fallback_project_id:
|
|
287
|
+
try:
|
|
288
|
+
fallback_project = hosting.get_project(
|
|
289
|
+
fallback_project_id, client=authenticated_client
|
|
290
|
+
)
|
|
291
|
+
project_display_name = (
|
|
292
|
+
fallback_project.get("name") or project_display_name
|
|
293
|
+
)
|
|
294
|
+
except Exception:
|
|
295
|
+
pass
|
|
310
296
|
|
|
311
297
|
if (
|
|
312
298
|
console.ask(
|
|
313
|
-
f"Create and deploy app '{app_name}' in project '{
|
|
299
|
+
f"Create and deploy app '{app_name}' in project '{project_display_name}'?",
|
|
314
300
|
choices=["y", "n"],
|
|
315
301
|
default="y",
|
|
316
302
|
)
|
|
@@ -6,6 +6,7 @@ a Cloud Build job (via a ``cloudbuild.yaml`` written to a tempfile and
|
|
|
6
6
|
referenced with ``gcloud builds submit --config=...``) — the user's project
|
|
7
7
|
tree is never modified. The script reads its parameters from environment
|
|
8
8
|
variables (GCP_PROJECT, GCP_REGION, SERVICE_NAME, AR_REPO, VERSION,
|
|
9
|
+
CLOUD_RUN_CPU, CLOUD_RUN_MEMORY, CLOUD_RUN_MIN_INSTANCES,
|
|
9
10
|
REFLEX_CLOUDBUILD_YAML).
|
|
10
11
|
"""
|
|
11
12
|
|
|
@@ -37,6 +38,9 @@ ENV_GCP_REGION = "GCP_REGION"
|
|
|
37
38
|
ENV_SERVICE_NAME = "SERVICE_NAME"
|
|
38
39
|
ENV_AR_REPO = "AR_REPO"
|
|
39
40
|
ENV_VERSION = "VERSION"
|
|
41
|
+
ENV_CPU = "CLOUD_RUN_CPU"
|
|
42
|
+
ENV_MEMORY = "CLOUD_RUN_MEMORY"
|
|
43
|
+
ENV_MIN_INSTANCES = "CLOUD_RUN_MIN_INSTANCES"
|
|
40
44
|
# Path to the Cloud Build config file written by the CLI. The rewritten
|
|
41
45
|
# deploy script references it as ``--config="${REFLEX_CLOUDBUILD_YAML}"``.
|
|
42
46
|
ENV_REFLEX_CLOUDBUILD_YAML = "REFLEX_CLOUDBUILD_YAML"
|
|
@@ -136,6 +140,28 @@ DEPLOY_ENV_ALLOWLIST = frozenset({
|
|
|
136
140
|
default=None,
|
|
137
141
|
help="The image version tag (sets VERSION). Defaults to a UTC timestamp.",
|
|
138
142
|
)
|
|
143
|
+
@click.option(
|
|
144
|
+
"--cpu",
|
|
145
|
+
"cpu",
|
|
146
|
+
default="1",
|
|
147
|
+
show_default=True,
|
|
148
|
+
help="Cloud Run CPU allocation, e.g. '1', '2', '4' (sets CLOUD_RUN_CPU).",
|
|
149
|
+
)
|
|
150
|
+
@click.option(
|
|
151
|
+
"--memory",
|
|
152
|
+
"memory",
|
|
153
|
+
default="1Gi",
|
|
154
|
+
show_default=True,
|
|
155
|
+
help="Cloud Run memory allocation, e.g. '512Mi', '1Gi', '2Gi' (sets CLOUD_RUN_MEMORY).",
|
|
156
|
+
)
|
|
157
|
+
@click.option(
|
|
158
|
+
"--min-instances",
|
|
159
|
+
"min_instances",
|
|
160
|
+
default=1,
|
|
161
|
+
show_default=True,
|
|
162
|
+
type=click.IntRange(min=0),
|
|
163
|
+
help="Minimum number of Cloud Run instances to keep warm (sets CLOUD_RUN_MIN_INSTANCES). Set to 0 to scale to zero.",
|
|
164
|
+
)
|
|
139
165
|
@click.option(
|
|
140
166
|
"--source",
|
|
141
167
|
"source_dir",
|
|
@@ -170,6 +196,9 @@ def deploy_command(
|
|
|
170
196
|
service_name: str,
|
|
171
197
|
ar_repo: str,
|
|
172
198
|
version_tag: str | None,
|
|
199
|
+
cpu: str,
|
|
200
|
+
memory: str,
|
|
201
|
+
min_instances: int,
|
|
173
202
|
source_dir: str,
|
|
174
203
|
token: str | None,
|
|
175
204
|
interactive: bool,
|
|
@@ -252,6 +281,9 @@ def deploy_command(
|
|
|
252
281
|
ENV_SERVICE_NAME: service_name,
|
|
253
282
|
ENV_AR_REPO: ar_repo,
|
|
254
283
|
ENV_VERSION: version_value,
|
|
284
|
+
ENV_CPU: cpu,
|
|
285
|
+
ENV_MEMORY: memory,
|
|
286
|
+
ENV_MIN_INSTANCES: str(min_instances),
|
|
255
287
|
}
|
|
256
288
|
|
|
257
289
|
console.info("Received deploy manifest from Reflex.")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/constants/compiler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{reflex_hosting_cli-0.1.64 → reflex_hosting_cli-0.1.66}/src/reflex_cli/v2/vmtypes_regions.py
RENAMED
|
File without changes
|