Skip to content

Commit 666149c

Browse files
committed
Merge #137: Add type-safe channel routing for UserOutput with newtype wrappers
d24db0a refactor: Improve encapsulation with writeln methods (copilot-swe-agent[bot]) 470d643 style: Apply rustfmt formatting (copilot-swe-agent[bot]) b49f0dd feat: Add type-safe channel routing with newtype wrappers (copilot-swe-agent[bot]) 5016d98 Initial plan (copilot-swe-agent[bot]) Pull request description: Channel routing (stdout vs stderr) in `UserOutput` was done via runtime pattern matching. This adds compile-time guarantees using newtype wrappers to prevent accidental channel confusion. ## Changes **Type-Safe Wrappers** (private) - `StdoutWriter` and `StderrWriter` newtypes wrapping `Box<dyn Write + Send + Sync>` - Methods: `new()`, `write_line()`, `writeln()` - Zero-cost abstraction via newtype pattern **UserOutput Structure** - Fields changed from `Box<dyn Write>` to typed wrappers (`stdout: StdoutWriter`, `stderr: StderrWriter`) - Private helpers `write_to_stdout()` and `write_to_stderr()` for type-safe dispatch - `write()` method now uses compile-time channel routing instead of runtime matching **Example** Before (runtime dispatch): ```rust let writer = match message.channel() { Channel::Stdout => &mut self.stdout_writer, Channel::Stderr => &mut self.stderr_writer, }; write!(writer, "{formatted}").ok(); ``` After (type-safe dispatch): ```rust match message.channel() { Channel::Stdout => self.write_to_stdout(&formatted), Channel::Stderr => self.write_to_stderr(&formatted), } ``` **Compatibility** - All existing tests pass without modification - Public API unchanged - Added 8 tests demonstrating compile-time safety > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `192.0.2.1` > - Triggering command: `ssh -i /nonexistent/key -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=5 testuser@192.0.2.1 echo &#39;SSH connected&#39;` (packet block) > - Triggering command: `ssh -i /nonexistent/key -p 22 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 testuser@192.0.2.1 echo &#39;SSH connected&#39;` (packet block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/torrust/torrust-tracker-deployer/settings/copilot/coding_agent) (admins only) > > </details> <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> ---- *This section details on the original issue you should resolve* <issue_title>Type-Safe Channel Routing for User Output</issue_title> <issue_description>## Overview Add compile-time type safety for channel routing (stdout vs stderr) in the `UserOutput` module by introducing newtype wrappers for writers. Currently, channel routing is done with runtime pattern matching which, while functional, doesn't provide compile-time guarantees that messages go to the correct channel. This refactoring introduces `StdoutWriter` and `StderrWriter` newtype wrappers that make channel routing explicit in the type system, preventing accidental channel confusion at compile time. ## Specification See detailed specification: [docs/issues/135-type-safe-channel-routing-for-user-output.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/issues/135-type-safe-channel-routing-for-user-output.md) ## 🏗️ Architecture Requirements **DDD Layer**: Presentation **Module Path**: `src/presentation/user_output.rs` **Pattern**: Type-safe wrappers using newtype pattern ### Module Structure Requirements - [ ] Follow module organization conventions (see [docs/contributing/module-organization.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/contributing/module-organization.md)) - [ ] Keep writer wrappers private as implementation details - [ ] Maintain public API compatibility with existing code ### Architectural Constraints - [ ] Zero-cost abstraction using newtype pattern - [ ] No runtime overhead compared to current implementation - [ ] Preserve existing error handling behavior - [ ] Error handling follows project conventions (see [docs/contributing/error-handling.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/contributing/error-handling.md)) ### Anti-Patterns to Avoid - ❌ Exposing writer wrappers in public API unnecessarily - ❌ Adding runtime checks when compile-time safety is available - ❌ Breaking existing test infrastructure ## Implementation Plan ### Phase 1: Create Newtype Wrappers (30 minutes) - [ ] Task 1.1: Create `StdoutWriter` newtype struct with documentation - [ ] Task 1.2: Create `StderrWriter` newtype struct with documentation - [ ] Task 1.3: Implement `new()` constructor for both wrappers - [ ] Task 1.4: Implement `write_line()` method for both wrappers - [ ] Task 1.5: Add unit tests for wrapper creation and writing ### Phase 2: Update UserOutput Structure (45 minutes) - [ ] Task 2.1: Update `UserOutput` struct fields to use typed wrappers - [ ] Task 2.2: Add private helper methods `write_to_stdout()` and `write_to_stderr()` - [ ] Task 2.3: Update all constructors to wrap writers in typed newtype - [ ] Task 2.4: Update `write()` method to use typed writer helpers - [ ] Task 2.5: Verify all existing public methods compile and work correctly ### Phase 3: Update Tests (30 minutes) - [ ] Task 3.1: Update test infrastructure to work with newtype wrappers - [ ] Task 3.2: Add tests for type-safe channel routing - [ ] Task 3.3: Verify all existing tests pass without modification - [ ] Task 3.4: Add test cases demonstrating compile-time safety benefits ### Phase 4: Documentation and Quality (30 minutes) - [ ] Task 4.1: Update module documentation to mention type-safe routing - [ ] Task 4.2: Add code examples showing type safety benefits - [ ] Task 4.3: Run pre-commit checks and fix any issues - [ ] Task 4.4: Verify documentation builds correctly ## Acceptance Criteria > **Note for Contributors**: These criteria define what the PR reviewer will check. Use this as your pre-review checklist before submitting the PR to minimize back-and-forth iterations. **Quality Checks**: - [ ] Pre-commit checks pass: `./scripts/pre-commit.sh` - [ ] All tests pass: `cargo test` - [ ] Documentation builds: `cargo doc --no-deps` **Task-Specific Criteria**: - [ ] `StdoutWriter` and `StderrWriter` newtype wrappers are implemented - [ ] Both wrappers have `new()` and `write_line()` methods - [ ] `UserOutput` struct uses typed wrappers instead of raw `Box<dyn Write>` - [ ] All constructors wrap raw writers in typed newtypes - [ ] Private helper methods `write_to_stdout()` and `write_to_stderr()` exist - [ ] The `write()` method uses typed helpers instead of direct writer access - [ ] All existing tests pass without modification - [ ] New tests demonstrate compile-time safety benefits - [ ] Module documentation is updated to reflect type-safe routing - [ ] Code examples show the benefits of the newtype pattern - [ ] No performance regression (zero-cost abstraction) - [ ] IDE autocomplete shows channel-specific methods ## Related - Parent: #102 (Epic: User Output Architecture Improvements) - Specification: docs/issues/135-type-safe-channel-routing-for-user-output.md - Refactoring Plan: [docs/refactors/plans/user-output-architecture-improvements.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/refactors/plans/use... </details> - Fixes #135 <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/torrust/torrust-tracker-deployer/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. ACKs for top commit: josecelano: ACK d24db0a Tree-SHA512: 9e916c8e7dfa799e9314bf7f0d8925cfd24d584c85ee395acf166f0a5d736867f2ead9f9dc3bea1c0359305f8ebaefe859c9a9c73a3e9835cd4f1bf278388c4b
2 parents b07f889 + d24db0a commit 666149c

File tree

1 file changed

+306
-38
lines changed

1 file changed

+306
-38
lines changed

0 commit comments

Comments
 (0)