ENG-11433 Move reflex deploy out of the framework into the Cloud CLI - #6924
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…sting CLI The managed-platform deploy command (options and body) now lives in reflex_cli.v2.deploy; the reflex CLI registers it via cli.add_command. Flags and behavior are unchanged. The module lazily imports reflex internals in the command body since it only runs through the reflex CLI.
d82f9ea to
b822d53
Compare
Greptile SummaryThe PR moves
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/reflex-hosting-cli/src/reflex_cli/v2/deploy.py | Hosts the moved deploy command with lazy framework imports and preserves argument forwarding to the hosting deployment flow. |
| reflex/reflex.py | Replaces the in-framework deploy implementation with guarded external command registration and missing-package placeholders. |
| packages/reflex-base/src/reflex_base/utils/cli_options.py | Centralizes shared Click logging options so the hosting CLI can import them without depending on the framework. |
| pyproject.toml | Raises the hosting CLI dependency floor to the workspace version containing the moved deploy command. |
| tests/units/reflex_cli/v2/test_deploy.py | Verifies registration, option compatibility, help rendering, and standalone importability. |
| tests/units/test_reflex.py | Verifies real cloud command registration and user-facing behavior when the hosting package is unavailable. |
Reviews (3): Last reviewed commit: "ENG-11433 docs(cli): drop the stale entr..." | Re-trigger Greptile
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
4 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/units/utils/test_cli_plugins.py">
<violation number="1" location="tests/units/utils/test_cli_plugins.py:282">
P3: This reflex-side test hardcodes `reflex_cli.v2.deploy`, a private module path of the separate reflex-hosting-cli package, to assert eager loading. If the hosting CLI renames or reorganizes that module, this framework test fails spuriously even though the decoupling behavior is unchanged. Derive the expected module from the discovered entry points instead (e.g., check that every module referenced by the entry-point value is present in sys.modules) so the test stays coupled to the entry-point contract rather than to the hosting CLI's internal layout.</violation>
</file>
<file name="reflex/utils/cli_plugins.py">
<violation number="1" location="reflex/utils/cli_plugins.py:75">
P2: When a Typer entry point cannot be converted, `typer.main.get_command` aborts construction of the entire `reflex` CLI. Catch conversion errors, log the plugin failure, and continue so the remaining commands and fallback placeholders remain available.</violation>
<violation number="2" location="reflex/utils/cli_plugins.py:163">
P2: When a contributed entry point exists but fails to load (`entry_point.load()` raises) or does not resolve to a click command, the code still registers the "install/upgrade reflex-hosting-cli" placeholder. That message is wrong for an installed, current package, so the user is told to reinstall or upgrade an already-correct package instead of the real cause. Track names that already had an entry point separately from truly absent ones, and give those a diagnostic that reflects the actual failure (the load error already logged, or the non-click object type).</violation>
<violation number="3" location="reflex/utils/cli_plugins.py:173">
P2: Guard duplicate names before registering the command. Click stores commands by name, so this call overwrites an existing built-in or earlier contributed command; reject or skip collisions instead.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
The command body now lives in reflex_cli.v2.deploy, so reflex/reflex.py imports it instead of defining it. That import is guarded: when the hosting CLI is absent, a stand-in of the same name is registered. It accepts any flags, so the user is told which package to install rather than getting a usage error about an option the real command understands. `login` and `logout` report the same way. deploy.py imported log_options from `reflex`, which is not a dependency of reflex-hosting-cli, so the package failed to import on its own. The shared click options move to reflex_base.utils.cli_options, which both packages already depend on; reflex/utils/cli_options.py re-exports them. The hosting CLI floor moves to the release carrying the moved module, held at the workspace development version until that ships.
b822d53 to
03a451c
Compare
Closes ENG-11433.
reflex deploylived inreflex/reflex.py, so cloud-specific code shipped inside the open-source framework. The implementation now lives inreflex-hosting-cli.What changed
The command moved.
reflex/reflex.pyloses 245 lines;reflex_cli/v2/deploy.pygains 236. The framework contains no cloud code.The import is guarded.
reflex/reflex.pyimports the moved command and falls back when it cannot:The typer conversion for
cloudis unchanged from before; it just moved inside theelse.A missing package no longer fails opaquely. The stand-in is a real command of the same name.
ignore_unknown_optionsplus aclick.UNPROCESSEDargument make it swallow every flag, soreflex deploy --app-name demoreportspip install reflex-hosting-cliinstead of dying on "No such option".loginandlogoutuse the same helper onImportError.Standalone importability, fixed.
deploy.pyimportedreflex.utils.cli_options, butreflexis not a dependency ofreflex-hosting-cli, so importing the package on its own raisedModuleNotFoundError. The shared click options moved toreflex_base.utils.cli_options(addingclick >=8.2to reflex-base);reflex/utils/cli_options.pyre-exports them for its existing callers.Answers to the issue's open questions
How is it wired up? A guarded import, with
reflex-hosting-clistill a required dependency.pip install reflexgives a workingreflex deployand nothing changes for existing users. Dropping the dependency would break them, which the "no breaking changes" bullet forbids.An earlier revision of this PR used a
reflex.cli_commandsentry point group instead. It was removed: the only thing it bought over a direct import was that the framework did not write the namereflex_cliin its source, which did not justify 173 lines of discovery machinery and an indirection that hides wherereflex deploycomes from. The cloud code is out of the framework either way, which is what the issue asks for.What if the Cloud CLI is not installed? The command name still exists and reports what to install, as above.
No UX change
Verified rather than assumed: the pre-move command is reconstructed from the merge-base copy of
reflex/reflex.pyand diffed against the live one. All 23 parameters match on name, opts, secondary opts, type, default,multipleandrequired, and the rendered--helpis identical. A separate check runs the command against a real app and asserts the 13 arguments still reachreflex_cli.v2.cli.deploy, and that--no-ssrand--exclude-from-backendstill reachexport()through theexport_fnclosure.Note for the release
reflex deploynow lives inreflex_cli.v2.deploy, which older hosting CLI releases do not carry, so the floor must exclude them. That release is unpublished, so the pin is the workspace development version0.1.70.post18.dev0— the same conventionreflex-hosting-clialready uses for itsreflex-basepin.scripts/check_min_deps.py --check-dev-pins reflexfails while it stands, so it must be re-pinned to the published version before release.One side effect:
check_min_deps.py reflexcannot build the root package while the dev pin stands.[tool.hatch.build.hooks.custom]setsrequire-runtime-dependencies = true, so runtime deps resolve inside the isolated build environment, which the script's local editable overrides never reach. The other packages still check.Tests
reflex deployhad no dedicated tests before this branch.tests/units/reflex_cli/v2/test_deploy.py— registration, the flag surface,--help, and asys.meta_pathprobe that imports the module with everyrefleximport blocked. That last one covers the standalone-import bug above.tests/units/test_reflex.py— the cloud commands resolve intoreflex_cli, and the stand-in reports the package rather than a usage error, including when the real command's flags are passed.Full suite: 7616 passed, 17 skipped. Ruff clean. Pyright: 0 errors.