Skip to content

Commit ce7d429

Browse files
committed
refactor: move CLI modules under presentation/cli/ for SDK separation
Move all CLI-specific presentation modules (controllers, dispatch, input, views, error, errors, tests) into an explicit presentation/cli/ sub-tree. This establishes a clean physical boundary between the CLI and SDK delivery mechanisms in the presentation layer. Changes: - Create src/presentation/cli/ with its own mod.rs - Move controllers/, dispatch/, input/, views/, error.rs, errors.rs, tests/ into presentation/cli/ - Update presentation/mod.rs to declare only cli and sdk modules with backward-compatible re-exports - Update all import paths across 160 files (crate::presentation::X → crate::presentation::cli::X) - Update all doc comment examples to use new paths - Verify SDK has zero imports from presentation::cli This is the first step in the 4-part SDK extraction plan: 1. ✅ CLI/SDK separation (this commit) 2. Extract SDK workspace package 3. Extract shared types package 4. Fix DDD layer boundary violations
1 parent 28ed228 commit ce7d429

160 files changed

Lines changed: 596 additions & 708 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/refactors/plans/presentation-cli-sdk-separation.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ This is the first step in a 4-part incremental plan to extract the SDK into its
4141
**Total Active Proposals**: 1
4242
**Total Postponed**: 0
4343
**Total Discarded**: 0
44-
**Completed**: 0
44+
**Completed**: 1
4545
**In Progress**: 0
46-
**Not Started**: 1
46+
**Not Started**: 0
4747

4848
### Phase Summary
4949

50-
- **Phase 0 - Directory Reorganization (High Impact, Medium Effort)**: ⏳ 0/1 completed (0%)
50+
- **Phase 0 - Directory Reorganization (High Impact, Medium Effort)**: ✅ 1/1 completed (100%)
5151

5252
### Discarded Proposals
5353

@@ -86,13 +86,13 @@ The SDK and CLI are independent today (the SDK has zero imports from CLI modules
8686

8787
### Proposal #0: Move CLI Modules into an Explicit `cli/` Sub-Tree
8888

89-
**Status**: ⏳ Not Started
89+
**Status**: ✅ Complete
9090
**Impact**: 🟢🟢🟢 High
9191
**Effort**: 🔵🔵 Medium
9292
**Priority**: P0
9393
**Depends On**: None
94-
**Completed**: -
95-
**Commit**: -
94+
**Completed**: 2026-02-25
95+
**Commit**: (this commit)
9696

9797
#### Problem
9898

@@ -138,18 +138,18 @@ The top-level `presentation/mod.rs` becomes minimal — it declares the two sub-
138138

139139
#### Implementation Checklist
140140

141-
- [ ] Create `src/presentation/cli/` directory
142-
- [ ] Move `controllers/`, `dispatch/`, `input/`, `views/`, `error.rs`, `errors.rs`, `tests/` into `presentation/cli/`
143-
- [ ] Create `src/presentation/cli/mod.rs` with the same module declarations and re-exports currently in `presentation/mod.rs` (minus `sdk`)
144-
- [ ] Update `src/presentation/mod.rs` to declare only `pub mod cli;` and `pub mod sdk;` (plus backward-compat re-exports if needed)
145-
- [ ] Update all `use crate::presentation::controllers::...` imports across the codebase to `use crate::presentation::cli::controllers::...`
146-
- [ ] Update all `use crate::presentation::views::...` imports to `use crate::presentation::cli::views::...`
147-
- [ ] Update all `use crate::presentation::dispatch::...`, `use crate::presentation::input::...`, `use crate::presentation::error*` imports similarly
148-
- [ ] Update `src/main.rs` and `src/bootstrap/` imports
149-
- [ ] Verify the SDK module has zero imports from `crate::presentation::cli`
150-
- [ ] Update the `presentation/mod.rs` module documentation
151-
- [ ] Verify all tests pass (`cargo test`)
152-
- [ ] Run linter and fix any issues
141+
- [x] Create `src/presentation/cli/` directory
142+
- [x] Move `controllers/`, `dispatch/`, `input/`, `views/`, `error.rs`, `errors.rs`, `tests/` into `presentation/cli/`
143+
- [x] Create `src/presentation/cli/mod.rs` with the same module declarations and re-exports currently in `presentation/mod.rs` (minus `sdk`)
144+
- [x] Update `src/presentation/mod.rs` to declare only `pub mod cli;` and `pub mod sdk;` (plus backward-compat re-exports)
145+
- [x] Update all `use crate::presentation::controllers::...` imports across the codebase to `use crate::presentation::cli::controllers::...`
146+
- [x] Update all `use crate::presentation::views::...` imports to `use crate::presentation::cli::views::...`
147+
- [x] Update all `use crate::presentation::dispatch::...`, `use crate::presentation::input::...`, `use crate::presentation::error*` imports similarly
148+
- [x] Update `src/main.rs` and `src/bootstrap/` imports
149+
- [x] Verify the SDK module has zero imports from `crate::presentation::cli`
150+
- [x] Update the `presentation/mod.rs` module documentation
151+
- [x] Verify all tests pass (`cargo test`)
152+
- [x] Run linter and fix any issues
153153

154154
#### Testing Strategy
155155

@@ -195,5 +195,5 @@ The top-level `presentation/mod.rs` becomes minimal — it declares the two sub-
195195
---
196196

197197
**Created**: 2026-02-24
198-
**Last Updated**: 2026-02-24
199-
**Status**: 📋 Planning
198+
**Last Updated**: 2026-02-25
199+
**Status**: ✅ Complete

src/bootstrap/app.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ use std::sync::Arc;
2222
use clap::Parser;
2323
use tracing::info;
2424

25-
use crate::{bootstrap, presentation};
25+
use crate::bootstrap;
26+
use crate::presentation::cli::dispatch::route_command;
27+
use crate::presentation::cli::dispatch::ExecutionContext;
28+
use crate::presentation::cli::error::handle_error;
29+
use crate::presentation::cli::Cli;
2630

2731
/// Main application entry point
2832
///
@@ -41,7 +45,7 @@ use crate::{bootstrap, presentation};
4145
///
4246
/// Both panics are intentional as logging is critical for observability.
4347
pub async fn run() {
44-
let cli = presentation::Cli::parse();
48+
let cli = Cli::parse();
4549

4650
let logging_config = cli.global.logging_config();
4751

@@ -62,15 +66,12 @@ pub async fn run() {
6266
cli.global.verbosity_level(),
6367
&cli.global.working_dir,
6468
));
65-
let context = presentation::dispatch::ExecutionContext::new(container, cli.global.clone());
69+
let context = ExecutionContext::new(container, cli.global.clone());
6670

6771
match cli.command {
6872
Some(command) => {
69-
if let Err(e) =
70-
presentation::dispatch::route_command(command, &cli.global.working_dir, &context)
71-
.await
72-
{
73-
presentation::error::handle_error(&e, &context.user_output());
73+
if let Err(e) = route_command(command, &cli.global.working_dir, &context).await {
74+
handle_error(&e, &context.user_output());
7475
std::process::exit(1);
7576
}
7677
}

src/bootstrap/container.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@ use parking_lot::ReentrantMutex;
1212
use crate::application::command_handlers::PurgeCommandHandler;
1313
use crate::domain::environment::repository::EnvironmentRepository;
1414
use crate::infrastructure::persistence::repository_factory::RepositoryFactory;
15-
use crate::presentation::controllers::configure::ConfigureCommandController;
16-
use crate::presentation::controllers::constants::DEFAULT_LOCK_TIMEOUT;
17-
use crate::presentation::controllers::create::subcommands::environment::CreateEnvironmentCommandController;
18-
use crate::presentation::controllers::create::subcommands::schema::CreateSchemaCommandController;
19-
use crate::presentation::controllers::create::subcommands::template::CreateTemplateCommandController;
20-
use crate::presentation::controllers::destroy::DestroyCommandController;
21-
use crate::presentation::controllers::docs::DocsCommandController;
22-
use crate::presentation::controllers::list::ListCommandController;
23-
use crate::presentation::controllers::provision::ProvisionCommandController;
24-
use crate::presentation::controllers::purge::PurgeCommandController;
25-
use crate::presentation::controllers::register::RegisterCommandController;
26-
use crate::presentation::controllers::release::ReleaseCommandController;
27-
use crate::presentation::controllers::render::RenderCommandController;
28-
use crate::presentation::controllers::run::RunCommandController;
29-
use crate::presentation::controllers::show::ShowCommandController;
30-
use crate::presentation::controllers::test::handler::TestCommandController;
31-
use crate::presentation::controllers::validate::ValidateCommandController;
32-
use crate::presentation::views::{UserOutput, VerbosityLevel};
15+
use crate::presentation::cli::controllers::configure::ConfigureCommandController;
16+
use crate::presentation::cli::controllers::constants::DEFAULT_LOCK_TIMEOUT;
17+
use crate::presentation::cli::controllers::create::subcommands::environment::CreateEnvironmentCommandController;
18+
use crate::presentation::cli::controllers::create::subcommands::schema::CreateSchemaCommandController;
19+
use crate::presentation::cli::controllers::create::subcommands::template::CreateTemplateCommandController;
20+
use crate::presentation::cli::controllers::destroy::DestroyCommandController;
21+
use crate::presentation::cli::controllers::docs::DocsCommandController;
22+
use crate::presentation::cli::controllers::list::ListCommandController;
23+
use crate::presentation::cli::controllers::provision::ProvisionCommandController;
24+
use crate::presentation::cli::controllers::purge::PurgeCommandController;
25+
use crate::presentation::cli::controllers::register::RegisterCommandController;
26+
use crate::presentation::cli::controllers::release::ReleaseCommandController;
27+
use crate::presentation::cli::controllers::render::RenderCommandController;
28+
use crate::presentation::cli::controllers::run::RunCommandController;
29+
use crate::presentation::cli::controllers::show::ShowCommandController;
30+
use crate::presentation::cli::controllers::test::handler::TestCommandController;
31+
use crate::presentation::cli::controllers::validate::ValidateCommandController;
32+
use crate::presentation::cli::views::{UserOutput, VerbosityLevel};
3333
use crate::shared::clock::Clock;
3434
use crate::shared::SystemClock;
3535

@@ -44,7 +44,7 @@ use crate::shared::SystemClock;
4444
/// ```rust
4545
/// use std::path::Path;
4646
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
47-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
47+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
4848
///
4949
/// let working_dir = Path::new(".");
5050
/// let container = Container::new(VerbosityLevel::Normal, working_dir);
@@ -79,7 +79,7 @@ impl Container {
7979
/// ```rust
8080
/// use std::path::Path;
8181
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
82-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
82+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
8383
///
8484
/// // For normal application use
8585
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
@@ -122,7 +122,7 @@ impl Container {
122122
/// ```rust
123123
/// use std::path::Path;
124124
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
125-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
125+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
126126
///
127127
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
128128
/// let user_output = container.user_output();
@@ -143,7 +143,7 @@ impl Container {
143143
/// ```rust
144144
/// use std::path::Path;
145145
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
146-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
146+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
147147
///
148148
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
149149
/// let repository_factory = container.repository_factory();
@@ -165,7 +165,7 @@ impl Container {
165165
/// ```rust
166166
/// use std::path::Path;
167167
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
168-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
168+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
169169
///
170170
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
171171
/// let repository = container.repository();
@@ -186,7 +186,7 @@ impl Container {
186186
/// ```rust
187187
/// use std::path::Path;
188188
/// use torrust_tracker_deployer_lib::bootstrap::container::Container;
189-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
189+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
190190
///
191191
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
192192
/// let clock = container.clock();

src/presentation/controllers/configure/errors.rs renamed to src/presentation/cli/controllers/configure/errors.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use thiserror::Error;
88

99
use crate::application::command_handlers::configure::errors::ConfigureCommandHandlerError;
1010
use crate::domain::environment::name::EnvironmentNameError;
11-
use crate::presentation::views::progress::ProgressReporterError;
11+
use crate::presentation::cli::views::progress::ProgressReporterError;
1212

1313
/// Configure command specific errors
1414
///
@@ -115,9 +115,9 @@ impl ConfigureSubcommandError {
115115
/// use std::path::Path;
116116
/// use std::sync::Arc;
117117
/// use torrust_tracker_deployer_lib::bootstrap::Container;
118-
/// use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
119-
/// use torrust_tracker_deployer_lib::presentation::controllers::configure;
120-
/// use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
118+
/// use torrust_tracker_deployer_lib::presentation::cli::dispatch::ExecutionContext;
119+
/// use torrust_tracker_deployer_lib::presentation::cli::controllers::configure;
120+
/// use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
121121
///
122122
/// let container = Container::new(VerbosityLevel::Normal, Path::new("."));
123123
/// let context = ExecutionContext::new(Arc::new(container), global_args);
@@ -140,8 +140,8 @@ impl ConfigureSubcommandError {
140140
/// use std::time::Duration;
141141
/// use parking_lot::ReentrantMutex;
142142
/// use std::cell::RefCell;
143-
/// use torrust_tracker_deployer_lib::presentation::controllers::configure::handler::ConfigureCommandController;
144-
/// use torrust_tracker_deployer_lib::presentation::views::{UserOutput, VerbosityLevel};
143+
/// use torrust_tracker_deployer_lib::presentation::cli::controllers::configure::handler::ConfigureCommandController;
144+
/// use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};
145145
/// use torrust_tracker_deployer_lib::infrastructure::persistence::repository_factory::RepositoryFactory;
146146
/// use torrust_tracker_deployer_lib::shared::clock::SystemClock;
147147
///

src/presentation/controllers/configure/handler.rs renamed to src/presentation/cli/controllers/configure/handler.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ use crate::domain::environment::name::EnvironmentName;
1313
use crate::domain::environment::repository::EnvironmentRepository;
1414
use crate::domain::environment::state::Configured;
1515
use crate::domain::environment::Environment;
16-
use crate::presentation::input::cli::OutputFormat;
17-
use crate::presentation::views::commands::configure::{ConfigureDetailsData, JsonView, TextView};
18-
use crate::presentation::views::progress::ProgressReporter;
19-
use crate::presentation::views::progress::VerboseProgressListener;
20-
use crate::presentation::views::UserOutput;
16+
use crate::presentation::cli::input::cli::OutputFormat;
17+
use crate::presentation::cli::views::commands::configure::{
18+
ConfigureDetailsData, JsonView, TextView,
19+
};
20+
use crate::presentation::cli::views::progress::ProgressReporter;
21+
use crate::presentation::cli::views::progress::VerboseProgressListener;
22+
use crate::presentation::cli::views::UserOutput;
2123
use crate::shared::clock::Clock;
2224

2325
use super::errors::ConfigureSubcommandError;
@@ -272,9 +274,9 @@ impl ConfigureCommandController {
272274
#[cfg(test)]
273275
mod tests {
274276
use super::*;
275-
use crate::presentation::controllers::constants::DEFAULT_LOCK_TIMEOUT;
276-
use crate::presentation::views::testing::TestUserOutput;
277-
use crate::presentation::views::VerbosityLevel;
277+
use crate::presentation::cli::controllers::constants::DEFAULT_LOCK_TIMEOUT;
278+
use crate::presentation::cli::views::testing::TestUserOutput;
279+
use crate::presentation::cli::views::VerbosityLevel;
278280
use crate::shared::SystemClock;
279281

280282
/// Create test dependencies for configure command handler tests

src/presentation/controllers/configure/mod.rs renamed to src/presentation/cli/controllers/configure/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
//! use std::path::Path;
2323
//! use std::sync::Arc;
2424
//! use torrust_tracker_deployer_lib::bootstrap::Container;
25-
//! use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
26-
//! use torrust_tracker_deployer_lib::presentation::controllers::configure;
27-
//! use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
25+
//! use torrust_tracker_deployer_lib::presentation::cli::dispatch::ExecutionContext;
26+
//! use torrust_tracker_deployer_lib::presentation::cli::controllers::configure;
27+
//! use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
2828
//!
2929
//! let container = Container::new(VerbosityLevel::Normal, Path::new("."));
3030
//! let context = ExecutionContext::new(Arc::new(container), global_args);
@@ -42,9 +42,9 @@
4242
//! use std::path::Path;
4343
//! use std::sync::Arc;
4444
//! use torrust_tracker_deployer_lib::bootstrap::Container;
45-
//! use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
46-
//! use torrust_tracker_deployer_lib::presentation::controllers::configure;
47-
//! use torrust_tracker_deployer_lib::presentation::views::VerbosityLevel;
45+
//! use torrust_tracker_deployer_lib::presentation::cli::dispatch::ExecutionContext;
46+
//! use torrust_tracker_deployer_lib::presentation::cli::controllers::configure;
47+
//! use torrust_tracker_deployer_lib::presentation::cli::views::VerbosityLevel;
4848
//!
4949
//! let container = Container::new(VerbosityLevel::Normal, Path::new("."));
5050
//! let context = ExecutionContext::new(Arc::new(container), global_args);
@@ -67,8 +67,8 @@
6767
//! use std::time::Duration;
6868
//! use parking_lot::ReentrantMutex;
6969
//! use std::cell::RefCell;
70-
//! use torrust_tracker_deployer_lib::presentation::controllers::configure::handler::ConfigureCommandController;
71-
//! use torrust_tracker_deployer_lib::presentation::views::{UserOutput, VerbosityLevel};
70+
//! use torrust_tracker_deployer_lib::presentation::cli::controllers::configure::handler::ConfigureCommandController;
71+
//! use torrust_tracker_deployer_lib::presentation::cli::views::{UserOutput, VerbosityLevel};
7272
//! use torrust_tracker_deployer_lib::infrastructure::persistence::repository_factory::RepositoryFactory;
7373
//! use torrust_tracker_deployer_lib::shared::clock::SystemClock;
7474
//!

src/presentation/controllers/configure/tests/mod.rs renamed to src/presentation/cli/controllers/configure/tests/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ mod integration_tests {
1212

1313
use crate::domain::environment::repository::EnvironmentRepository;
1414
use crate::infrastructure::persistence::repository_factory::RepositoryFactory;
15-
use crate::presentation::controllers::configure;
16-
use crate::presentation::controllers::configure::handler::ConfigureCommandController;
17-
use crate::presentation::controllers::constants::DEFAULT_LOCK_TIMEOUT;
18-
use crate::presentation::input::cli::OutputFormat;
19-
use crate::presentation::views::testing::TestUserOutput;
20-
use crate::presentation::views::{UserOutput, VerbosityLevel};
15+
use crate::presentation::cli::controllers::configure;
16+
use crate::presentation::cli::controllers::configure::handler::ConfigureCommandController;
17+
use crate::presentation::cli::controllers::constants::DEFAULT_LOCK_TIMEOUT;
18+
use crate::presentation::cli::input::cli::OutputFormat;
19+
use crate::presentation::cli::views::testing::TestUserOutput;
20+
use crate::presentation::cli::views::{UserOutput, VerbosityLevel};
2121
use crate::shared::clock::Clock;
2222
use crate::shared::SystemClock;
2323

src/presentation/controllers/constants.rs renamed to src/presentation/cli/controllers/constants.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
//! ## Usage Example
1919
//!
2020
//! ```rust
21-
//! use torrust_tracker_deployer_lib::presentation::controllers::constants::{DEFAULT_LOCK_TIMEOUT, DEFAULT_VERBOSITY};
21+
//! use torrust_tracker_deployer_lib::presentation::cli::controllers::constants::{DEFAULT_LOCK_TIMEOUT, DEFAULT_VERBOSITY};
2222
//! use torrust_tracker_deployer_lib::infrastructure::persistence::repository_factory::RepositoryFactory;
23-
//! use torrust_tracker_deployer_lib::presentation::views::UserOutput;
23+
//! use torrust_tracker_deployer_lib::presentation::cli::views::UserOutput;
2424
//!
2525
//! // Use default lock timeout for repository operations
2626
//! let repository_factory = RepositoryFactory::new(DEFAULT_LOCK_TIMEOUT);
@@ -31,7 +31,7 @@
3131
3232
use std::time::Duration;
3333

34-
use crate::presentation::views::VerbosityLevel;
34+
use crate::presentation::cli::views::VerbosityLevel;
3535

3636
/// Default timeout for file lock operations in repository
3737
///
File renamed without changes.

src/presentation/controllers/create/mod.rs renamed to src/presentation/cli/controllers/create/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
//! ```ignore
2424
//! use std::path::{Path, PathBuf};
2525
//! use std::sync::{Arc, Mutex};
26-
//! use torrust_tracker_deployer_lib::presentation::input::cli::commands::CreateAction;
27-
//! use torrust_tracker_deployer_lib::presentation::controllers::create;
28-
//! use torrust_tracker_deployer_lib::presentation::dispatch::ExecutionContext;
26+
//! use torrust_tracker_deployer_lib::presentation::cli::input::cli::commands::CreateAction;
27+
//! use torrust_tracker_deployer_lib::presentation::cli::controllers::create;
28+
//! use torrust_tracker_deployer_lib::presentation::cli::dispatch::ExecutionContext;
2929
//!
3030
//! # #[tokio::main]
3131
//! # async fn main() {

0 commit comments

Comments
 (0)