gitflow-analytics 1.0.3__py3-none-any.whl → 1.3.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitflow_analytics/_version.py +1 -1
- gitflow_analytics/classification/__init__.py +31 -0
- gitflow_analytics/classification/batch_classifier.py +752 -0
- gitflow_analytics/classification/classifier.py +464 -0
- gitflow_analytics/classification/feature_extractor.py +725 -0
- gitflow_analytics/classification/linguist_analyzer.py +574 -0
- gitflow_analytics/classification/model.py +455 -0
- gitflow_analytics/cli.py +4158 -350
- gitflow_analytics/cli_rich.py +198 -48
- gitflow_analytics/config/__init__.py +43 -0
- gitflow_analytics/config/errors.py +261 -0
- gitflow_analytics/config/loader.py +905 -0
- gitflow_analytics/config/profiles.py +264 -0
- gitflow_analytics/config/repository.py +124 -0
- gitflow_analytics/config/schema.py +444 -0
- gitflow_analytics/config/validator.py +154 -0
- gitflow_analytics/config.py +44 -508
- gitflow_analytics/core/analyzer.py +1209 -98
- gitflow_analytics/core/cache.py +1337 -29
- gitflow_analytics/core/data_fetcher.py +1285 -0
- gitflow_analytics/core/identity.py +363 -14
- gitflow_analytics/core/metrics_storage.py +526 -0
- gitflow_analytics/core/progress.py +372 -0
- gitflow_analytics/core/schema_version.py +269 -0
- gitflow_analytics/extractors/ml_tickets.py +1100 -0
- gitflow_analytics/extractors/story_points.py +8 -1
- gitflow_analytics/extractors/tickets.py +749 -11
- gitflow_analytics/identity_llm/__init__.py +6 -0
- gitflow_analytics/identity_llm/analysis_pass.py +231 -0
- gitflow_analytics/identity_llm/analyzer.py +464 -0
- gitflow_analytics/identity_llm/models.py +76 -0
- gitflow_analytics/integrations/github_integration.py +175 -11
- gitflow_analytics/integrations/jira_integration.py +461 -24
- gitflow_analytics/integrations/orchestrator.py +124 -1
- gitflow_analytics/metrics/activity_scoring.py +322 -0
- gitflow_analytics/metrics/branch_health.py +470 -0
- gitflow_analytics/metrics/dora.py +379 -20
- gitflow_analytics/models/database.py +843 -53
- gitflow_analytics/pm_framework/__init__.py +115 -0
- gitflow_analytics/pm_framework/adapters/__init__.py +50 -0
- gitflow_analytics/pm_framework/adapters/jira_adapter.py +1845 -0
- gitflow_analytics/pm_framework/base.py +406 -0
- gitflow_analytics/pm_framework/models.py +211 -0
- gitflow_analytics/pm_framework/orchestrator.py +652 -0
- gitflow_analytics/pm_framework/registry.py +333 -0
- gitflow_analytics/qualitative/__init__.py +9 -10
- gitflow_analytics/qualitative/chatgpt_analyzer.py +259 -0
- gitflow_analytics/qualitative/classifiers/__init__.py +3 -3
- gitflow_analytics/qualitative/classifiers/change_type.py +518 -244
- gitflow_analytics/qualitative/classifiers/domain_classifier.py +272 -165
- gitflow_analytics/qualitative/classifiers/intent_analyzer.py +321 -222
- gitflow_analytics/qualitative/classifiers/llm/__init__.py +35 -0
- gitflow_analytics/qualitative/classifiers/llm/base.py +193 -0
- gitflow_analytics/qualitative/classifiers/llm/batch_processor.py +383 -0
- gitflow_analytics/qualitative/classifiers/llm/cache.py +479 -0
- gitflow_analytics/qualitative/classifiers/llm/cost_tracker.py +435 -0
- gitflow_analytics/qualitative/classifiers/llm/openai_client.py +403 -0
- gitflow_analytics/qualitative/classifiers/llm/prompts.py +373 -0
- gitflow_analytics/qualitative/classifiers/llm/response_parser.py +287 -0
- gitflow_analytics/qualitative/classifiers/llm_commit_classifier.py +607 -0
- gitflow_analytics/qualitative/classifiers/risk_analyzer.py +215 -189
- gitflow_analytics/qualitative/core/__init__.py +4 -4
- gitflow_analytics/qualitative/core/llm_fallback.py +239 -235
- gitflow_analytics/qualitative/core/nlp_engine.py +157 -148
- gitflow_analytics/qualitative/core/pattern_cache.py +214 -192
- gitflow_analytics/qualitative/core/processor.py +381 -248
- gitflow_analytics/qualitative/enhanced_analyzer.py +2236 -0
- gitflow_analytics/qualitative/example_enhanced_usage.py +420 -0
- gitflow_analytics/qualitative/models/__init__.py +7 -7
- gitflow_analytics/qualitative/models/schemas.py +155 -121
- gitflow_analytics/qualitative/utils/__init__.py +4 -4
- gitflow_analytics/qualitative/utils/batch_processor.py +136 -123
- gitflow_analytics/qualitative/utils/cost_tracker.py +142 -140
- gitflow_analytics/qualitative/utils/metrics.py +172 -158
- gitflow_analytics/qualitative/utils/text_processing.py +146 -104
- gitflow_analytics/reports/__init__.py +100 -0
- gitflow_analytics/reports/analytics_writer.py +539 -14
- gitflow_analytics/reports/base.py +648 -0
- gitflow_analytics/reports/branch_health_writer.py +322 -0
- gitflow_analytics/reports/classification_writer.py +924 -0
- gitflow_analytics/reports/cli_integration.py +427 -0
- gitflow_analytics/reports/csv_writer.py +1676 -212
- gitflow_analytics/reports/data_models.py +504 -0
- gitflow_analytics/reports/database_report_generator.py +427 -0
- gitflow_analytics/reports/example_usage.py +344 -0
- gitflow_analytics/reports/factory.py +499 -0
- gitflow_analytics/reports/formatters.py +698 -0
- gitflow_analytics/reports/html_generator.py +1116 -0
- gitflow_analytics/reports/interfaces.py +489 -0
- gitflow_analytics/reports/json_exporter.py +2770 -0
- gitflow_analytics/reports/narrative_writer.py +2287 -158
- gitflow_analytics/reports/story_point_correlation.py +1144 -0
- gitflow_analytics/reports/weekly_trends_writer.py +389 -0
- gitflow_analytics/training/__init__.py +5 -0
- gitflow_analytics/training/model_loader.py +377 -0
- gitflow_analytics/training/pipeline.py +550 -0
- gitflow_analytics/tui/__init__.py +1 -1
- gitflow_analytics/tui/app.py +129 -126
- gitflow_analytics/tui/screens/__init__.py +3 -3
- gitflow_analytics/tui/screens/analysis_progress_screen.py +188 -179
- gitflow_analytics/tui/screens/configuration_screen.py +154 -178
- gitflow_analytics/tui/screens/loading_screen.py +100 -110
- gitflow_analytics/tui/screens/main_screen.py +89 -72
- gitflow_analytics/tui/screens/results_screen.py +305 -281
- gitflow_analytics/tui/widgets/__init__.py +2 -2
- gitflow_analytics/tui/widgets/data_table.py +67 -69
- gitflow_analytics/tui/widgets/export_modal.py +76 -76
- gitflow_analytics/tui/widgets/progress_widget.py +41 -46
- gitflow_analytics-1.3.11.dist-info/METADATA +1015 -0
- gitflow_analytics-1.3.11.dist-info/RECORD +122 -0
- gitflow_analytics-1.0.3.dist-info/METADATA +0 -490
- gitflow_analytics-1.0.3.dist-info/RECORD +0 -62
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/WHEEL +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/entry_points.txt +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/licenses/LICENSE +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Configuration error handling and user-friendly error messages."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConfigurationError(ValueError):
|
|
10
|
+
"""Base exception for configuration-related errors."""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self, message: str, config_path: Optional[Path] = None, suggestion: Optional[str] = None
|
|
14
|
+
):
|
|
15
|
+
"""Initialize configuration error.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
message: The error message
|
|
19
|
+
config_path: Path to the configuration file
|
|
20
|
+
suggestion: Helpful suggestion for fixing the error
|
|
21
|
+
"""
|
|
22
|
+
self.message = message
|
|
23
|
+
self.config_path = config_path
|
|
24
|
+
self.suggestion = suggestion
|
|
25
|
+
super().__init__(self._format_message())
|
|
26
|
+
|
|
27
|
+
def _format_message(self) -> str:
|
|
28
|
+
"""Format the error message with context and suggestions."""
|
|
29
|
+
msg = f"❌ {self.message}"
|
|
30
|
+
if self.suggestion:
|
|
31
|
+
msg += f"\n\n💡 {self.suggestion}"
|
|
32
|
+
if self.config_path:
|
|
33
|
+
msg += f"\n\n📁 File: {self.config_path}"
|
|
34
|
+
return msg
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class YAMLParseError(ConfigurationError):
|
|
38
|
+
"""YAML parsing error with user-friendly messages."""
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_yaml_error(cls, error: yaml.YAMLError, config_path: Path) -> "YAMLParseError":
|
|
42
|
+
"""Create YAMLParseError from yaml.YAMLError with helpful guidance.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
error: The original YAML error
|
|
46
|
+
config_path: Path to the configuration file
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
YAMLParseError with user-friendly message
|
|
50
|
+
"""
|
|
51
|
+
file_name = config_path.name
|
|
52
|
+
|
|
53
|
+
# Extract error details if available
|
|
54
|
+
line_number = getattr(error, "problem_mark", None)
|
|
55
|
+
context_mark = getattr(error, "context_mark", None)
|
|
56
|
+
problem = getattr(error, "problem", str(error))
|
|
57
|
+
context = getattr(error, "context", None)
|
|
58
|
+
|
|
59
|
+
# Build error message parts
|
|
60
|
+
location_info = ""
|
|
61
|
+
if line_number:
|
|
62
|
+
location_info = f" at line {line_number.line + 1}, column {line_number.column + 1}"
|
|
63
|
+
elif context_mark:
|
|
64
|
+
location_info = f" at line {context_mark.line + 1}, column {context_mark.column + 1}"
|
|
65
|
+
|
|
66
|
+
# Create user-friendly error message
|
|
67
|
+
base_msg = f"YAML configuration error in {file_name}{location_info}"
|
|
68
|
+
|
|
69
|
+
# Detect common YAML issues and provide specific guidance
|
|
70
|
+
problem_lower = problem.lower()
|
|
71
|
+
suggestion = cls._get_suggestion_for_problem(problem_lower, context)
|
|
72
|
+
|
|
73
|
+
# Add context information if available
|
|
74
|
+
if context and context != problem:
|
|
75
|
+
base_msg += f"\n📍 Context: {context}"
|
|
76
|
+
|
|
77
|
+
# Add helpful resources
|
|
78
|
+
base_msg += "\n\n🔗 For YAML syntax help, visit: https://yaml.org/spec/1.2/spec.html"
|
|
79
|
+
base_msg += "\n Or use an online YAML validator to check your syntax."
|
|
80
|
+
|
|
81
|
+
return cls(base_msg, config_path, suggestion)
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _get_suggestion_for_problem(problem_lower: str, context: Optional[str] = None) -> str:
|
|
85
|
+
"""Get specific suggestion based on the YAML problem.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
problem_lower: Lowercase problem description
|
|
89
|
+
context: Optional context string
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Helpful suggestion for fixing the problem
|
|
93
|
+
"""
|
|
94
|
+
if "found character '\\t'" in problem_lower.replace("'", "'"):
|
|
95
|
+
return (
|
|
96
|
+
"🚫 Tab characters are not allowed in YAML files!\n\n"
|
|
97
|
+
"Fix: Replace all tab characters with spaces (usually 2 or 4 spaces).\n"
|
|
98
|
+
" Most editors can show whitespace characters and convert tabs to spaces.\n"
|
|
99
|
+
" In VS Code: View → Render Whitespace, then Edit → Convert Indentation to Spaces"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
elif "mapping values are not allowed here" in problem_lower:
|
|
103
|
+
return (
|
|
104
|
+
"🚫 Invalid YAML syntax - missing colon or incorrect indentation!\n\n"
|
|
105
|
+
"Common fixes:\n"
|
|
106
|
+
" • Add a colon (:) after the key name\n"
|
|
107
|
+
" • Check that all lines are properly indented with spaces\n"
|
|
108
|
+
" • Ensure nested items are indented consistently"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
elif "could not find expected" in problem_lower and ":" in problem_lower:
|
|
112
|
+
return (
|
|
113
|
+
"🚫 Missing colon (:) after a key name!\n\n"
|
|
114
|
+
"Fix: Add a colon and space after the key name.\n"
|
|
115
|
+
" Example: 'key_name: value' not 'key_name value'"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
elif "found undefined alias" in problem_lower:
|
|
119
|
+
return (
|
|
120
|
+
"🚫 YAML alias reference not found!\n\n"
|
|
121
|
+
"Fix: Check that the referenced alias (&name) is defined before using it (*name)"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
elif "expected <block end>" in problem_lower:
|
|
125
|
+
return (
|
|
126
|
+
"🚫 Incorrect indentation or missing content!\n\n"
|
|
127
|
+
"Common fixes:\n"
|
|
128
|
+
" • Check that all nested items are properly indented\n"
|
|
129
|
+
" • Ensure list items start with '- ' (dash and space)\n"
|
|
130
|
+
" • Make sure there's content after colons"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
elif "while scanning a quoted scalar" in problem_lower:
|
|
134
|
+
return (
|
|
135
|
+
"🚫 Unclosed or incorrectly quoted string!\n\n"
|
|
136
|
+
"Fix: Check that all quotes are properly closed.\n"
|
|
137
|
+
" • Use matching quotes: 'text' or \"text\"\n"
|
|
138
|
+
' • Escape quotes inside strings: \'don\\\'t\' or "say \\"hello\\""'
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
elif "found unexpected end of stream" in problem_lower:
|
|
142
|
+
return (
|
|
143
|
+
"🚫 Incomplete YAML structure!\n\n"
|
|
144
|
+
"Fix: The file appears to end unexpectedly.\n"
|
|
145
|
+
" • Check that all sections are complete\n"
|
|
146
|
+
" • Ensure there are no missing closing brackets or braces"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
elif "found unknown escape character" in problem_lower:
|
|
150
|
+
return (
|
|
151
|
+
"🚫 Invalid escape sequence in quoted string!\n\n"
|
|
152
|
+
"Fix: Use proper YAML escape sequences or raw strings.\n"
|
|
153
|
+
' • For regex patterns: Use double quotes and double backslashes ("\\\\d+")\n'
|
|
154
|
+
" • For file paths: Use forward slashes or double backslashes\n"
|
|
155
|
+
" • Or use single quotes for literal strings: 'C:\\path\\to\\file'"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
elif "scanner" in problem_lower and "character" in problem_lower:
|
|
159
|
+
return (
|
|
160
|
+
"🚫 Invalid character in YAML file!\n\n"
|
|
161
|
+
"Fix: Check for special characters that need to be quoted.\n"
|
|
162
|
+
" • Wrap values containing special characters in quotes\n"
|
|
163
|
+
" • Common problematic characters: @, `, |, >, [, ], {, }"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
else:
|
|
167
|
+
return (
|
|
168
|
+
f"🚫 YAML parsing error: {problem_lower}\n\n"
|
|
169
|
+
"Common YAML issues to check:\n"
|
|
170
|
+
" • Use spaces for indentation, not tabs\n"
|
|
171
|
+
" • Add colons (:) after key names\n"
|
|
172
|
+
" • Ensure consistent indentation (usually 2 or 4 spaces)\n"
|
|
173
|
+
" • Quote strings containing special characters\n"
|
|
174
|
+
" • Use '- ' (dash and space) for list items"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class MissingFieldError(ConfigurationError):
|
|
179
|
+
"""Error for missing required configuration fields."""
|
|
180
|
+
|
|
181
|
+
def __init__(
|
|
182
|
+
self,
|
|
183
|
+
field_name: str,
|
|
184
|
+
section: str,
|
|
185
|
+
config_path: Optional[Path] = None,
|
|
186
|
+
example: Optional[str] = None,
|
|
187
|
+
):
|
|
188
|
+
"""Initialize missing field error.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
field_name: Name of the missing field
|
|
192
|
+
section: Configuration section containing the field
|
|
193
|
+
config_path: Path to the configuration file
|
|
194
|
+
example: Example of correct usage
|
|
195
|
+
"""
|
|
196
|
+
message = f"Missing required field '{field_name}' in {section}"
|
|
197
|
+
suggestion = f"Add the '{field_name}' field to your configuration"
|
|
198
|
+
if example:
|
|
199
|
+
suggestion += f":\n {example}"
|
|
200
|
+
super().__init__(message, config_path, suggestion)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class InvalidValueError(ConfigurationError):
|
|
204
|
+
"""Error for invalid configuration values."""
|
|
205
|
+
|
|
206
|
+
def __init__(
|
|
207
|
+
self,
|
|
208
|
+
field_name: str,
|
|
209
|
+
value: Any,
|
|
210
|
+
reason: str,
|
|
211
|
+
config_path: Optional[Path] = None,
|
|
212
|
+
valid_values: Optional[list] = None,
|
|
213
|
+
):
|
|
214
|
+
"""Initialize invalid value error.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
field_name: Name of the field with invalid value
|
|
218
|
+
value: The invalid value
|
|
219
|
+
reason: Reason why the value is invalid
|
|
220
|
+
config_path: Path to the configuration file
|
|
221
|
+
valid_values: List of valid values (if applicable)
|
|
222
|
+
"""
|
|
223
|
+
message = f"Invalid value for '{field_name}': {value} - {reason}"
|
|
224
|
+
suggestion = f"Check the value of '{field_name}'"
|
|
225
|
+
if valid_values:
|
|
226
|
+
suggestion += f"\n Valid values: {', '.join(str(v) for v in valid_values)}"
|
|
227
|
+
super().__init__(message, config_path, suggestion)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class EnvironmentVariableError(ConfigurationError):
|
|
231
|
+
"""Error for missing environment variables."""
|
|
232
|
+
|
|
233
|
+
def __init__(self, var_name: str, field_context: str, config_path: Optional[Path] = None):
|
|
234
|
+
"""Initialize environment variable error.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
var_name: Name of the missing environment variable
|
|
238
|
+
field_context: Context where the variable is used
|
|
239
|
+
config_path: Path to the configuration file
|
|
240
|
+
"""
|
|
241
|
+
message = f"{field_context} is configured but {var_name} environment variable is not set"
|
|
242
|
+
suggestion = (
|
|
243
|
+
f"Set the {var_name} environment variable:\n"
|
|
244
|
+
f" • Export directly: export {var_name}='your_value'\n"
|
|
245
|
+
f" • Or create a .env file in the same directory as your config:\n"
|
|
246
|
+
f" {var_name}=your_value"
|
|
247
|
+
)
|
|
248
|
+
super().__init__(message, config_path, suggestion)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def handle_yaml_error(error: yaml.YAMLError, config_path: Path) -> None:
|
|
252
|
+
"""Handle YAML parsing errors with user-friendly messages.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
error: The YAML error to handle
|
|
256
|
+
config_path: Path to the configuration file
|
|
257
|
+
|
|
258
|
+
Raises:
|
|
259
|
+
YAMLParseError: With user-friendly error message
|
|
260
|
+
"""
|
|
261
|
+
raise YAMLParseError.from_yaml_error(error, config_path)
|