Commit e813fe2
committed
Merge #94: Add ProgressReporter for multi-step command operations
7112dfb style: apply cargo fmt formatting (copilot-swe-agent[bot])
efe20cc feat: integrate ProgressReporter with create and destroy commands (copilot-swe-agent[bot])
7705383 feat: add ProgressReporter for long-running operations (copilot-swe-agent[bot])
90ae761 Initial plan (copilot-swe-agent[bot])
Pull request description:
Commands previously provided no progress feedback during long-running operations, leaving users unable to distinguish between stuck and actively processing operations.
## Changes
### Core Implementation
- **`ProgressReporter`** (`src/presentation/progress.rs`): New abstraction for standardized progress tracking with step numbering, timing, and sub-step support. Wraps `UserOutput` and maintains step state.
- **`CommandContext.into_output()`**: Enables consuming context to extract `UserOutput` for ownership transfer to `ProgressReporter`.
### Command Integration
- **Create command**: 3-step progression (load config → initialize → create environment) with timing per step
- **Destroy command**: 3-step progression (validate → initialize → tear down) with timing per step
## Output Format
```
⏳ [1/3] Loading configuration...
✓ Configuration loaded: demo-env (took 150ms)
⏳ [2/3] Initializing dependencies...
✓ Done (took 23ms)
⏳ [3/3] Creating environment...
→ Creating virtual machine
→ Configuring network
✓ Instance created: vm-demo-env (took 2.3s)
✅ Environment 'demo-env' created successfully
```
Duration formatting: `<1s` shown as milliseconds, `≥1s` shown as seconds with one decimal place.
## Testing
12 unit tests for `ProgressReporter` covering step tracking, timing, sub-steps, and verbosity handling. All existing command tests (15 total) updated and passing.
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
----
*This section details on the original issue you should resolve*
<issue_title>Add Progress Reporter for Long-Running Operations</issue_title>
<issue_description>**Parent Issue**: #63
**Type**: 🚀 Advanced Pattern
**Impact**: 🟢🟢 Medium
**Effort**: 🔵🔵🔵 High
**Priority**: P2
## Problem
Commands currently have no mechanism to report progress during long-running operations:
- Users see no feedback during lengthy operations
- No indication of current step or overall progress
- Hard to know if the operation is stuck or progressing
- Poor user experience for operations that take minutes
Current behavior:
```rust
output.progress("Creating environment...");
// Long operation happens with no updates
// User sees nothing until completion
output.success("Environment created!");
```
## Proposed Solution
Create a `ProgressReporter` abstraction for standardized progress reporting:
```rust
//! Progress Reporting for Long-Running Operations
use std::time::{Duration, Instant};
/// Progress reporter for multi-step operations
pub struct ProgressReporter {
output: UserOutput,
total_steps: usize,
current_step: usize,
step_start: Option<Instant>,
}
impl ProgressReporter {
pub fn new(output: UserOutput, total_steps: usize) -> Self {
Self {
output,
total_steps,
current_step: 0,
step_start: None,
}
}
/// Start a new step with a description
pub fn start_step(&mut self, description: &str) {
self.current_step += 1;
self.step_start = Some(Instant::now());
self.output.progress(&format!(
"[{}/{}] {}...",
self.current_step,
self.total_steps,
description
));
}
/// Complete the current step with optional result message
pub fn complete_step(&mut self, result: Option<&str>) {
if let Some(start) = self.step_start {
let duration = start.elapsed();
if let Some(msg) = result {
self.output.result(&format!(
" ✓ {} (took {:?})",
msg,
duration
));
} else {
self.output.result(&format!(" ✓ Done (took {:?})", duration));
}
}
self.step_start = None;
}
/// Report a sub-step within the current step
pub fn sub_step(&mut self, description: &str) {
self.output.info(&format!(" → {}", description));
}
/// Complete all steps and show summary
pub fn complete(&mut self, summary: &str) {
self.output.success(summary);
}
}
```
Then use in command handlers:
```rust
pub fn handle_environment_creation(env_file: &Path, working_dir: &Path)
-> Result<(), CreateSubcommandError>
{
let output = output::create_default();
let mut progress = ProgressReporter::new(output, 5);
// Step 1: Load configuration
progress.start_step("Loading configuration");
let config = load_configuration(env_file)?;
progress.complete_step(Some(&format!("Configuration loaded: {}", config.environment.name)));
// Step 2: Create dependencies
progress.start_step("Initializing dependencies");
let context = CommandContext::new(working_dir.to_path_buf());
progress.complete_step(None);
// Step 3: Validate environment
progress.start_step("Validating environment");
validate_environment(&config)?;
progress.complete_step(Some("Environment is valid"));
// Step 4: Provision infrastructure
progress.start_step("Provisioning infrastructure");
progress.sub_step("Creating virtual machine");
progress.sub_step("Configuring network");
let instance = provision_infrastructure(&config)?;
progress.complete_step(Some(&format!("Instance created: {}", instance.name)));
// Step 5: Finalize
progress.start_step("Finalizing environment");
let environment = finalize_environment(config, instance)?;
progress.complete_step(None);
progress.complete(&format!(
"Environment '{}' created successfully",
environment.name()
));
Ok(())
}
```
## Benefits
- ✅ Clear progress feedback for users
- ✅ Shows current step and overall progress
- ✅ Reports timing for each step
- ✅ Consistent progress reporting across commands
- ✅ Better user experience for long operations
- ✅ Helps identify slow steps
## Implementation Checklist
**Phase 1: Create progress reporter**
- [ ] Create `src/presentation/progress.rs`
- [ ] Implement `ProgressReporter` struct
- [ ] Add `new()` constructor
- [ ] Add `start_step()` method
- [ ] Add `complete_step()` method
- [ ] Add `sub_step()` method
- [ ] Add `complete()` method
- [ ] Add comprehensive documentation
- [ ] Write unit tests
**Phase 2: Integrate with create command**
- [ ] Identify steps in environment creation
- [ ] Add progress reporting to each step
- [ ] Test with real operations
- [ ...
</details>
- Fixes #73
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
ACKs for top commit:
josecelano:
ACK 7112dfb
Tree-SHA512: 3283d6bcb5a135d09cd2c7ac2617d90fbc8e483ae48af03b751afe4805cfa0b15427dfb8d6d2d2ebd5a7afe789db74f3b09e37b2d851e0428feadd74e297d1785 files changed
Lines changed: 596 additions & 28 deletions
File tree
- src/presentation
- commands
- create/subcommands
- destroy
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
254 | 254 | | |
255 | 255 | | |
256 | 256 | | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
257 | 277 | | |
258 | 278 | | |
259 | 279 | | |
| |||
Lines changed: 37 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
19 | | - | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
24 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | | - | |
| 28 | + | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
| |||
47 | 49 | | |
48 | 50 | | |
49 | 51 | | |
50 | | - | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
51 | 56 | | |
52 | 57 | | |
53 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
54 | 64 | | |
55 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
56 | 68 | | |
57 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
58 | 84 | | |
59 | | - | |
60 | | - | |
| 85 | + | |
| 86 | + | |
61 | 87 | | |
62 | 88 | | |
63 | 89 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
15 | 16 | | |
16 | | - | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| |||
53 | 55 | | |
54 | 56 | | |
55 | 57 | | |
56 | | - | |
| 58 | + | |
57 | 59 | | |
58 | | - | |
59 | | - | |
60 | | - | |
| 60 | + | |
| 61 | + | |
61 | 62 | | |
62 | | - | |
| 63 | + | |
| 64 | + | |
63 | 65 | | |
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
68 | | - | |
| 70 | + | |
69 | 71 | | |
70 | 72 | | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
71 | 76 | | |
72 | | - | |
73 | | - | |
74 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
75 | 80 | | |
| 81 | + | |
76 | 82 | | |
77 | | - | |
| 83 | + | |
| 84 | + | |
78 | 85 | | |
79 | 86 | | |
80 | 87 | | |
81 | 88 | | |
82 | 89 | | |
83 | | - | |
| 90 | + | |
84 | 91 | | |
85 | 92 | | |
| 93 | + | |
86 | 94 | | |
87 | | - | |
88 | | - | |
| 95 | + | |
| 96 | + | |
89 | 97 | | |
90 | 98 | | |
91 | 99 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
44 | 45 | | |
45 | 46 | | |
46 | 47 | | |
| |||
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| 53 | + | |
52 | 54 | | |
0 commit comments