Skip to main content

ralph_workflow/config/
mod.rs

1//! Configuration Module
2//!
3//! Handles environment variables and configuration for Ralph.
4//!
5//! # Key Types
6//!
7//! - [`Config`] - Runtime configuration used during pipeline execution
8//! - [`Verbosity`] - Output verbosity levels (Quiet, Normal, Verbose, Full, Debug)
9//! - [`ReviewDepth`] - Review thoroughness (Standard, Comprehensive, Security, Incremental)
10//! - [`UnifiedConfig`] - Full configuration file representation
11//!
12//! # Configuration Sources
13//!
14//! Ralph configuration is loaded from (in order of priority):
15//!
16//! 1. `~/.config/ralph-workflow.toml` (global config)
17//! 2. `.agent/ralph-workflow.toml` (local config, overrides global)
18//! 3. Environment variables (`RALPH_*`) as overrides
19//! 4. CLI arguments (final override)
20//!
21//! # Module Structure
22//!
23//! - [`types`] - Core configuration types (Config, `ReviewDepth`, Verbosity)
24//! - [`cloud`] - Cloud and git remote configuration types
25//! - [`truncation`] - Truncation limits for verbosity levels
26//! - [`parser`] - Environment variable parsing (legacy)
27//! - [`unified`] - Unified configuration format types
28//! - [`loader`] - Unified configuration loader with env overrides
29//! - [`path_resolver`] - Configuration path resolution with dependency injection
30
31pub mod cloud;
32pub mod loader;
33pub mod parser;
34pub mod path_resolver;
35pub mod truncation;
36pub mod types;
37pub mod unified;
38pub mod validation;
39
40// Re-export main types at module level for convenience
41pub use cloud::{
42    CloudConfig, CloudStateConfig, GitAuthMethod, GitAuthStateMethod, GitRemoteConfig,
43    GitRemoteStateConfig,
44};
45pub use types::{Config, ReviewDepth, Verbosity};
46
47// Re-export unified config types for --init-global handling
48pub use unified::{
49    unified_config_path, CcsAliasConfig, CcsConfig, ConfigInitResult as UnifiedConfigInitResult,
50    UnifiedConfig,
51};
52
53// Re-export config environment types for dependency injection
54pub use path_resolver::{ConfigEnvironment, MemoryConfigEnvironment, RealConfigEnvironment};
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_verbosity_from_u8() {
62        assert_eq!(Verbosity::from(0), Verbosity::Quiet);
63        assert_eq!(Verbosity::from(1), Verbosity::Normal);
64        assert_eq!(Verbosity::from(2), Verbosity::Verbose);
65        assert_eq!(Verbosity::from(3), Verbosity::Full);
66        assert_eq!(Verbosity::from(4), Verbosity::Debug);
67        assert_eq!(Verbosity::from(100), Verbosity::Debug);
68    }
69
70    #[test]
71    fn test_truncate_limits() {
72        // Quiet has reduced limits
73        assert_eq!(Verbosity::Quiet.truncate_limit("text"), 80);
74        assert_eq!(Verbosity::Quiet.truncate_limit("tool_input"), 40);
75
76        // Normal has conservative limits for manageable output
77        assert_eq!(Verbosity::Normal.truncate_limit("text"), 1000);
78        assert_eq!(Verbosity::Normal.truncate_limit("tool_input"), 300);
79        assert_eq!(Verbosity::Normal.truncate_limit("tool_result"), 500);
80
81        // Verbose (default) has conservative limits for reasonable output
82        assert_eq!(Verbosity::Verbose.truncate_limit("text"), 2000);
83        assert_eq!(Verbosity::Verbose.truncate_limit("tool_input"), 300);
84        assert_eq!(Verbosity::Verbose.truncate_limit("tool_result"), 500);
85
86        // Full and Debug have unlimited
87        assert_eq!(Verbosity::Full.truncate_limit("text"), 999_999);
88        assert_eq!(Verbosity::Debug.truncate_limit("text"), 999_999);
89    }
90
91    #[test]
92    fn test_verbosity_helpers() {
93        assert!(!Verbosity::Quiet.is_debug());
94        assert!(!Verbosity::Normal.is_debug());
95        assert!(!Verbosity::Verbose.is_debug());
96        assert!(!Verbosity::Full.is_debug());
97        assert!(Verbosity::Debug.is_debug());
98
99        assert!(!Verbosity::Quiet.is_verbose());
100        assert!(!Verbosity::Normal.is_verbose());
101        assert!(Verbosity::Verbose.is_verbose());
102        assert!(Verbosity::Full.is_verbose());
103        assert!(Verbosity::Debug.is_verbose());
104
105        // show_tool_input: true for Normal and above, false for Quiet
106        assert!(!Verbosity::Quiet.show_tool_input());
107        assert!(Verbosity::Normal.show_tool_input());
108        assert!(Verbosity::Verbose.show_tool_input());
109        assert!(Verbosity::Full.show_tool_input());
110        assert!(Verbosity::Debug.show_tool_input());
111    }
112
113    #[test]
114    fn test_review_depth_from_str() {
115        // Standard aliases
116        assert_eq!(
117            ReviewDepth::from_str("standard"),
118            Some(ReviewDepth::Standard)
119        );
120        assert_eq!(
121            ReviewDepth::from_str("default"),
122            Some(ReviewDepth::Standard)
123        );
124        assert_eq!(ReviewDepth::from_str("normal"), Some(ReviewDepth::Standard));
125
126        // Comprehensive aliases
127        assert_eq!(
128            ReviewDepth::from_str("comprehensive"),
129            Some(ReviewDepth::Comprehensive)
130        );
131        assert_eq!(
132            ReviewDepth::from_str("thorough"),
133            Some(ReviewDepth::Comprehensive)
134        );
135        assert_eq!(
136            ReviewDepth::from_str("full"),
137            Some(ReviewDepth::Comprehensive)
138        );
139
140        // Security aliases
141        assert_eq!(
142            ReviewDepth::from_str("security"),
143            Some(ReviewDepth::Security)
144        );
145        assert_eq!(ReviewDepth::from_str("secure"), Some(ReviewDepth::Security));
146        assert_eq!(
147            ReviewDepth::from_str("security-focused"),
148            Some(ReviewDepth::Security)
149        );
150
151        // Incremental aliases
152        assert_eq!(
153            ReviewDepth::from_str("incremental"),
154            Some(ReviewDepth::Incremental)
155        );
156        assert_eq!(
157            ReviewDepth::from_str("diff"),
158            Some(ReviewDepth::Incremental)
159        );
160        assert_eq!(
161            ReviewDepth::from_str("changed"),
162            Some(ReviewDepth::Incremental)
163        );
164
165        // Case insensitivity
166        assert_eq!(
167            ReviewDepth::from_str("SECURITY"),
168            Some(ReviewDepth::Security)
169        );
170        assert_eq!(
171            ReviewDepth::from_str("Comprehensive"),
172            Some(ReviewDepth::Comprehensive)
173        );
174
175        // Invalid values
176        assert_eq!(ReviewDepth::from_str("invalid"), None);
177        assert_eq!(ReviewDepth::from_str(""), None);
178    }
179
180    #[test]
181    fn test_review_depth_default() {
182        assert_eq!(ReviewDepth::default(), ReviewDepth::Standard);
183    }
184
185    #[test]
186    fn test_review_depth_description() {
187        assert!(ReviewDepth::Standard.description().contains("Balanced"));
188        assert!(ReviewDepth::Comprehensive
189            .description()
190            .contains("In-depth"));
191        assert!(ReviewDepth::Security.description().contains("OWASP"));
192        assert!(ReviewDepth::Incremental.description().contains("git diff"));
193    }
194}