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.
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 +4158 -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 +905 -0
  13. gitflow_analytics/config/profiles.py +264 -0
  14. gitflow_analytics/config/repository.py +124 -0
  15. gitflow_analytics/config/schema.py +444 -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 +1285 -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.11.dist-info/METADATA +1015 -0
  110. gitflow_analytics-1.3.11.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.11.dist-info}/WHEEL +0 -0
  114. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/entry_points.txt +0 -0
  115. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/licenses/LICENSE +0 -0
  116. {gitflow_analytics-1.0.3.dist-info → gitflow_analytics-1.3.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,344 @@
1
+ """Example usage of the report generation abstraction layer.
2
+
3
+ This module demonstrates how to use the new report abstraction layer
4
+ to generate reports in various formats with a unified interface.
5
+ """
6
+
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List
10
+
11
+ from .base import ReportData, ReportMetadata
12
+ from .factory import ReportBuilder, ReportFactory, create_multiple_reports, create_report
13
+ from .interfaces import ReportFormat, ReportType
14
+
15
+
16
+ def example_basic_usage():
17
+ """Example of basic report generation using the factory."""
18
+
19
+ # Create sample data
20
+ sample_commits = [
21
+ {
22
+ "hash": "abc123",
23
+ "author_email": "dev@example.com",
24
+ "author_name": "Developer One",
25
+ "timestamp": datetime.now(timezone.utc),
26
+ "message": "feat: Add new feature",
27
+ "insertions": 100,
28
+ "deletions": 20,
29
+ "files_changed": 5
30
+ }
31
+ ]
32
+
33
+ sample_developer_stats = [
34
+ {
35
+ "canonical_id": "dev@example.com",
36
+ "primary_email": "dev@example.com",
37
+ "primary_name": "Developer One",
38
+ "total_commits": 50,
39
+ "total_story_points": 25,
40
+ "ticket_coverage_pct": 85.0
41
+ }
42
+ ]
43
+
44
+ # Create ReportData
45
+ report_data = ReportData(
46
+ commits=sample_commits,
47
+ developer_stats=sample_developer_stats,
48
+ metadata=ReportMetadata(
49
+ analysis_period_weeks=4,
50
+ total_commits=len(sample_commits),
51
+ total_developers=len(sample_developer_stats)
52
+ )
53
+ )
54
+
55
+ # Method 1: Using the factory directly
56
+ factory = ReportFactory()
57
+ csv_generator = factory.create_generator(ReportType.WEEKLY_METRICS, ReportFormat.CSV)
58
+ output = csv_generator.generate(report_data, Path("weekly_metrics.csv"))
59
+
60
+ if output.success:
61
+ print(f"Report generated: {output.file_path}")
62
+ else:
63
+ print(f"Errors: {output.errors}")
64
+
65
+ # Method 2: Using the convenience function
66
+ output = create_report(
67
+ ReportType.DEVELOPER_STATS,
68
+ ReportFormat.CSV,
69
+ report_data,
70
+ "developer_stats.csv"
71
+ )
72
+
73
+ # Method 3: Using the builder pattern
74
+ builder = ReportBuilder()
75
+ generator = (builder
76
+ .add_report(ReportType.NARRATIVE, ReportFormat.MARKDOWN)
77
+ .with_config(anonymize=False, exclude_authors=["bot@example.com"])
78
+ .with_data(report_data)
79
+ .build())
80
+
81
+ output = generator.generate(report_data, Path("narrative.md"))
82
+
83
+
84
+ def example_composite_reports():
85
+ """Example of generating multiple report formats at once."""
86
+
87
+ # Create sample data
88
+ report_data = ReportData(
89
+ commits=[{"hash": "test", "author_email": "dev@test.com", "timestamp": datetime.now(timezone.utc)}],
90
+ developer_stats=[{"canonical_id": "dev@test.com", "total_commits": 10}]
91
+ )
92
+
93
+ # Generate multiple reports at once
94
+ outputs = create_multiple_reports(
95
+ [
96
+ (ReportType.WEEKLY_METRICS, ReportFormat.CSV),
97
+ (ReportType.DEVELOPER_STATS, ReportFormat.CSV),
98
+ (ReportType.COMPREHENSIVE, ReportFormat.JSON)
99
+ ],
100
+ report_data,
101
+ output_dir="reports/"
102
+ )
103
+
104
+ for output in outputs:
105
+ if output.success:
106
+ print(f"Generated: {output.file_path}")
107
+ else:
108
+ print(f"Failed: {output.errors}")
109
+
110
+
111
+ def example_custom_generator():
112
+ """Example of creating a custom report generator."""
113
+
114
+ from .base import BaseReportGenerator, ReportOutput
115
+
116
+ class CustomHTMLGenerator(BaseReportGenerator):
117
+ """Custom HTML report generator."""
118
+
119
+ def generate(self, data: ReportData, output_path: Path = None) -> ReportOutput:
120
+ """Generate HTML report."""
121
+ # Pre-process data
122
+ data = self.pre_process(data)
123
+
124
+ # Generate HTML
125
+ html_content = self._generate_html(data)
126
+
127
+ if output_path:
128
+ self.write_to_file(html_content, output_path)
129
+ return ReportOutput(
130
+ success=True,
131
+ file_path=output_path,
132
+ format="html",
133
+ size_bytes=len(html_content)
134
+ )
135
+ else:
136
+ return ReportOutput(
137
+ success=True,
138
+ content=html_content,
139
+ format="html",
140
+ size_bytes=len(html_content)
141
+ )
142
+
143
+ def get_required_fields(self) -> List[str]:
144
+ return ["commits", "developer_stats"]
145
+
146
+ def get_format_type(self) -> str:
147
+ return "html"
148
+
149
+ def _generate_html(self, data: ReportData) -> str:
150
+ """Generate HTML content."""
151
+ html = f"""
152
+ <!DOCTYPE html>
153
+ <html>
154
+ <head>
155
+ <title>GitFlow Analytics Report</title>
156
+ <style>
157
+ body {{ font-family: Arial, sans-serif; margin: 20px; }}
158
+ h1 {{ color: #333; }}
159
+ table {{ border-collapse: collapse; width: 100%; }}
160
+ th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
161
+ th {{ background-color: #f2f2f2; }}
162
+ </style>
163
+ </head>
164
+ <body>
165
+ <h1>GitFlow Analytics Report</h1>
166
+ <h2>Summary</h2>
167
+ <p>Total Commits: {len(data.commits)}</p>
168
+ <p>Total Developers: {len(data.developer_stats)}</p>
169
+
170
+ <h2>Top Contributors</h2>
171
+ <table>
172
+ <tr>
173
+ <th>Developer</th>
174
+ <th>Commits</th>
175
+ <th>Story Points</th>
176
+ </tr>
177
+ """
178
+
179
+ for dev in sorted(data.developer_stats,
180
+ key=lambda d: d.get("total_commits", 0),
181
+ reverse=True)[:10]:
182
+ html += f"""
183
+ <tr>
184
+ <td>{dev.get('primary_name', 'Unknown')}</td>
185
+ <td>{dev.get('total_commits', 0)}</td>
186
+ <td>{dev.get('total_story_points', 0)}</td>
187
+ </tr>
188
+ """
189
+
190
+ html += """
191
+ </table>
192
+ </body>
193
+ </html>
194
+ """
195
+
196
+ return html
197
+
198
+ # Register the custom generator
199
+ factory = ReportFactory()
200
+ factory.register_generator(
201
+ ReportType.CUSTOM,
202
+ ReportFormat.HTML,
203
+ CustomHTMLGenerator
204
+ )
205
+
206
+ # Use the custom generator
207
+ report_data = ReportData(
208
+ commits=[{"hash": "test", "timestamp": datetime.now(timezone.utc)}],
209
+ developer_stats=[{"primary_name": "Test Dev", "total_commits": 10}]
210
+ )
211
+
212
+ generator = factory.create_generator(ReportType.CUSTOM, ReportFormat.HTML)
213
+ output = generator.generate(report_data, Path("custom_report.html"))
214
+
215
+ if output.success:
216
+ print(f"Custom report generated: {output.file_path}")
217
+
218
+
219
+ def example_report_chaining():
220
+ """Example of chaining report generators."""
221
+
222
+ from .base import ChainedReportGenerator
223
+
224
+ # Create a chain of generators that process data sequentially
225
+ factory = ReportFactory()
226
+
227
+ # First generate CSV, then use that to generate a summary JSON
228
+ csv_gen = factory.create_generator(ReportType.WEEKLY_METRICS, ReportFormat.CSV)
229
+ json_gen = factory.create_generator(ReportType.COMPREHENSIVE, ReportFormat.JSON)
230
+
231
+ chain = ChainedReportGenerator([csv_gen, json_gen])
232
+
233
+ report_data = ReportData(
234
+ commits=[{"hash": "test", "timestamp": datetime.now(timezone.utc)}],
235
+ developer_stats=[{"canonical_id": "dev@test.com", "total_commits": 10}]
236
+ )
237
+
238
+ output = chain.generate(report_data, Path("final_output.json"))
239
+
240
+ if output.success:
241
+ print(f"Chained report generated: {output.file_path}")
242
+
243
+
244
+ def example_template_based_generation():
245
+ """Example of using templates for report generation."""
246
+
247
+ from string import Template
248
+
249
+ class TemplateReportGenerator(BaseReportGenerator):
250
+ """Template-based report generator."""
251
+
252
+ def __init__(self, template_path: Path = None, **kwargs):
253
+ super().__init__(**kwargs)
254
+ self.template_path = template_path
255
+
256
+ def generate(self, data: ReportData, output_path: Path = None) -> ReportOutput:
257
+ """Generate report from template."""
258
+ # Pre-process data
259
+ data = self.pre_process(data)
260
+
261
+ # Load template
262
+ if self.template_path and self.template_path.exists():
263
+ template_str = self.template_path.read_text()
264
+ else:
265
+ template_str = self._get_default_template()
266
+
267
+ template = Template(template_str)
268
+
269
+ # Prepare context
270
+ context = {
271
+ "total_commits": len(data.commits),
272
+ "total_developers": len(data.developer_stats),
273
+ "date": datetime.now().strftime("%Y-%m-%d"),
274
+ "top_developer": self._get_top_developer(data.developer_stats)
275
+ }
276
+
277
+ # Render template
278
+ content = template.safe_substitute(context)
279
+
280
+ if output_path:
281
+ self.write_to_file(content, output_path)
282
+ return ReportOutput(success=True, file_path=output_path, format="txt")
283
+ else:
284
+ return ReportOutput(success=True, content=content, format="txt")
285
+
286
+ def get_required_fields(self) -> List[str]:
287
+ return []
288
+
289
+ def get_format_type(self) -> str:
290
+ return "template"
291
+
292
+ def _get_default_template(self) -> str:
293
+ return """
294
+ GitFlow Analytics Report
295
+ ========================
296
+ Date: $date
297
+
298
+ Summary:
299
+ - Total Commits: $total_commits
300
+ - Total Developers: $total_developers
301
+ - Top Contributor: $top_developer
302
+
303
+ Generated by GitFlow Analytics
304
+ """
305
+
306
+ def _get_top_developer(self, developers: List[Dict[str, Any]]) -> str:
307
+ if not developers:
308
+ return "N/A"
309
+
310
+ top = max(developers, key=lambda d: d.get("total_commits", 0))
311
+ return f"{top.get('primary_name', 'Unknown')} ({top.get('total_commits', 0)} commits)"
312
+
313
+ # Use the template generator
314
+ report_data = ReportData(
315
+ commits=[{"hash": "test", "timestamp": datetime.now(timezone.utc)}],
316
+ developer_stats=[
317
+ {"primary_name": "Alice", "total_commits": 50},
318
+ {"primary_name": "Bob", "total_commits": 30}
319
+ ]
320
+ )
321
+
322
+ generator = TemplateReportGenerator()
323
+ output = generator.generate(report_data, Path("template_report.txt"))
324
+
325
+ if output.success:
326
+ print(f"Template report generated: {output.file_path}")
327
+
328
+
329
+ if __name__ == "__main__":
330
+ # Run examples
331
+ print("Running basic usage example...")
332
+ example_basic_usage()
333
+
334
+ print("\nRunning composite reports example...")
335
+ example_composite_reports()
336
+
337
+ print("\nRunning custom generator example...")
338
+ example_custom_generator()
339
+
340
+ print("\nRunning report chaining example...")
341
+ example_report_chaining()
342
+
343
+ print("\nRunning template-based generation example...")
344
+ example_template_based_generation()