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