Skip to content

Commit 8a84515

Browse files
committed
docs: create issue specification for environment show command
- Create issue specification in docs/issues/241-implement-environment-show-command.md - Add issue link to roadmap task 5.1 - Add 'runnability' to project dictionary - GitHub issue #241 created and updated with correct file path
1 parent f12ff10 commit 8a84515

File tree

3 files changed

+401
-1
lines changed

3 files changed

+401
-1
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
# Implement Environment Show Command
2+
3+
**Issue**: #241
4+
**Parent Epic**: N/A (Part of Roadmap Section 5: "Add extra console app commands")
5+
**Related**:
6+
7+
- Roadmap #1 - Task 5.1
8+
- Feature Specification: [docs/features/environment-status-command/](../features/environment-status-command/)
9+
10+
## Overview
11+
12+
Implement a new console command `show` that displays environment information with state-aware details. The command provides a read-only view of stored environment data without remote verification, making it fast and reliable for users to inspect their deployment state.
13+
14+
This command displays different information based on the environment's current state (Created, Provisioned, Configured, Released, Running) and provides next-step guidance to help users understand what actions to take.
15+
16+
## Goals
17+
18+
- [ ] Provide console command to display environment information
19+
- [ ] Show state-aware details (different information per state)
20+
- [ ] Use human-friendly output formatting with UserOutput
21+
- [ ] Handle errors gracefully with actionable messages
22+
- [ ] Maintain fast execution (< 100ms for typical environments)
23+
- [ ] Ensure comprehensive test coverage (unit + E2E)
24+
25+
## 🏗️ Architecture Requirements
26+
27+
**DDD Layers**: Application + Presentation
28+
29+
**Module Paths**:
30+
31+
- `src/application/commands/show/` (command handler, DTOs, errors, formatter)
32+
- `src/presentation/input/cli/subcommands/show.rs` (CLI interface)
33+
34+
**Patterns**:
35+
36+
- Application Layer: Command Handler pattern
37+
- Presentation Layer: CLI Subcommand pattern
38+
- Data Transfer: DTO pattern (EnvironmentInfo, InfrastructureInfo, ServicesInfo)
39+
40+
### Module Structure Requirements
41+
42+
- [ ] Follow DDD layer separation (see [docs/codebase-architecture.md](../codebase-architecture.md))
43+
- [ ] Application layer handles business logic (loading, extraction, formatting)
44+
- [ ] Presentation layer handles CLI input/output only
45+
- [ ] No direct infrastructure dependencies (use existing EnvironmentLoader)
46+
- [ ] Use appropriate module organization (see [docs/contributing/module-organization.md](../contributing/module-organization.md))
47+
- [ ] Follow import conventions (imports first, prefer imports over full paths)
48+
49+
### Architectural Constraints
50+
51+
- [ ] **CRITICAL**: All output through UserOutput - **NEVER use `println!`, `eprintln!`, or direct stdio** (see [docs/contributing/output-handling.md](../contributing/output-handling.md))
52+
- [ ] No business logic in presentation layer (only CLI argument parsing and dispatch)
53+
- [ ] Error handling with explicit enum types (not anyhow) - see [docs/contributing/error-handling.md](../contributing/error-handling.md)
54+
- [ ] Read-only operation - no state modifications
55+
- [ ] No remote network calls (displays stored data only)
56+
- [ ] Testing strategy: unit tests at each phase + E2E test evolution
57+
58+
### Anti-Patterns to Avoid
59+
60+
-**Direct `println!`/`eprintln!` usage** (must use UserOutput)
61+
- ❌ Business logic in CLI subcommand
62+
- ❌ Using anyhow instead of explicit error enums
63+
- ❌ Remote verification/health checks (out of scope - use `test` command)
64+
- ❌ Batching test completions (mark complete immediately after each phase)
65+
66+
## Specifications
67+
68+
### Command Interface
69+
70+
**Command Name**: `show` (not `status` - reserves that for future service health checks)
71+
72+
**Usage**:
73+
74+
```bash
75+
torrust-tracker-deployer show <environment-name>
76+
```
77+
78+
**Example**:
79+
80+
```bash
81+
torrust-tracker-deployer show my-environment
82+
```
83+
84+
### Output Format by State
85+
86+
#### Created State
87+
88+
```text
89+
Environment: my-environment
90+
State: Created
91+
Provider: LXD
92+
93+
The environment configuration is ready. Run 'provision' to create infrastructure.
94+
```
95+
96+
#### Provisioned State
97+
98+
```text
99+
Environment: my-environment
100+
State: Provisioned
101+
Provider: LXD
102+
103+
Infrastructure:
104+
Instance IP: 10.140.190.14
105+
SSH Port: 22
106+
SSH User: ubuntu
107+
SSH Key: /home/user/.ssh/torrust_deployer_key
108+
109+
Connection:
110+
ssh -i /home/user/.ssh/torrust_deployer_key [email protected]
111+
112+
Next step: Run 'configure' to set up the system.
113+
```
114+
115+
#### Running State
116+
117+
```text
118+
Environment: my-environment
119+
State: Running
120+
Provider: Hetzner Cloud
121+
122+
Infrastructure:
123+
Instance IP: 157.10.23.45
124+
SSH Port: 22
125+
SSH User: root
126+
127+
Tracker Services:
128+
UDP Trackers:
129+
- udp://157.10.23.45:6868/announce
130+
- udp://157.10.23.45:6969/announce
131+
HTTP Tracker:
132+
- http://157.10.23.45:7070/announce
133+
- Health: http://157.10.23.45:7070/health_check
134+
API Endpoint:
135+
- http://157.10.23.45:1212/api
136+
- Health: http://157.10.23.45:1212/api/health_check
137+
138+
Status: ✓ All services running
139+
```
140+
141+
### Data Transfer Objects
142+
143+
**EnvironmentInfo**:
144+
145+
```rust
146+
pub struct EnvironmentInfo {
147+
pub name: String,
148+
pub state: EnvironmentState,
149+
pub provider: String,
150+
pub created_at: Option<String>,
151+
pub infrastructure: Option<InfrastructureInfo>,
152+
pub services: Option<ServicesInfo>,
153+
pub next_step: String,
154+
}
155+
```
156+
157+
**InfrastructureInfo**:
158+
159+
```rust
160+
pub struct InfrastructureInfo {
161+
pub instance_ip: IpAddr,
162+
pub ssh_port: u16,
163+
pub ssh_user: String,
164+
pub ssh_key_path: String,
165+
}
166+
```
167+
168+
**ServicesInfo**:
169+
170+
```rust
171+
pub struct ServicesInfo {
172+
pub udp_trackers: Vec<url::Url>,
173+
pub http_tracker: Option<url::Url>,
174+
pub http_tracker_health: Option<url::Url>,
175+
pub api_endpoint: Option<url::Url>,
176+
pub api_health: Option<url::Url>,
177+
}
178+
```
179+
180+
### Error Handling
181+
182+
**ShowCommandError** enum with explicit variants:
183+
184+
```rust
185+
#[derive(Debug, thiserror::Error)]
186+
pub enum ShowCommandError {
187+
#[error("Environment '{0}' not found")]
188+
EnvironmentNotFound(EnvironmentName),
189+
190+
#[error("Failed to load environment: {0}")]
191+
LoadError(#[from] EnvironmentLoadError),
192+
193+
#[error("Invalid environment state: {0}")]
194+
InvalidState(String),
195+
}
196+
```
197+
198+
All errors must include actionable messages guiding users on how to resolve the issue.
199+
200+
## Implementation Plan
201+
202+
### Phase 1: Presentation Layer - CLI Skeleton (1-2 hours)
203+
204+
- [ ] Create CLI subcommand in `src/presentation/input/cli/subcommands/show.rs`
205+
- [ ] Add `Show` variant to `Commands` enum in `src/presentation/input/cli/commands.rs`
206+
- [ ] Add command dispatch in `src/presentation/dispatch/mod.rs`
207+
- [ ] Add placeholder handler returning "Not implemented" message via UserOutput
208+
- [ ] Verify command appears in `--help` output
209+
- [ ] Create initial E2E test in `tests/e2e/commands/show_command.rs` (creates environment, runs show)
210+
- [ ] Manual CLI testing - command is runnable
211+
212+
**Result**: Command runnable from CLI with placeholder message. E2E test validates basic execution.
213+
214+
### Phase 2: Application Layer Foundation (2-3 hours)
215+
216+
- [ ] Create `ShowCommandHandler` in `src/application/commands/show/mod.rs`
217+
- [ ] Create `ShowCommandError` enum in `src/application/commands/show/error.rs`
218+
- [ ] Create `EnvironmentInfo` DTO in `src/application/commands/show/info.rs`
219+
- [ ] Implement environment loading with error handling (environment not found)
220+
- [ ] Extract basic info (name, state, provider) from environment
221+
- [ ] Display basic information via UserOutput (no println!/eprintln!)
222+
- [ ] Comprehensive unit tests for handler logic and error scenarios
223+
- [ ] Update E2E test to validate basic info display
224+
225+
**Result**: Command displays environment name, state, and provider.
226+
227+
### Phase 3: State-Aware Information Extraction (3-4 hours)
228+
229+
- [ ] Implement state-specific extraction using existing environment data
230+
- [ ] Add infrastructure details for Provisioned state (IP, SSH port, SSH user, SSH key path)
231+
- [ ] Handle missing runtime_outputs gracefully with clear errors
232+
- [ ] Extract service configuration for Running state from tracker config
233+
- [ ] Handle all environment states (Created, Configured, Released, Running, etc.)
234+
- [ ] Handle invalid/corrupted state data
235+
- [ ] Comprehensive unit tests for all states and edge cases
236+
- [ ] Update E2E test to validate state-specific details
237+
238+
**Result**: Command shows state-aware information for all environment states.
239+
240+
**Note**: Uses only data already in environment JSON - no new fields yet.
241+
242+
### Phase 4: Output Formatting (2-3 hours)
243+
244+
- [ ] Implement output formatter using UserOutput
245+
- [ ] Add state-aware formatting for each environment state
246+
- [ ] Include next-step guidance based on current state
247+
- [ ] Add visual improvements (colors, spacing, structured output)
248+
- [ ] Unit tests for formatting logic
249+
- [ ] Update E2E test to validate output formatting
250+
- [ ] Manual terminal testing
251+
252+
**Result**: Human-friendly, well-formatted output with next-step guidance.
253+
254+
### Phase 5: Testing Strategy Analysis and Documentation (2-3 hours)
255+
256+
- [ ] Analyze E2E testing strategies for different states:
257+
- **Strategy 1**: Call show in existing workflow tests after each state transition
258+
- **Strategy 2**: Mock internal state in dedicated E2E test
259+
- **Strategy 3**: Test different states via unit tests only (message formatting)
260+
- **Decision**: Use combination (Strategy 3 for formatting + Strategy 1 for E2E)
261+
- [ ] Implement chosen strategy
262+
- [ ] Add E2E tests for error scenarios (missing environment, corrupted data)
263+
- [ ] Verify test coverage meets requirements
264+
- [ ] Write user documentation in `docs/user-guide/commands/show.md`
265+
- [ ] Update `docs/console-commands.md` with show command
266+
- [ ] Update `docs/user-guide/commands.md` with command reference
267+
- [ ] Update `docs/roadmap.md` to mark task 5.1 as complete
268+
269+
**Result**: Complete test coverage and user documentation.
270+
271+
### Phase 6: Add Creation Timestamp (1-2 hours)
272+
273+
- [ ] Add `created_at` field to Environment domain model
274+
- [ ] Update environment JSON serialization to include timestamp
275+
- [ ] Update `create` command to populate creation timestamp
276+
- [ ] Update `show` command to display creation timestamp
277+
- [ ] Unit tests for timestamp persistence and display
278+
- [ ] Update E2E test to validate timestamp display
279+
280+
**Result**: Show command displays when environment was created.
281+
282+
**Note**: Extends domain model with new field. No backward compatibility needed (early development).
283+
284+
### Phase 7: Add Service URLs to RuntimeOutputs (2-3 hours)
285+
286+
- [ ] Add `service_endpoints` field to RuntimeOutputs domain model (`src/domain/environment/runtime_outputs.rs`)
287+
- [ ] Define `ServiceEndpoints` struct with `url::Url` fields (not String)
288+
- [ ] Update `run` command to populate service URLs after successful startup
289+
- [ ] Update `show` command to read from RuntimeOutputs (with fallback to construction)
290+
- [ ] Unit tests for ServiceEndpoints persistence and display
291+
- [ ] Update E2E test to validate service URLs display
292+
293+
**Result**: Service URLs stored in RuntimeOutputs and displayed in show command.
294+
295+
**Note**: Makes service URLs first-class deployment state, available to all commands.
296+
297+
## Acceptance Criteria
298+
299+
> **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.
300+
301+
**Quality Checks**:
302+
303+
- [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
304+
- All linters pass (markdown, yaml, toml, cspell, clippy, rustfmt, shellcheck)
305+
- All unit tests pass
306+
- Documentation builds successfully
307+
- E2E tests pass
308+
309+
**Functional Requirements**:
310+
311+
- [ ] Command displays environment name and state for all state types
312+
- [ ] Command shows IP, SSH port, SSH user, SSH key path for Provisioned+ states
313+
- [ ] Command includes ready-to-use SSH connection command
314+
- [ ] Command shows service URLs for Running state
315+
- [ ] Command provides next-step guidance based on state
316+
- [ ] Command handles missing environment with clear error + suggestion to use `list` command
317+
- [ ] Command handles invalid/corrupted data gracefully
318+
- [ ] Output is human-friendly and easy to read
319+
- [ ] Command execution is fast (< 100ms typical)
320+
321+
**Technical Requirements**:
322+
323+
- [ ] **All output via UserOutput** (no println!/eprintln!)
324+
- [ ] Follows DDD layer placement (Application + Presentation)
325+
- [ ] Error types use explicit enums (not anyhow)
326+
- [ ] Follows module organization conventions (public first, imports at top)
327+
- [ ] Follows import conventions (prefer imports over full paths)
328+
- [ ] Performance acceptable (< 100ms)
329+
330+
**Testing Requirements**:
331+
332+
- [ ] Unit tests cover ShowCommandHandler logic
333+
- [ ] Unit tests cover info extraction for all states
334+
- [ ] Unit tests cover output formatting
335+
- [ ] Unit tests cover all error scenarios and edge cases
336+
- [ ] Unit tests use behavior-driven naming (`it_should_*_when_*`)
337+
- [ ] E2E test validates Created environment
338+
- [ ] E2E test validates Provisioned environment
339+
- [ ] E2E test validates Running environment
340+
- [ ] E2E test validates error handling for missing environment
341+
- [ ] Test coverage includes missing data and invalid states
342+
343+
**Documentation Requirements**:
344+
345+
- [ ] Feature docs complete in `docs/features/environment-status-command/`
346+
- [ ] Show command section added to `docs/console-commands.md`
347+
- [ ] Command reference added to `docs/user-guide/commands.md`
348+
- [ ] Detailed guide created in `docs/user-guide/commands/show.md`
349+
- [ ] Roadmap updated (task 5.1 marked complete)
350+
- [ ] Inline code documentation (doc comments for public APIs)
351+
- [ ] Command help text complete (shows in `--help`)
352+
353+
**Code Quality**:
354+
355+
- [ ] No code duplication (DRY principle)
356+
- [ ] Clear separation of concerns (formatting vs logic vs presentation)
357+
- [ ] Meaningful variable and function names
358+
- [ ] Proper error context with actionable messages
359+
- [ ] Follows behavior-driven test naming (`it_should_*_when_*`, never `test_*`)
360+
361+
## Related Documentation
362+
363+
- **Feature Specification**: [docs/features/environment-status-command/specification.md](../features/environment-status-command/specification.md)
364+
- **Questions & Answers**: [docs/features/environment-status-command/questions.md](../features/environment-status-command/questions.md)
365+
- **Feature Overview**: [docs/features/environment-status-command/README.md](../features/environment-status-command/README.md)
366+
- **Codebase Architecture**: [docs/codebase-architecture.md](../codebase-architecture.md)
367+
- **Output Handling**: [docs/contributing/output-handling.md](../contributing/output-handling.md)
368+
- **Error Handling**: [docs/contributing/error-handling.md](../contributing/error-handling.md)
369+
- **Module Organization**: [docs/contributing/module-organization.md](../contributing/module-organization.md)
370+
- **Unit Testing Conventions**: [docs/contributing/testing/unit-testing.md](../contributing/testing/unit-testing.md)
371+
372+
## Notes
373+
374+
### Key Design Decisions
375+
376+
- **Command Name**: `show` (not `status`) - reserves `status` for future service health checks
377+
- **No Remote Verification**: Displays stored state only - infrastructure verification is in `test` command
378+
- **Clear Command Separation**:
379+
- `show` - Display stored data (fast, no network)
380+
- `test` - Verify infrastructure (cloud-init, Docker, Docker Compose)
381+
- `status` (future) - Check service health (connectivity, health endpoints)
382+
383+
### Development Approach
384+
385+
- **Top-Down Development**: Implement presentation layer first for immediate runnability
386+
- **E2E Test Evolution**: Create in Phase 1, update at each phase for continuous validation
387+
- **Unit Tests**: Write at every phase for code added/modified
388+
- **Incremental Progress**: Each phase produces working, testable command with more features
389+
390+
### Future Enhancements
391+
392+
- **JSON Output Format**: Can be added later with `--format json` flag
393+
- **Provider-Specific Details**: LXD container ID/profile, Hetzner server ID/datacenter/type
394+
395+
### Estimated Duration
396+
397+
**Total**: 14-22 hours (2-3 days) for complete implementation
398+
399+
**Target Completion**: January 2026

0 commit comments

Comments
 (0)