1818//!
1919//! Add new fields here when: User needs to configure something at environment creation time.
2020
21- use std:: fmt;
22-
2321use serde:: { Deserialize , Serialize } ;
22+ use thiserror:: Error ;
2423
2524use crate :: adapters:: ssh:: SshCredentials ;
2625use crate :: domain:: environment:: EnvironmentName ;
@@ -35,45 +34,36 @@ use crate::domain::InstanceName;
3534///
3635/// These errors represent cross-service invariant violations that can only be
3736/// detected when considering multiple service configurations together.
38- #[ derive( Debug , Clone , PartialEq ) ]
37+ #[ derive( Debug , Clone , PartialEq , Error ) ]
3938pub enum UserInputsError {
4039 /// Grafana requires Prometheus to be configured as its data source
40+ ///
41+ /// Use `.help()` for detailed troubleshooting steps.
42+ #[ error(
43+ "Grafana requires Prometheus to be configured as its data source
44+ Tip: Add a 'prometheus' section or remove the 'grafana' section"
45+ ) ]
4146 GrafanaRequiresPrometheus ,
4247
4348 /// HTTPS section is defined but no service has TLS configured
49+ ///
50+ /// Use `.help()` for detailed troubleshooting steps.
51+ #[ error(
52+ "HTTPS section is defined but no service has TLS configured
53+ Tip: Set 'use_tls_proxy: true' on at least one service, or remove the 'https' section"
54+ ) ]
4455 HttpsSectionWithoutTlsServices ,
4556
4657 /// At least one service has TLS configured but HTTPS section is missing
58+ ///
59+ /// Use `.help()` for detailed troubleshooting steps.
60+ #[ error(
61+ "At least one service has TLS configured but HTTPS section is missing
62+ Tip: Add an 'https' section with 'admin_email' for Let's Encrypt certificate management"
63+ ) ]
4764 TlsServicesWithoutHttpsSection ,
4865}
4966
50- impl fmt:: Display for UserInputsError {
51- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
52- match self {
53- Self :: GrafanaRequiresPrometheus => {
54- write ! (
55- f,
56- "Grafana requires Prometheus to be configured as its data source"
57- )
58- }
59- Self :: HttpsSectionWithoutTlsServices => {
60- write ! (
61- f,
62- "HTTPS section is defined but no service has TLS configured"
63- )
64- }
65- Self :: TlsServicesWithoutHttpsSection => {
66- write ! (
67- f,
68- "At least one service has TLS configured but HTTPS section is missing"
69- )
70- }
71- }
72- }
73- }
74-
75- impl std:: error:: Error for UserInputsError { }
76-
7767impl UserInputsError {
7868 /// Provides actionable help text for fixing the error
7969 #[ must_use]
@@ -697,18 +687,26 @@ mod tests {
697687
698688 #[ test]
699689 fn it_should_provide_helpful_error_messages ( ) {
700- assert_eq ! (
701- UserInputsError :: GrafanaRequiresPrometheus . to_string( ) ,
702- "Grafana requires Prometheus to be configured as its data source"
703- ) ;
690+ assert ! ( UserInputsError :: GrafanaRequiresPrometheus
691+ . to_string( )
692+ . contains( "Grafana requires Prometheus" ) ) ;
693+ assert ! ( UserInputsError :: GrafanaRequiresPrometheus
694+ . to_string( )
695+ . contains( "Tip:" ) ) ;
704696 assert ! ( UserInputsError :: GrafanaRequiresPrometheus
705697 . help( )
706698 . contains( "prometheus" ) ) ;
707699
700+ assert ! ( UserInputsError :: HttpsSectionWithoutTlsServices
701+ . to_string( )
702+ . contains( "Tip:" ) ) ;
708703 assert ! ( UserInputsError :: HttpsSectionWithoutTlsServices
709704 . help( )
710705 . contains( "use_tls_proxy" ) ) ;
711706
707+ assert ! ( UserInputsError :: TlsServicesWithoutHttpsSection
708+ . to_string( )
709+ . contains( "Tip:" ) ) ;
712710 assert ! ( UserInputsError :: TlsServicesWithoutHttpsSection
713711 . help( )
714712 . contains( "https" ) ) ;
0 commit comments