Problem
The codebase evolved from bash scripts to Rust CLI, resulting in:
- Monolithic command functions that are hard to test in isolation
- Heavy coupling to external services (GitHub API, Docker, S3, etc.)
- Side effects scattered throughout (file I/O, network calls, command execution)
- Limited ability to test error conditions and edge cases
- No clear separation between business logic and I/O
Current State Analysis
Hard-to-test patterns:
- Commands directly instantiate external clients (Octocrab, ObjectStore, etc.)
- Business logic intertwined with I/O operations
- No dependency injection or trait-based abstractions
- Tests require real git repositories and cargo workspaces
- Parallel execution logic hard to test without real semaphores
Proposed Refactoring Strategy
Phase 1: Extract Core Business Logic
1.1 Create domain models
// src/domain/mod.rs
pub mod package; // Pure Package representations
pub mod dependency; // Dependency graph logic
pub mod change_set; // Changed packages computation
pub mod publish_plan; // What to publish, where, how
1.2 Define service traits
// src/services/traits.rs
pub trait GitService {
fn diff_files(&self, base: &str, head: &str) -> Result<Vec<PathBuf>>;
fn resolve_ref(&self, ref_name: &str) -> Result<String>;
}
pub trait GithubService {
async fn find_release(&self, tag: &str) -> Result<Option<Release>>;
async fn upload_asset(&self, release_id: u64, name: &str, data: Vec<u8>) -> Result<()>;
}
pub trait CargoRegistry {
async fn package_exists(&self, name: &str, version: &str) -> Result<bool>;
async fn publish(&self, package_path: &Path, registry: &str) -> Result<()>;
}
1.3 Implement production and test implementations
Phase 2: Refactor Commands to Use Services
Extract testable functions from monolithic commands. Split into:
- Pure planning functions (no I/O)
- Execution functions using service traits (testable with mocks)
Phase 3: Improve CrateGraph Testability
Make CrateGraph independent of git2 by extracting git operations to a trait.
Implementation Plan
Week 1-2: Foundation
Week 3-4: Refactor CrateGraph
Week 5-6: Refactor Publish Command
Week 7-8: Refactor Tests Command
Week 9-10: Remaining Commands
Success Metrics
Breaking Changes
- Internal refactoring only; CLI interface remains the same
- May need to update some internal imports if used by external consumers
Labels
refactoring, testing, priority:high
Problem
The codebase evolved from bash scripts to Rust CLI, resulting in:
Current State Analysis
Hard-to-test patterns:
Proposed Refactoring Strategy
Phase 1: Extract Core Business Logic
1.1 Create domain models
1.2 Define service traits
1.3 Implement production and test implementations
Phase 2: Refactor Commands to Use Services
Extract testable functions from monolithic commands. Split into:
Phase 3: Improve CrateGraph Testability
Make CrateGraph independent of git2 by extracting git operations to a trait.
Implementation Plan
Week 1-2: Foundation
src/domain/with core business modelssrc/services/traits.rssrc/testing/with test utilities and mocksWeek 3-4: Refactor CrateGraph
GitServicetraitCrateGraph::affected_packagesuse trait instead ofgit2::RepositoryWeek 5-6: Refactor Publish Command
publish/mod.rsto use servicesWeek 7-8: Refactor Tests Command
Week 9-10: Remaining Commands
check_workspace,fix_lock_files, etc.CommandContextSuccess Metrics
Breaking Changes
Labels
refactoring,testing,priority:high