gitflow-analytics 1.0.3__py3-none-any.whl → 1.3.6__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 +4108 -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 +904 -0
- gitflow_analytics/config/profiles.py +264 -0
- gitflow_analytics/config/repository.py +124 -0
- gitflow_analytics/config/schema.py +441 -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 +1193 -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.6.dist-info/METADATA +1015 -0
- gitflow_analytics-1.3.6.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.6.dist-info}/WHEEL +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/entry_points.txt +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/licenses/LICENSE +0 -0
- {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/top_level.txt +0 -0
|
@@ -2,27 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
4
|
from typing import Optional
|
|
5
|
-
from datetime import datetime, timedelta
|
|
6
5
|
|
|
7
|
-
from textual.
|
|
8
|
-
from textual.containers import Container, Vertical
|
|
6
|
+
from textual.containers import Container
|
|
9
7
|
from textual.reactive import reactive
|
|
10
|
-
from
|
|
8
|
+
from textual.widgets import Label, ProgressBar
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
class AnalysisProgressWidget(Container):
|
|
14
12
|
"""
|
|
15
13
|
Custom progress widget that shows progress with ETA calculation.
|
|
16
|
-
|
|
17
|
-
WHY: Standard progress bars don't provide time estimates which are crucial
|
|
14
|
+
|
|
15
|
+
WHY: Standard progress bars don't provide time estimates which are crucial
|
|
18
16
|
for long-running analysis operations. This widget combines progress tracking
|
|
19
17
|
with ETA calculations to give users better feedback.
|
|
20
|
-
|
|
21
|
-
DESIGN DECISION: Uses reactive attributes for real-time updates and
|
|
18
|
+
|
|
19
|
+
DESIGN DECISION: Uses reactive attributes for real-time updates and
|
|
22
20
|
calculates ETA based on average processing speed rather than simple linear
|
|
23
21
|
extrapolation for more accurate estimates.
|
|
24
22
|
"""
|
|
25
|
-
|
|
23
|
+
|
|
26
24
|
DEFAULT_CSS = """
|
|
27
25
|
AnalysisProgressWidget {
|
|
28
26
|
height: auto;
|
|
@@ -47,11 +45,11 @@ class AnalysisProgressWidget(Container):
|
|
|
47
45
|
text-style: italic;
|
|
48
46
|
}
|
|
49
47
|
"""
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
progress = reactive(0.0)
|
|
52
50
|
total = reactive(100.0)
|
|
53
51
|
status_text = reactive("Initializing...")
|
|
54
|
-
|
|
52
|
+
|
|
55
53
|
def __init__(
|
|
56
54
|
self,
|
|
57
55
|
title: str,
|
|
@@ -59,7 +57,7 @@ class AnalysisProgressWidget(Container):
|
|
|
59
57
|
*,
|
|
60
58
|
name: Optional[str] = None,
|
|
61
59
|
id: Optional[str] = None,
|
|
62
|
-
classes: Optional[str] = None
|
|
60
|
+
classes: Optional[str] = None,
|
|
63
61
|
) -> None:
|
|
64
62
|
super().__init__(name=name, id=id, classes=classes)
|
|
65
63
|
self.title = title
|
|
@@ -67,87 +65,84 @@ class AnalysisProgressWidget(Container):
|
|
|
67
65
|
self.start_time = time.time()
|
|
68
66
|
self.last_update_time = time.time()
|
|
69
67
|
self.progress_history = []
|
|
70
|
-
|
|
68
|
+
|
|
71
69
|
def compose(self):
|
|
72
70
|
"""Compose the progress widget."""
|
|
73
71
|
yield Label(self.title, classes="progress-title")
|
|
74
72
|
yield ProgressBar(total=self.total, id="progress-bar")
|
|
75
73
|
yield Label(self.status_text, classes="progress-status", id="status-label")
|
|
76
74
|
yield Label("", classes="progress-eta", id="eta-label")
|
|
77
|
-
|
|
75
|
+
|
|
78
76
|
def update_progress(self, value: float, status: str = "") -> None:
|
|
79
77
|
"""
|
|
80
78
|
Update progress and status with ETA calculation.
|
|
81
|
-
|
|
79
|
+
|
|
82
80
|
WHY: Provides comprehensive progress updates including time estimates
|
|
83
81
|
which are essential for user experience during long operations.
|
|
84
|
-
|
|
82
|
+
|
|
85
83
|
@param value: Current progress value
|
|
86
84
|
@param status: Status message to display
|
|
87
85
|
"""
|
|
88
86
|
current_time = time.time()
|
|
89
|
-
|
|
87
|
+
|
|
90
88
|
# Update reactive values
|
|
91
89
|
self.progress = value
|
|
92
90
|
if status:
|
|
93
91
|
self.status_text = status
|
|
94
|
-
|
|
92
|
+
|
|
95
93
|
# Update progress bar
|
|
96
94
|
progress_bar = self.query_one("#progress-bar", ProgressBar)
|
|
97
95
|
progress_bar.update(progress=value)
|
|
98
|
-
|
|
96
|
+
|
|
99
97
|
# Update status label
|
|
100
98
|
status_label = self.query_one("#status-label", Label)
|
|
101
99
|
status_label.update(status)
|
|
102
|
-
|
|
100
|
+
|
|
103
101
|
# Calculate and update ETA
|
|
104
102
|
eta_text = self._calculate_eta(value, current_time)
|
|
105
103
|
eta_label = self.query_one("#eta-label", Label)
|
|
106
104
|
eta_label.update(eta_text)
|
|
107
|
-
|
|
105
|
+
|
|
108
106
|
# Store progress history for better ETA calculation
|
|
109
|
-
self.progress_history.append({
|
|
110
|
-
|
|
111
|
-
'progress': value
|
|
112
|
-
})
|
|
113
|
-
|
|
107
|
+
self.progress_history.append({"time": current_time, "progress": value})
|
|
108
|
+
|
|
114
109
|
# Keep only recent history (last 10 updates)
|
|
115
110
|
if len(self.progress_history) > 10:
|
|
116
111
|
self.progress_history = self.progress_history[-10:]
|
|
117
|
-
|
|
112
|
+
|
|
118
113
|
def _calculate_eta(self, current_progress: float, current_time: float) -> str:
|
|
119
114
|
"""
|
|
120
115
|
Calculate estimated time of arrival based on progress history.
|
|
121
|
-
|
|
116
|
+
|
|
122
117
|
WHY: Uses historical data points to calculate a more accurate ETA
|
|
123
|
-
than simple linear extrapolation, accounting for variations in
|
|
118
|
+
than simple linear extrapolation, accounting for variations in
|
|
124
119
|
processing speed.
|
|
125
120
|
"""
|
|
126
121
|
if current_progress <= 0 or current_progress >= self.total:
|
|
127
122
|
return ""
|
|
128
|
-
|
|
123
|
+
|
|
129
124
|
# Need at least 2 data points for calculation
|
|
130
125
|
if len(self.progress_history) < 2:
|
|
131
126
|
return "Calculating ETA..."
|
|
132
|
-
|
|
127
|
+
|
|
133
128
|
# Calculate average rate from recent history
|
|
134
129
|
recent_history = self.progress_history[-5:] # Last 5 updates
|
|
135
130
|
if len(recent_history) < 2:
|
|
136
131
|
return "Calculating ETA..."
|
|
137
|
-
|
|
138
|
-
time_span = recent_history[-1][
|
|
139
|
-
progress_span = recent_history[-1][
|
|
140
|
-
|
|
132
|
+
|
|
133
|
+
time_span = recent_history[-1]["time"] - recent_history[0]["time"]
|
|
134
|
+
progress_span = recent_history[-1]["progress"] - recent_history[0]["progress"]
|
|
135
|
+
|
|
141
136
|
if time_span <= 0 or progress_span <= 0:
|
|
142
137
|
return "Calculating ETA..."
|
|
143
|
-
|
|
138
|
+
|
|
144
139
|
# Calculate rate (progress per second)
|
|
145
140
|
rate = progress_span / time_span
|
|
146
|
-
|
|
141
|
+
|
|
147
142
|
# Calculate remaining work and time
|
|
148
143
|
remaining_progress = self.total - current_progress
|
|
149
144
|
estimated_seconds = remaining_progress / rate
|
|
150
|
-
|
|
145
|
+
|
|
151
146
|
# Format ETA
|
|
152
147
|
if estimated_seconds < 60:
|
|
153
148
|
return f"ETA: {estimated_seconds:.0f}s"
|
|
@@ -157,28 +152,28 @@ class AnalysisProgressWidget(Container):
|
|
|
157
152
|
else:
|
|
158
153
|
hours = estimated_seconds / 3600
|
|
159
154
|
return f"ETA: {hours:.1f}h"
|
|
160
|
-
|
|
155
|
+
|
|
161
156
|
def reset(self) -> None:
|
|
162
157
|
"""Reset the progress widget to initial state."""
|
|
163
158
|
self.progress = 0.0
|
|
164
159
|
self.status_text = "Initializing..."
|
|
165
160
|
self.start_time = time.time()
|
|
166
161
|
self.progress_history = []
|
|
167
|
-
|
|
162
|
+
|
|
168
163
|
# Reset UI elements
|
|
169
164
|
progress_bar = self.query_one("#progress-bar", ProgressBar)
|
|
170
165
|
progress_bar.update(progress=0)
|
|
171
|
-
|
|
166
|
+
|
|
172
167
|
status_label = self.query_one("#status-label", Label)
|
|
173
168
|
status_label.update("Initializing...")
|
|
174
|
-
|
|
169
|
+
|
|
175
170
|
eta_label = self.query_one("#eta-label", Label)
|
|
176
171
|
eta_label.update("")
|
|
177
|
-
|
|
172
|
+
|
|
178
173
|
def complete(self, final_message: str = "Complete!") -> None:
|
|
179
174
|
"""Mark progress as complete."""
|
|
180
175
|
self.update_progress(self.total, final_message)
|
|
181
|
-
|
|
176
|
+
|
|
182
177
|
# Calculate total elapsed time
|
|
183
178
|
total_time = time.time() - self.start_time
|
|
184
179
|
if total_time < 60:
|
|
@@ -187,6 +182,6 @@ class AnalysisProgressWidget(Container):
|
|
|
187
182
|
time_str = f"{total_time/60:.1f}m"
|
|
188
183
|
else:
|
|
189
184
|
time_str = f"{total_time/3600:.1f}h"
|
|
190
|
-
|
|
185
|
+
|
|
191
186
|
eta_label = self.query_one("#eta-label", Label)
|
|
192
|
-
eta_label.update(f"Completed in {time_str}")
|
|
187
|
+
eta_label.update(f"Completed in {time_str}")
|