Skip to content

feat: add JSON output to register command (12.13) #396#397

Merged
josecelano merged 1 commit into
mainfrom
396-add-json-output-to-register-command
Feb 27, 2026
Merged

feat: add JSON output to register command (12.13) #396#397
josecelano merged 1 commit into
mainfrom
396-add-json-output-to-register-command

Conversation

@josecelano

Copy link
Copy Markdown
Member

Description

Implements JSON output support for the register command, closing #396.

Follows the same Strategy Pattern used for all previous commands in epic #348.

Changes

New files

  • src/presentation/cli/views/commands/register/mod.rs — module root with re-exports
  • src/presentation/cli/views/commands/register/view_data/register_details.rsRegisterDetailsData DTO
  • src/presentation/cli/views/commands/register/views/json_view.rs — JSON renderer
  • src/presentation/cli/views/commands/register/views/text_view.rs — text renderer

Modified files

  • src/presentation/cli/views/commands/mod.rs — added pub mod register
  • src/presentation/cli/controllers/register/handler.rsexecute() now takes output_format: OutputFormat; complete_workflow() takes &Environment<Provisioned> and dispatches to the correct view
  • src/presentation/cli/dispatch/router.rs — passes context.output_format() to execute()

JSON Output Format

{
  "environment_name": "my-env",
  "instance_ip": "192.168.1.100",
  "ssh_port": 22,
  "registered": true
}

Testing

  • All 431 unit/doc tests pass
  • All linters pass (cargo run --bin linter all)

Related

- Add RegisterDetailsData DTO with environment_name, instance_ip, ssh_port, registered fields
- Add JsonView and TextView strategy renderers for register command
- Add output_format parameter to RegisterCommandController::execute()
- Update complete_workflow() to use Environment<Provisioned> and dispatch to correct view
- Pass output_format from dispatch router to register controller
- All linters pass, 431 tests pass
@josecelano josecelano requested a review from Copilot February 27, 2026 09:03
@josecelano josecelano self-assigned this Feb 27, 2026
@josecelano

Copy link
Copy Markdown
Member Author

ACK 10d304a

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds JSON output support to the register CLI command as part of the ongoing “JSON output for all commands” epic, using the same view/DTO strategy pattern used by other commands.

Changes:

  • Introduces RegisterDetailsData DTO plus TextView and JsonView renderers for register.
  • Updates RegisterCommandController::execute() to accept output_format and dispatch rendering accordingly.
  • Updates the CLI router to pass context.output_format() into the register controller.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/presentation/cli/views/commands/register/mod.rs Adds the register views module root and re-exports DTO/views.
src/presentation/cli/views/commands/register/view_data/register_details.rs Adds RegisterDetailsData DTO + constructor from Environment<Provisioned>.
src/presentation/cli/views/commands/register/views/json_view.rs Adds JSON rendering for register output.
src/presentation/cli/views/commands/register/views/text_view.rs Adds text rendering to preserve prior register output format.
src/presentation/cli/views/commands/mod.rs Exposes the new register views module.
src/presentation/cli/controllers/register/handler.rs Adds output_format to execute() and renders via TextView/JsonView.
src/presentation/cli/dispatch/router.rs Passes context.output_format() into the register controller.

environment_name: env.name().to_string(),
instance_ip: env
.instance_ip()
.map_or_else(String::new, |ip| ip.to_string()),

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instance_ip() is optional, but here it’s converted to an empty string when missing. For the register success path the IP should be present (provided by the user and set during the Created→Provisioned transition), and emitting "" can silently violate the expected JSON contract. Consider treating None as an internal invariant violation (e.g., expect with a clear message) or representing absence explicitly in the DTO (e.g., Option<IpAddr>/Option<String>) and reflecting that in the JSON view.

Suggested change
.map_or_else(String::new, |ip| ip.to_string()),
.expect("Provisioned environment must have an instance IP on register success path")
.to_string(),

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +99
// The constructor only produces RegisterDetailsData on the success path.
// We verify the field directly since we cannot construct Environment<Provisioned>
// without full infrastructure in a unit test.
let data = RegisterDetailsData {

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests don’t cover RegisterDetailsData::from_environment(), and the comment suggests Environment<Provisioned> can’t be constructed in a unit test. The domain state machine provides Environment<Created>::register(ip) -> Environment<Provisioned>, so it should be possible to build a minimal environment and assert the DTO mapping (env name, instance_ip, ssh_port, registered) is correct.

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +95
format!(
r#"{{
"error": "Failed to serialize register details",
"message": "{e}"
}}"#
)

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unwrap_or_else fallback interpolates the error {e} directly into a JSON string. If the message contains quotes, backslashes, or newlines, this fallback can produce invalid JSON. To guarantee valid JSON even on the error path, build the error object with serde_json (e.g., serde_json::json! + to_string_pretty) so the message is properly escaped.

Suggested change
format!(
r#"{{
"error": "Failed to serialize register details",
"message": "{e}"
}}"#
)
serde_json::to_string_pretty(&serde_json::json!({
"error": "Failed to serialize register details",
"message": e.to_string(),
}))
.unwrap_or_else(|_| {
r#"{
"error": "Failed to serialize error message"
}"#
.to_string()
})

Copilot uses AI. Check for mistakes.
@josecelano josecelano merged commit 0e95725 into main Feb 27, 2026
37 checks passed
josecelano added a commit that referenced this pull request Feb 27, 2026
…alid JSON

Replace unsafe format!() string interpolation of error messages with
serde_json::json! construction in all JsonView::render() error fallbacks.

The previous format!(r#"{{ "message": "{e}" }}"#) approach would
produce invalid JSON if the error message contained quotes, backslashes,
or newlines. Using serde_json::json! ensures the message is always
properly escaped.

Applies to 11 json_view.rs files:
- configure, release, render, destroy, purge, test, register, validate,
  list, run, show

Reported by Copilot review on PR #397.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add JSON output to register command (12.13)

2 participants