omni_dev/data/context.rs
1//! Context data structures for enhanced commit message analysis
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::path::PathBuf;
7
8/// Complete context information for intelligent commit message improvement
9#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10pub struct CommitContext {
11 /// Project-level context and conventions
12 pub project: ProjectContext,
13 /// Branch analysis and work pattern detection
14 pub branch: BranchContext,
15 /// Multi-commit analysis and work patterns
16 pub range: CommitRangeContext,
17 /// File-specific context and architectural understanding
18 pub files: Vec<FileContext>,
19 /// User-provided context information
20 pub user_provided: Option<String>,
21}
22
23/// Project-level context discovered from configuration files
24#[derive(Debug, Clone, Serialize, Deserialize, Default)]
25pub struct ProjectContext {
26 /// Project-specific commit guidelines from .omni-dev/commit-guidelines.md
27 pub commit_guidelines: Option<String>,
28 /// Default commit message template from .gitmessage or .omni-dev/commit-template.txt
29 pub commit_template: Option<String>,
30 /// Valid scopes and their descriptions from .omni-dev/scopes.yaml
31 pub valid_scopes: Vec<ScopeDefinition>,
32 /// Feature-specific context from .omni-dev/context/
33 pub feature_contexts: HashMap<String, FeatureContext>,
34 /// Parsed conventions from CONTRIBUTING.md
35 pub project_conventions: ProjectConventions,
36 /// Detected ecosystem (rust, node, python, etc.)
37 pub ecosystem: Ecosystem,
38}
39
40/// Definition of a valid scope in the project
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct ScopeDefinition {
43 /// Name of the scope
44 pub name: String,
45 /// Human-readable description of the scope
46 pub description: String,
47 /// Example commit messages using this scope
48 pub examples: Vec<String>,
49 /// File patterns that match this scope
50 pub file_patterns: Vec<String>,
51}
52
53/// Context for a specific feature or work area
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct FeatureContext {
56 /// Name of the feature context
57 pub name: String,
58 /// Description of the feature or work area
59 pub description: String,
60 /// Associated scope for this feature
61 pub scope: String,
62 /// Specific conventions for this feature
63 pub conventions: Vec<String>,
64}
65
66/// Project conventions parsed from documentation
67#[derive(Debug, Clone, Serialize, Deserialize, Default)]
68pub struct ProjectConventions {
69 /// Expected commit message format
70 pub commit_format: Option<String>,
71 /// Required trailers like Signed-off-by
72 pub required_trailers: Vec<String>,
73 /// Preferred commit types for this project
74 pub preferred_types: Vec<String>,
75 /// Scope usage requirements and definitions
76 pub scope_requirements: ScopeRequirements,
77}
78
79/// Requirements and validation rules for commit scopes
80#[derive(Debug, Clone, Serialize, Deserialize, Default)]
81pub struct ScopeRequirements {
82 /// Whether a scope is required in commit messages
83 pub required: bool,
84 /// List of valid scope names
85 pub valid_scopes: Vec<String>,
86 /// Mapping from file patterns to suggested scopes
87 pub scope_mapping: HashMap<String, Vec<String>>, // file patterns -> scope
88}
89
90/// Detected project ecosystem
91#[derive(Debug, Clone, Serialize, Deserialize, Default)]
92pub enum Ecosystem {
93 #[default]
94 /// Unknown or undetected ecosystem
95 Unknown,
96 /// Rust ecosystem with Cargo
97 Rust,
98 /// Node.js ecosystem with npm/yarn
99 Node,
100 /// Python ecosystem with pip/poetry
101 Python,
102 /// Go ecosystem with go modules
103 Go,
104 /// Java ecosystem with Maven/Gradle
105 Java,
106 /// Generic project without specific ecosystem
107 Generic,
108}
109
110/// Branch analysis and work pattern detection
111#[derive(Debug, Clone, Serialize, Deserialize, Default)]
112pub struct BranchContext {
113 /// Type of work being performed on this branch
114 pub work_type: WorkType,
115 /// Extracted scope from branch name
116 pub scope: Option<String>,
117 /// Associated ticket or issue ID
118 pub ticket_id: Option<String>,
119 /// Human-readable description of the branch purpose
120 pub description: String,
121 /// Whether this is a feature branch (vs main/master)
122 pub is_feature_branch: bool,
123 /// Base branch this was created from
124 pub base_branch: Option<String>,
125}
126
127/// Type of work being performed
128#[derive(Debug, Clone, Serialize, Deserialize, Default)]
129pub enum WorkType {
130 #[default]
131 /// Unknown or unspecified work type
132 Unknown,
133 /// New feature development
134 Feature,
135 /// Bug fix
136 Fix,
137 /// Documentation changes
138 Docs,
139 /// Code refactoring
140 Refactor,
141 /// Maintenance tasks
142 Chore,
143 /// Test-related changes
144 Test,
145 /// CI/CD pipeline changes
146 Ci,
147 /// Build system changes
148 Build,
149 /// Performance improvements
150 Perf,
151}
152
153impl std::str::FromStr for WorkType {
154 type Err = anyhow::Error;
155
156 fn from_str(s: &str) -> Result<Self> {
157 match s.to_lowercase().as_str() {
158 "feature" | "feat" => Ok(WorkType::Feature),
159 "fix" | "bugfix" => Ok(WorkType::Fix),
160 "docs" | "doc" => Ok(WorkType::Docs),
161 "refactor" | "refact" => Ok(WorkType::Refactor),
162 "chore" => Ok(WorkType::Chore),
163 "test" | "tests" => Ok(WorkType::Test),
164 "ci" => Ok(WorkType::Ci),
165 "build" => Ok(WorkType::Build),
166 "perf" | "performance" => Ok(WorkType::Perf),
167 _ => Ok(WorkType::Unknown),
168 }
169 }
170}
171
172impl std::fmt::Display for WorkType {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 match self {
175 WorkType::Unknown => write!(f, "unknown work"),
176 WorkType::Feature => write!(f, "feature development"),
177 WorkType::Fix => write!(f, "bug fix"),
178 WorkType::Docs => write!(f, "documentation update"),
179 WorkType::Refactor => write!(f, "refactoring"),
180 WorkType::Chore => write!(f, "maintenance"),
181 WorkType::Test => write!(f, "testing"),
182 WorkType::Ci => write!(f, "CI/CD"),
183 WorkType::Build => write!(f, "build system"),
184 WorkType::Perf => write!(f, "performance improvement"),
185 }
186 }
187}
188
189/// Multi-commit analysis and work patterns
190#[derive(Debug, Clone, Serialize, Deserialize, Default)]
191pub struct CommitRangeContext {
192 /// Related commit hashes in this analysis
193 pub related_commits: Vec<String>, // commit hashes
194 /// Files that appear in multiple commits
195 pub common_files: Vec<PathBuf>,
196 /// Detected work pattern across commits
197 pub work_pattern: WorkPattern,
198 /// Analysis of scope consistency
199 pub scope_consistency: ScopeAnalysis,
200 /// Overall architectural impact assessment
201 pub architectural_impact: ArchitecturalImpact,
202 /// Significance of changes for commit message detail
203 pub change_significance: ChangeSignificance,
204}
205
206/// Detected work pattern across commits
207#[derive(Debug, Clone, Serialize, Deserialize, Default)]
208pub enum WorkPattern {
209 #[default]
210 /// Unknown or undetected pattern
211 Unknown,
212 /// Building feature step by step
213 Sequential,
214 /// Multiple small cleanup commits
215 Refactoring,
216 /// Investigation and fixes
217 BugHunt,
218 /// Documentation updates
219 Documentation,
220 /// Config and setup changes
221 Configuration,
222}
223
224/// Analysis of scope consistency across commits
225#[derive(Debug, Clone, Serialize, Deserialize, Default)]
226pub struct ScopeAnalysis {
227 /// Most consistent scope across commits if any
228 pub consistent_scope: Option<String>,
229 /// All scope changes detected
230 pub scope_changes: Vec<String>,
231 /// Confidence level in scope consistency (0.0-1.0)
232 pub confidence: f32,
233}
234
235/// Impact on system architecture
236#[derive(Debug, Clone, Serialize, Deserialize, Default)]
237pub enum ArchitecturalImpact {
238 #[default]
239 /// Small changes, no architecture impact
240 Minimal,
241 /// Some architectural changes
242 Moderate,
243 /// Major architectural changes
244 Significant,
245 /// Breaking changes
246 Breaking,
247}
248
249/// Significance of changes for commit message detail level
250#[derive(Debug, Clone, Serialize, Deserialize, Default)]
251pub enum ChangeSignificance {
252 #[default]
253 /// Simple fix or small addition
254 Minor,
255 /// Notable feature or improvement
256 Moderate,
257 /// Significant enhancement or new capability
258 Major,
259 /// Major system changes or breaking changes
260 Critical,
261}
262
263/// File-based context and architectural understanding
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct FileContext {
266 /// Path to the file
267 pub path: PathBuf,
268 /// Purpose of this file in the project
269 pub file_purpose: FilePurpose,
270 /// Architectural layer this file belongs to
271 pub architectural_layer: ArchitecturalLayer,
272 /// Impact of changes to this file
273 pub change_impact: ChangeImpact,
274 /// Significance of this file in the project
275 pub project_significance: ProjectSignificance,
276}
277
278/// Purpose of the file in the project
279#[derive(Debug, Clone, Serialize, Deserialize)]
280pub enum FilePurpose {
281 /// Configuration files
282 Config,
283 /// Test files
284 Test,
285 /// Docs and README files
286 Documentation,
287 /// Main application logic
288 CoreLogic,
289 /// API definitions, public interfaces
290 Interface,
291 /// Build and deployment files
292 Build,
293 /// Development tools and scripts
294 Tooling,
295}
296
297/// Architectural layer of the file
298#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
299pub enum ArchitecturalLayer {
300 /// UI, CLI, web interfaces
301 Presentation,
302 /// Core business logic
303 Business,
304 /// Data access, models, storage
305 Data,
306 /// System, network, deployment
307 Infrastructure,
308 /// Cross-cutting concerns (logging, auth, etc.)
309 Cross,
310}
311
312/// Impact of changes to this file
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub enum ChangeImpact {
315 /// Formatting, comments, style changes
316 Style,
317 /// New functionality, non-breaking
318 Additive,
319 /// Changing existing functionality
320 Modification,
321 /// Breaking existing functionality
322 Breaking,
323 /// Security, safety, or critical fixes
324 Critical,
325}
326
327/// Significance of file in project
328#[derive(Debug, Clone, Serialize, Deserialize)]
329pub enum ProjectSignificance {
330 /// Common, everyday files
331 Routine,
332 /// Key files but not critical
333 Important,
334 /// Core files that define the project
335 Critical,
336}
337
338impl CommitContext {
339 /// Create a new empty context
340 pub fn new() -> Self {
341 Self::default()
342 }
343
344 /// Check if this context suggests a significant change needing detailed commit message
345 pub fn is_significant_change(&self) -> bool {
346 matches!(
347 self.range.change_significance,
348 ChangeSignificance::Major | ChangeSignificance::Critical
349 ) || matches!(
350 self.range.architectural_impact,
351 ArchitecturalImpact::Significant | ArchitecturalImpact::Breaking
352 ) || self.files.iter().any(|f| {
353 matches!(f.project_significance, ProjectSignificance::Critical)
354 || matches!(
355 f.change_impact,
356 ChangeImpact::Breaking | ChangeImpact::Critical
357 )
358 })
359 }
360
361 /// Get suggested commit message verbosity level
362 pub fn suggested_verbosity(&self) -> VerbosityLevel {
363 if self.is_significant_change() {
364 VerbosityLevel::Comprehensive
365 } else if matches!(self.range.change_significance, ChangeSignificance::Moderate)
366 || self.files.len() > 1
367 || self.files.iter().any(|f| {
368 matches!(
369 f.architectural_layer,
370 ArchitecturalLayer::Presentation | ArchitecturalLayer::Business
371 )
372 })
373 {
374 // Be more generous with Detailed level for twiddle system:
375 // - Moderate changes
376 // - Multiple files
377 // - UI/CLI or business logic changes
378 VerbosityLevel::Detailed
379 } else {
380 VerbosityLevel::Concise
381 }
382 }
383}
384
385/// Suggested level of detail for commit messages
386#[derive(Debug, Clone, Copy)]
387pub enum VerbosityLevel {
388 /// Single line, basic conventional commit
389 Concise,
390 /// Subject + brief body paragraph
391 Detailed,
392 /// Subject + detailed multi-paragraph body + lists
393 Comprehensive,
394}