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.
Files changed (116) hide show
  1. gitflow_analytics/_version.py +1 -1
  2. gitflow_analytics/classification/__init__.py +31 -0
  3. gitflow_analytics/classification/batch_classifier.py +752 -0
  4. gitflow_analytics/classification/classifier.py +464 -0
  5. gitflow_analytics/classification/feature_extractor.py +725 -0
  6. gitflow_analytics/classification/linguist_analyzer.py +574 -0
  7. gitflow_analytics/classification/model.py +455 -0
  8. gitflow_analytics/cli.py +4108 -350
  9. gitflow_analytics/cli_rich.py +198 -48
  10. gitflow_analytics/config/__init__.py +43 -0
  11. gitflow_analytics/config/errors.py +261 -0
  12. gitflow_analytics/config/loader.py +904 -0
  13. gitflow_analytics/config/profiles.py +264 -0
  14. gitflow_analytics/config/repository.py +124 -0
  15. gitflow_analytics/config/schema.py +441 -0
  16. gitflow_analytics/config/validator.py +154 -0
  17. gitflow_analytics/config.py +44 -508
  18. gitflow_analytics/core/analyzer.py +1209 -98
  19. gitflow_analytics/core/cache.py +1337 -29
  20. gitflow_analytics/core/data_fetcher.py +1193 -0
  21. gitflow_analytics/core/identity.py +363 -14
  22. gitflow_analytics/core/metrics_storage.py +526 -0
  23. gitflow_analytics/core/progress.py +372 -0
  24. gitflow_analytics/core/schema_version.py +269 -0
  25. gitflow_analytics/extractors/ml_tickets.py +1100 -0
  26. gitflow_analytics/extractors/story_points.py +8 -1
  27. gitflow_analytics/extractors/tickets.py +749 -11
  28. gitflow_analytics/identity_llm/__init__.py +6 -0
  29. gitflow_analytics/identity_llm/analysis_pass.py +231 -0
  30. gitflow_analytics/identity_llm/analyzer.py +464 -0
  31. gitflow_analytics/identity_llm/models.py +76 -0
  32. gitflow_analytics/integrations/github_integration.py +175 -11
  33. gitflow_analytics/integrations/jira_integration.py +461 -24
  34. gitflow_analytics/integrations/orchestrator.py +124 -1
  35. gitflow_analytics/metrics/activity_scoring.py +322 -0
  36. gitflow_analytics/metrics/branch_health.py +470 -0
  37. gitflow_analytics/metrics/dora.py +379 -20
  38. gitflow_analytics/models/database.py +843 -53
  39. gitflow_analytics/pm_framework/__init__.py +115 -0
  40. gitflow_analytics/pm_framework/adapters/__init__.py +50 -0
  41. gitflow_analytics/pm_framework/adapters/jira_adapter.py +1845 -0
  42. gitflow_analytics/pm_framework/base.py +406 -0
  43. gitflow_analytics/pm_framework/models.py +211 -0
  44. gitflow_analytics/pm_framework/orchestrator.py +652 -0
  45. gitflow_analytics/pm_framework/registry.py +333 -0
  46. gitflow_analytics/qualitative/__init__.py +9 -10
  47. gitflow_analytics/qualitative/chatgpt_analyzer.py +259 -0
  48. gitflow_analytics/qualitative/classifiers/__init__.py +3 -3
  49. gitflow_analytics/qualitative/classifiers/change_type.py +518 -244
  50. gitflow_analytics/qualitative/classifiers/domain_classifier.py +272 -165
  51. gitflow_analytics/qualitative/classifiers/intent_analyzer.py +321 -222
  52. gitflow_analytics/qualitative/classifiers/llm/__init__.py +35 -0
  53. gitflow_analytics/qualitative/classifiers/llm/base.py +193 -0
  54. gitflow_analytics/qualitative/classifiers/llm/batch_processor.py +383 -0
  55. gitflow_analytics/qualitative/classifiers/llm/cache.py +479 -0
  56. gitflow_analytics/qualitative/classifiers/llm/cost_tracker.py +435 -0
  57. gitflow_analytics/qualitative/classifiers/llm/openai_client.py +403 -0
  58. gitflow_analytics/qualitative/classifiers/llm/prompts.py +373 -0
  59. gitflow_analytics/qualitative/classifiers/llm/response_parser.py +287 -0
  60. gitflow_analytics/qualitative/classifiers/llm_commit_classifier.py +607 -0
  61. gitflow_analytics/qualitative/classifiers/risk_analyzer.py +215 -189
  62. gitflow_analytics/qualitative/core/__init__.py +4 -4
  63. gitflow_analytics/qualitative/core/llm_fallback.py +239 -235
  64. gitflow_analytics/qualitative/core/nlp_engine.py +157 -148
  65. gitflow_analytics/qualitative/core/pattern_cache.py +214 -192
  66. gitflow_analytics/qualitative/core/processor.py +381 -248
  67. gitflow_analytics/qualitative/enhanced_analyzer.py +2236 -0
  68. gitflow_analytics/qualitative/example_enhanced_usage.py +420 -0
  69. gitflow_analytics/qualitative/models/__init__.py +7 -7
  70. gitflow_analytics/qualitative/models/schemas.py +155 -121
  71. gitflow_analytics/qualitative/utils/__init__.py +4 -4
  72. gitflow_analytics/qualitative/utils/batch_processor.py +136 -123
  73. gitflow_analytics/qualitative/utils/cost_tracker.py +142 -140
  74. gitflow_analytics/qualitative/utils/metrics.py +172 -158
  75. gitflow_analytics/qualitative/utils/text_processing.py +146 -104
  76. gitflow_analytics/reports/__init__.py +100 -0
  77. gitflow_analytics/reports/analytics_writer.py +539 -14
  78. gitflow_analytics/reports/base.py +648 -0
  79. gitflow_analytics/reports/branch_health_writer.py +322 -0
  80. gitflow_analytics/reports/classification_writer.py +924 -0
  81. gitflow_analytics/reports/cli_integration.py +427 -0
  82. gitflow_analytics/reports/csv_writer.py +1676 -212
  83. gitflow_analytics/reports/data_models.py +504 -0
  84. gitflow_analytics/reports/database_report_generator.py +427 -0
  85. gitflow_analytics/reports/example_usage.py +344 -0
  86. gitflow_analytics/reports/factory.py +499 -0
  87. gitflow_analytics/reports/formatters.py +698 -0
  88. gitflow_analytics/reports/html_generator.py +1116 -0
  89. gitflow_analytics/reports/interfaces.py +489 -0
  90. gitflow_analytics/reports/json_exporter.py +2770 -0
  91. gitflow_analytics/reports/narrative_writer.py +2287 -158
  92. gitflow_analytics/reports/story_point_correlation.py +1144 -0
  93. gitflow_analytics/reports/weekly_trends_writer.py +389 -0
  94. gitflow_analytics/training/__init__.py +5 -0
  95. gitflow_analytics/training/model_loader.py +377 -0
  96. gitflow_analytics/training/pipeline.py +550 -0
  97. gitflow_analytics/tui/__init__.py +1 -1
  98. gitflow_analytics/tui/app.py +129 -126
  99. gitflow_analytics/tui/screens/__init__.py +3 -3
  100. gitflow_analytics/tui/screens/analysis_progress_screen.py +188 -179
  101. gitflow_analytics/tui/screens/configuration_screen.py +154 -178
  102. gitflow_analytics/tui/screens/loading_screen.py +100 -110
  103. gitflow_analytics/tui/screens/main_screen.py +89 -72
  104. gitflow_analytics/tui/screens/results_screen.py +305 -281
  105. gitflow_analytics/tui/widgets/__init__.py +2 -2
  106. gitflow_analytics/tui/widgets/data_table.py +67 -69
  107. gitflow_analytics/tui/widgets/export_modal.py +76 -76
  108. gitflow_analytics/tui/widgets/progress_widget.py +41 -46
  109. gitflow_analytics-1.3.6.dist-info/METADATA +1015 -0
  110. gitflow_analytics-1.3.6.dist-info/RECORD +122 -0
  111. gitflow_analytics-1.0.3.dist-info/METADATA +0 -490
  112. gitflow_analytics-1.0.3.dist-info/RECORD +0 -62
  113. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/WHEEL +0 -0
  114. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/entry_points.txt +0 -0
  115. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/licenses/LICENSE +0 -0
  116. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,489 @@
1
+ """Report interfaces and data contracts for GitFlow Analytics.
2
+
3
+ This module defines the interfaces and contracts that all report generators
4
+ must adhere to, ensuring consistency and interoperability.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass
9
+ from enum import Enum
10
+ from typing import Any, Callable, Dict, List, Optional, Protocol, Union
11
+
12
+
13
+ class ReportFormat(Enum):
14
+ """Supported report format types."""
15
+
16
+ CSV = "csv"
17
+ MARKDOWN = "markdown"
18
+ JSON = "json"
19
+ HTML = "html"
20
+ PDF = "pdf"
21
+ XML = "xml"
22
+ YAML = "yaml"
23
+ EXCEL = "excel"
24
+
25
+ @classmethod
26
+ def from_string(cls, value: str) -> "ReportFormat":
27
+ """Create format from string value.
28
+
29
+ Args:
30
+ value: String representation of format
31
+
32
+ Returns:
33
+ ReportFormat enum value
34
+
35
+ Raises:
36
+ ValueError: If format is not recognized
37
+ """
38
+ value_upper = value.upper()
39
+ if value_upper in cls.__members__:
40
+ return cls[value_upper]
41
+
42
+ # Try by value
43
+ for member in cls:
44
+ if member.value == value.lower():
45
+ return member
46
+
47
+ raise ValueError(f"Unknown report format: {value}")
48
+
49
+
50
+ class ReportType(Enum):
51
+ """Types of reports that can be generated."""
52
+
53
+ WEEKLY_METRICS = "weekly_metrics"
54
+ DEVELOPER_STATS = "developer_stats"
55
+ ACTIVITY_DISTRIBUTION = "activity_distribution"
56
+ DEVELOPER_FOCUS = "developer_focus"
57
+ QUALITATIVE_INSIGHTS = "qualitative_insights"
58
+ NARRATIVE = "narrative"
59
+ DORA_METRICS = "dora_metrics"
60
+ BRANCH_HEALTH = "branch_health"
61
+ STORY_POINTS = "story_points"
62
+ UNTRACKED_COMMITS = "untracked_commits"
63
+ WEEKLY_TRENDS = "weekly_trends"
64
+ PR_ANALYSIS = "pr_analysis"
65
+ COMPREHENSIVE = "comprehensive"
66
+ CUSTOM = "custom"
67
+
68
+
69
+ @dataclass
70
+ class ReportField:
71
+ """Definition of a report field."""
72
+
73
+ name: str
74
+ field_type: type
75
+ required: bool = False
76
+ default: Any = None
77
+ description: str = ""
78
+ validator: Optional[Callable[[Any], bool]] = None
79
+ transformer: Optional[Callable[[Any], Any]] = None
80
+
81
+ def validate(self, value: Any) -> bool:
82
+ """Validate a field value.
83
+
84
+ Args:
85
+ value: Value to validate
86
+
87
+ Returns:
88
+ True if valid, False otherwise
89
+ """
90
+ if value is None:
91
+ return not self.required
92
+
93
+ if not isinstance(value, self.field_type):
94
+ return False
95
+
96
+ if self.validator:
97
+ return self.validator(value)
98
+
99
+ return True
100
+
101
+ def transform(self, value: Any) -> Any:
102
+ """Transform a field value.
103
+
104
+ Args:
105
+ value: Value to transform
106
+
107
+ Returns:
108
+ Transformed value
109
+ """
110
+ if self.transformer:
111
+ return self.transformer(value)
112
+ return value
113
+
114
+
115
+ @dataclass
116
+ class ReportSchema:
117
+ """Schema definition for a report."""
118
+
119
+ name: str
120
+ version: str
121
+ fields: List[ReportField]
122
+ description: str = ""
123
+
124
+ def validate(self, data: Dict[str, Any]) -> bool:
125
+ """Validate data against the schema.
126
+
127
+ Args:
128
+ data: Data to validate
129
+
130
+ Returns:
131
+ True if valid, False otherwise
132
+ """
133
+ for field in self.fields:
134
+ if field.required and field.name not in data:
135
+ return False
136
+
137
+ if field.name in data:
138
+ if not field.validate(data[field.name]):
139
+ return False
140
+
141
+ return True
142
+
143
+ def transform(self, data: Dict[str, Any]) -> Dict[str, Any]:
144
+ """Transform data according to the schema.
145
+
146
+ Args:
147
+ data: Data to transform
148
+
149
+ Returns:
150
+ Transformed data
151
+ """
152
+ result = {}
153
+
154
+ for field in self.fields:
155
+ if field.name in data:
156
+ result[field.name] = field.transform(data[field.name])
157
+ elif field.default is not None:
158
+ result[field.name] = field.default
159
+
160
+ return result
161
+
162
+
163
+ class ReportGenerator(Protocol):
164
+ """Protocol defining the interface for report generators."""
165
+
166
+ def generate(self, data: Any, output_path: Optional[Any] = None) -> Any:
167
+ """Generate a report from the provided data."""
168
+ ...
169
+
170
+ def validate_data(self, data: Any) -> bool:
171
+ """Validate input data."""
172
+ ...
173
+
174
+ def get_required_fields(self) -> List[str]:
175
+ """Get list of required fields."""
176
+ ...
177
+
178
+ def get_format_type(self) -> str:
179
+ """Get the format type produced by this generator."""
180
+ ...
181
+
182
+
183
+ class ReportProcessor(Protocol):
184
+ """Protocol for report processors that transform data."""
185
+
186
+ def process(self, data: Any) -> Any:
187
+ """Process data for report generation."""
188
+ ...
189
+
190
+
191
+ class ReportFormatter(Protocol):
192
+ """Protocol for report formatters."""
193
+
194
+ def format(self, data: Any) -> str:
195
+ """Format data for output."""
196
+ ...
197
+
198
+
199
+ class ReportWriter(Protocol):
200
+ """Protocol for report writers."""
201
+
202
+ def write(self, content: Union[str, bytes], path: Any) -> None:
203
+ """Write report content to storage."""
204
+ ...
205
+
206
+
207
+ class IReportFactory(ABC):
208
+ """Interface for report generator factories."""
209
+
210
+ @abstractmethod
211
+ def create_generator(
212
+ self,
213
+ report_type: ReportType,
214
+ format_type: ReportFormat,
215
+ **kwargs
216
+ ) -> ReportGenerator:
217
+ """Create a report generator.
218
+
219
+ Args:
220
+ report_type: Type of report to generate
221
+ format_type: Format for the report
222
+ **kwargs: Additional configuration
223
+
224
+ Returns:
225
+ Report generator instance
226
+ """
227
+ pass
228
+
229
+ @abstractmethod
230
+ def register_generator(
231
+ self,
232
+ report_type: ReportType,
233
+ format_type: ReportFormat,
234
+ generator_class: type
235
+ ) -> None:
236
+ """Register a report generator class.
237
+
238
+ Args:
239
+ report_type: Type of report
240
+ format_type: Format type
241
+ generator_class: Generator class to register
242
+ """
243
+ pass
244
+
245
+ @abstractmethod
246
+ def get_supported_formats(self, report_type: ReportType) -> List[ReportFormat]:
247
+ """Get supported formats for a report type.
248
+
249
+ Args:
250
+ report_type: Type of report
251
+
252
+ Returns:
253
+ List of supported formats
254
+ """
255
+ pass
256
+
257
+ @abstractmethod
258
+ def get_supported_reports(self) -> List[ReportType]:
259
+ """Get list of supported report types.
260
+
261
+ Returns:
262
+ List of supported report types
263
+ """
264
+ pass
265
+
266
+
267
+ class IReportTemplate(ABC):
268
+ """Interface for report templates."""
269
+
270
+ @abstractmethod
271
+ def render(self, context: Dict[str, Any]) -> str:
272
+ """Render the template with the given context.
273
+
274
+ Args:
275
+ context: Template context data
276
+
277
+ Returns:
278
+ Rendered template string
279
+ """
280
+ pass
281
+
282
+ @abstractmethod
283
+ def get_required_context(self) -> List[str]:
284
+ """Get list of required context variables.
285
+
286
+ Returns:
287
+ List of required variable names
288
+ """
289
+ pass
290
+
291
+ @abstractmethod
292
+ def validate_context(self, context: Dict[str, Any]) -> bool:
293
+ """Validate template context.
294
+
295
+ Args:
296
+ context: Context to validate
297
+
298
+ Returns:
299
+ True if valid, False otherwise
300
+ """
301
+ pass
302
+
303
+
304
+ class IReportAggregator(ABC):
305
+ """Interface for report aggregators that combine multiple reports."""
306
+
307
+ @abstractmethod
308
+ def add_report(self, report_id: str, report_data: Any) -> None:
309
+ """Add a report to the aggregation.
310
+
311
+ Args:
312
+ report_id: Unique identifier for the report
313
+ report_data: Report data to add
314
+ """
315
+ pass
316
+
317
+ @abstractmethod
318
+ def aggregate(self) -> Any:
319
+ """Aggregate all added reports.
320
+
321
+ Returns:
322
+ Aggregated report data
323
+ """
324
+ pass
325
+
326
+ @abstractmethod
327
+ def clear(self) -> None:
328
+ """Clear all aggregated reports."""
329
+ pass
330
+
331
+
332
+ class IReportCache(ABC):
333
+ """Interface for report caching."""
334
+
335
+ @abstractmethod
336
+ def get(self, key: str) -> Optional[Any]:
337
+ """Get cached report data.
338
+
339
+ Args:
340
+ key: Cache key
341
+
342
+ Returns:
343
+ Cached data if exists, None otherwise
344
+ """
345
+ pass
346
+
347
+ @abstractmethod
348
+ def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
349
+ """Cache report data.
350
+
351
+ Args:
352
+ key: Cache key
353
+ value: Data to cache
354
+ ttl: Time to live in seconds
355
+ """
356
+ pass
357
+
358
+ @abstractmethod
359
+ def invalidate(self, key: str) -> None:
360
+ """Invalidate cached data.
361
+
362
+ Args:
363
+ key: Cache key to invalidate
364
+ """
365
+ pass
366
+
367
+ @abstractmethod
368
+ def clear(self) -> None:
369
+ """Clear all cached data."""
370
+ pass
371
+
372
+
373
+ class IReportValidator(ABC):
374
+ """Interface for report validators."""
375
+
376
+ @abstractmethod
377
+ def validate(self, report_data: Any, schema: Optional[ReportSchema] = None) -> bool:
378
+ """Validate report data.
379
+
380
+ Args:
381
+ report_data: Data to validate
382
+ schema: Optional schema to validate against
383
+
384
+ Returns:
385
+ True if valid, False otherwise
386
+ """
387
+ pass
388
+
389
+ @abstractmethod
390
+ def get_errors(self) -> List[str]:
391
+ """Get validation errors.
392
+
393
+ Returns:
394
+ List of error messages
395
+ """
396
+ pass
397
+
398
+ @abstractmethod
399
+ def get_warnings(self) -> List[str]:
400
+ """Get validation warnings.
401
+
402
+ Returns:
403
+ List of warning messages
404
+ """
405
+ pass
406
+
407
+
408
+ class IReportExporter(ABC):
409
+ """Interface for report exporters."""
410
+
411
+ @abstractmethod
412
+ def export(
413
+ self,
414
+ report_data: Any,
415
+ format_type: ReportFormat,
416
+ output_path: Optional[Any] = None
417
+ ) -> Any:
418
+ """Export report data to specified format.
419
+
420
+ Args:
421
+ report_data: Data to export
422
+ format_type: Target format
423
+ output_path: Optional output path
424
+
425
+ Returns:
426
+ Exported data or path
427
+ """
428
+ pass
429
+
430
+ @abstractmethod
431
+ def supports_format(self, format_type: ReportFormat) -> bool:
432
+ """Check if format is supported.
433
+
434
+ Args:
435
+ format_type: Format to check
436
+
437
+ Returns:
438
+ True if supported, False otherwise
439
+ """
440
+ pass
441
+
442
+
443
+ class IReportTransformer(ABC):
444
+ """Interface for report data transformers."""
445
+
446
+ @abstractmethod
447
+ def transform(self, data: Any, target_schema: ReportSchema) -> Any:
448
+ """Transform data to match target schema.
449
+
450
+ Args:
451
+ data: Input data
452
+ target_schema: Target schema
453
+
454
+ Returns:
455
+ Transformed data
456
+ """
457
+ pass
458
+
459
+ @abstractmethod
460
+ def can_transform(self, source_type: type, target_schema: ReportSchema) -> bool:
461
+ """Check if transformation is possible.
462
+
463
+ Args:
464
+ source_type: Type of source data
465
+ target_schema: Target schema
466
+
467
+ Returns:
468
+ True if transformation is possible
469
+ """
470
+ pass
471
+
472
+
473
+ # Report configuration protocol
474
+ class ReportConfig(Protocol):
475
+ """Protocol for report configuration."""
476
+
477
+ format: ReportFormat
478
+ output_path: Optional[str]
479
+ include_metadata: bool
480
+ anonymize: bool
481
+ exclude_authors: List[str]
482
+
483
+ def to_dict(self) -> Dict[str, Any]:
484
+ """Convert configuration to dictionary."""
485
+ ...
486
+
487
+ def validate(self) -> bool:
488
+ """Validate configuration."""
489
+ ...