release/v0.7.4
Plan: decouple build/deploy from the CLI into smbcloud-deploy
Status: in progress. Stages 0 to 3 (vite_spa slice) shipped. Remaining work below is the next milestone.
Goal
Move the deploy logic out of crates/cli into a reusable crates/smbcloud-deploy
engine so the CLI, the CI action, and (later) the server-side git receiver all
drive the same code. They differ only in how they report progress and how they
authenticate.
Two inversions make it reusable:
- Reporter replaces direct spinners / dialoguer / println!, so the engine
never owns the terminal. The CLI supplies SpinnerReporter.
- Auth is passed in (a token / credentials); the engine never reads ~/.smb or
prompts for login.
Decisions already made:
- Networking crates (smbcloud-networking*) stay direct deps of the engine.
Only reporting and auth are inverted.
- git.rs (SSH-git remote setup) stays in the CLI for now. It is the SSH-git
path slated for replacement by git-smart-HTTP, so decoupling it is wasted work.
- Interactive setup (setup*.rs, process_migrate.rs) stays in the CLI. It is
UX, not engine.
Done
- Stage 0 engine crate:
error::DeployError,report::{Reporter, NoopReporter},runner::detect_runner. - Stage 1 CLI depends on the engine;
ui/reporter.rs::SpinnerReporter;detect_runnerrewired; olddeploy/detect_runner.rsremoved. - Stage 2 transport:
transport::{Transport, RsyncTransport}+ movedknown_hosts. CLI helperdeploy::rsync_transport(config, runner, user_id)resolves the local~/.sshidentity and remote path. - Stage 3 (vite_spa slice) build split:
build::{BuildStrategy, BuildArtifact, ViteSpaBuild}.process_deploy_vite_spa.rsnow calls the engine for the build and reuses oneSpinnerReporterfor build + transport.
Next milestone
1. Shared remote-command step
Several strategies do the same "SSH in and restart the service" step, inlined
per file. Extract it into the engine first (e.g. transport::RemoteCommand or a
remote module) so the strategies can share it. Model it behind the same pinned
host-key SSH used by RsyncTransport.
2. Remaining BuildStrategy extractions (one per pass, compile-green each)
Do smallest first. Each: lift build mechanics into a BuildStrategy, swap
spinners + stop_and_persist for Reporter, take auth as a param, route the
remote-restart step through step 1.
| File | Lines | Shape |
|---|---|---|
process_deploy_rails.rs |
~395 | rsync shared lib, SSH compile native gem, git force-push |
process_deploy_rust.rs |
~641 | cross-build Linux binary, rsync, SSH restart |
process_deploy_nextjs_ssr.rs |
~700 | install, build, upload .next/standalone, SSH restart |
process_deploy_swift.rs |
~832 | Docker Linux build, rsync binary + Resources, SSH restart |
Follow ViteSpaBuild as the template. Keep the deployment-record API calls
(create_deployment / update) in the CLI router, not the engine.
3. Stage 4: router + retire the CommandResult wart
- Flip
process_deploy.rs's router to call anengine::deploy(...)orchestrator. - Retire
CommandResult'sspinner: Spinnerfield (the "return a live spinner, caller stops it" pattern) now that the engine reports the whole flow throughReporter.CommandResulthas ~50 construction sites, so this is its own pass: either makespinneroptional or drop it and have commands return plain data.
Reference
- Spec:
smbcloudrepo.agents/specs/smbcloud-deploy.md(product direction),smbcloud-actions.md(CI wrapper). Direction is git-smart-HTTP, local-first build, drop SSH transport later. - Engine crate:
crates/smbcloud-deploy/.