|
| 1 | +# Plan: decouple build/deploy from the CLI into `smbcloud-deploy` |
| 2 | + |
| 3 | +Status: in progress. Stages 0 to 3 (vite_spa slice) shipped. Remaining work below |
| 4 | +is the **next milestone**. |
| 5 | + |
| 6 | +## Goal |
| 7 | + |
| 8 | +Move the deploy logic out of `crates/cli` into a reusable `crates/smbcloud-deploy` |
| 9 | +engine so the CLI, the CI action, and (later) the server-side git receiver all |
| 10 | +drive the same code. They differ only in how they report progress and how they |
| 11 | +authenticate. |
| 12 | + |
| 13 | +Two inversions make it reusable: |
| 14 | +- `Reporter` replaces direct `spinners` / `dialoguer` / `println!`, so the engine |
| 15 | + never owns the terminal. The CLI supplies `SpinnerReporter`. |
| 16 | +- Auth is passed in (a token / credentials); the engine never reads `~/.smb` or |
| 17 | + prompts for login. |
| 18 | + |
| 19 | +Decisions already made: |
| 20 | +- Networking crates (`smbcloud-networking*`) stay direct deps of the engine. |
| 21 | + Only reporting and auth are inverted. |
| 22 | +- `git.rs` (SSH-git remote setup) stays in the CLI for now. It is the SSH-git |
| 23 | + path slated for replacement by git-smart-HTTP, so decoupling it is wasted work. |
| 24 | +- Interactive setup (`setup*.rs`, `process_migrate.rs`) stays in the CLI. It is |
| 25 | + UX, not engine. |
| 26 | + |
| 27 | +## Done |
| 28 | + |
| 29 | +- **Stage 0** engine crate: `error::DeployError`, `report::{Reporter, NoopReporter}`, |
| 30 | + `runner::detect_runner`. |
| 31 | +- **Stage 1** CLI depends on the engine; `ui/reporter.rs::SpinnerReporter`; |
| 32 | + `detect_runner` rewired; old `deploy/detect_runner.rs` removed. |
| 33 | +- **Stage 2** transport: `transport::{Transport, RsyncTransport}` + moved |
| 34 | + `known_hosts`. CLI helper `deploy::rsync_transport(config, runner, user_id)` |
| 35 | + resolves the local `~/.ssh` identity and remote path. |
| 36 | +- **Stage 3 (vite_spa slice)** build split: `build::{BuildStrategy, BuildArtifact, |
| 37 | + ViteSpaBuild}`. `process_deploy_vite_spa.rs` now calls the engine for the build |
| 38 | + and reuses one `SpinnerReporter` for build + transport. |
| 39 | + |
| 40 | +## Next milestone |
| 41 | + |
| 42 | +### 1. Shared remote-command step |
| 43 | + |
| 44 | +Several strategies do the same "SSH in and restart the service" step, inlined |
| 45 | +per file. Extract it into the engine first (e.g. `transport::RemoteCommand` or a |
| 46 | +`remote` module) so the strategies can share it. Model it behind the same pinned |
| 47 | +host-key SSH used by `RsyncTransport`. |
| 48 | + |
| 49 | +### 2. Remaining `BuildStrategy` extractions (one per pass, compile-green each) |
| 50 | + |
| 51 | +Do smallest first. Each: lift build mechanics into a `BuildStrategy`, swap |
| 52 | +`spinners` + `stop_and_persist` for `Reporter`, take auth as a param, route the |
| 53 | +remote-restart step through step 1. |
| 54 | + |
| 55 | +| File | Lines | Shape | |
| 56 | +| --- | --- | --- | |
| 57 | +| `process_deploy_rails.rs` | ~395 | rsync shared lib, SSH compile native gem, git force-push | |
| 58 | +| `process_deploy_rust.rs` | ~641 | cross-build Linux binary, rsync, SSH restart | |
| 59 | +| `process_deploy_nextjs_ssr.rs` | ~700 | install, build, upload `.next/standalone`, SSH restart | |
| 60 | +| `process_deploy_swift.rs` | ~832 | Docker Linux build, rsync binary + Resources, SSH restart | |
| 61 | + |
| 62 | +Follow `ViteSpaBuild` as the template. Keep the deployment-record API calls |
| 63 | +(`create_deployment` / `update`) in the CLI router, not the engine. |
| 64 | + |
| 65 | +### 3. Stage 4: router + retire the CommandResult wart |
| 66 | + |
| 67 | +- Flip `process_deploy.rs`'s router to call an `engine::deploy(...)` orchestrator. |
| 68 | +- Retire `CommandResult`'s `spinner: Spinner` field (the "return a live spinner, |
| 69 | + caller stops it" pattern) now that the engine reports the whole flow through |
| 70 | + `Reporter`. `CommandResult` has ~50 construction sites, so this is its own pass: |
| 71 | + either make `spinner` optional or drop it and have commands return plain data. |
| 72 | + |
| 73 | +## Reference |
| 74 | + |
| 75 | +- Spec: `smbcloud` repo `.agents/specs/smbcloud-deploy.md` (product direction), |
| 76 | + `smbcloud-actions.md` (CI wrapper). Direction is git-smart-HTTP, local-first |
| 77 | + build, drop SSH transport later. |
| 78 | +- Engine crate: `crates/smbcloud-deploy/`. |
0 commit comments