Skip to content

refactor: improve release handler code organization and reduce duplication#305

Merged
josecelano merged 12 commits into
mainfrom
refactor-release-handler
Jan 26, 2026
Merged

refactor: improve release handler code organization and reduce duplication#305
josecelano merged 12 commits into
mainfrom
refactor-release-handler

Conversation

@josecelano
Copy link
Copy Markdown
Member

Summary

This PR refactors the release command handler to improve code organization, reduce duplication, and enhance maintainability.

Changes

Module Reorganization

  • Extract service-specific steps into dedicated modules under steps/:
    • tracker.rs - Tracker service release steps
    • prometheus.rs - Prometheus service release steps
    • grafana.rs - Grafana service release steps
    • mysql.rs - MySQL service release steps
    • caddy.rs - Caddy service release steps
    • compose.rs - Docker Compose deployment steps
    • common.rs - Shared utilities (ansible client factory)

Workflow Extraction

  • Extract release workflow to dedicated module (workflow.rs) - Separates orchestration logic from handler state management

Code Quality Improvements

  • Remove instance_ip parameter from workflow - The IP is now obtained from the environment object within each step, reducing coupling
  • Move service availability checks to release() functions - Eliminates repetitive conditional checks in every step function (~90 lines removed)
  • Improve workflow module readability - Use explicit imports and remove redundant comments

Benefits

  1. Better separation of concerns: Each service has its own module with clear responsibilities
  2. Reduced duplication: Service availability checks now happen once per service, not per step
  3. Improved testability: Smaller, focused modules are easier to test in isolation
  4. Enhanced maintainability: Changes to one service don't affect others
  5. Clearer control flow: The main release() function in each module shows the complete service workflow

Testing

  • All pre-commit checks pass
  • E2E tests pass (both infrastructure lifecycle and deployment workflow tests)
  • Documentation builds successfully

- Convert all step-related error variants from tuple String to struct with
  message and source fields using BoxedStepError (Box<dyn Error>)
- Add module-level documentation explaining the boxed error design decision
- Replace generic Deployment/DeploymentFailed variants with specific:
  TrackerConfigDeployment, GrafanaProvisioningDeployment,
  PrometheusConfigDeployment, ComposeFilesDeployment
- Update Traceable impl, error_kind(), and help() for new variants
- Update handler.rs to construct errors with both message and source
- Update tests to use struct variant syntax with helper function

Trade-off: Using Box<dyn Error> loses pattern matching on source type,
but enables uniform error handling for 15+ heterogeneous step error types
and preserves error messages for debugging.
Reorganized the release command handler by extracting step implementations
into a dedicated steps/ subdirectory organized by service:

- steps/tracker.rs: tracker service release steps
- steps/prometheus.rs: prometheus service steps (optional)
- steps/grafana.rs: grafana service steps (optional)
- steps/mysql.rs: mysql service steps (optional)
- steps/caddy.rs: caddy service steps (HTTPS)
- steps/compose.rs: docker compose deployment (async)
- steps/common.rs: shared utilities (ansible_client helper)

Each module only exposes its release() function publicly, with individual
step implementations remaining private. This improves code organization
and encapsulation while reducing handler.rs from 1114 to 291 lines (~74%).
Moved execute_release_workflow to a new workflow.rs module, separating:
- handler.rs: State management, persistence, error handling
- workflow.rs: Orchestrates step execution in correct order

This makes the workflow a stateless free function that coordinates
step calls, while the handler focuses on state transitions and persistence.
- Use explicit imports for step modules (tracker, prometheus, etc.)
- Remove redundant inline comments since code is self-explanatory
- Simplify doc comment to avoid duplicating individual module docs
- Inline return value for conciseness
The instance_ip is now obtained from the environment object within
each step, rather than being passed as a parameter. This simplifies
the function signatures and reduces coupling.

- Remove instance_ip param from workflow::execute()
- Remove instance_ip param from compose::release() and deploy_files_to_remote()
- Update compose logging to use environment.instance_ip()
- Keep instance_ip validation in handler for early error detection
Move the conditional checks for optional services (MySQL, Caddy,
Prometheus, Grafana) from individual step functions to the main
release() function in each module. This eliminates repetitive checks
in every step and makes the control flow clearer.

- mysql.rs: Check uses_mysql() once in release()
- caddy.rs: Check https().is_none() once in release()
- prometheus.rs: Check prometheus().is_none() once in release()
- grafana.rs: Check grafana().is_none() in release(), with secondary
  prometheus check after storage creation (since only provisioning
  requires Prometheus for datasource)
The analysis document was used during the refactoring process and
is no longer needed now that the improvements have been implemented.
@josecelano josecelano self-assigned this Jan 26, 2026
@josecelano
Copy link
Copy Markdown
Member Author

ACK 45588ce

@josecelano josecelano merged commit 5fd6991 into main Jan 26, 2026
43 of 49 checks passed
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.

1 participant