gitflow-analytics 1.0.0__py3-none-any.whl → 1.0.3__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/__init__.py +11 -9
- gitflow_analytics/_version.py +2 -2
- gitflow_analytics/cli.py +691 -243
- gitflow_analytics/cli_rich.py +353 -0
- gitflow_analytics/config.py +389 -96
- gitflow_analytics/core/analyzer.py +175 -78
- gitflow_analytics/core/branch_mapper.py +132 -132
- gitflow_analytics/core/cache.py +242 -173
- gitflow_analytics/core/identity.py +214 -178
- gitflow_analytics/extractors/base.py +13 -11
- gitflow_analytics/extractors/story_points.py +70 -59
- gitflow_analytics/extractors/tickets.py +111 -88
- gitflow_analytics/integrations/github_integration.py +91 -77
- gitflow_analytics/integrations/jira_integration.py +284 -0
- gitflow_analytics/integrations/orchestrator.py +99 -72
- gitflow_analytics/metrics/dora.py +183 -179
- gitflow_analytics/models/database.py +191 -54
- gitflow_analytics/qualitative/__init__.py +30 -0
- gitflow_analytics/qualitative/classifiers/__init__.py +13 -0
- gitflow_analytics/qualitative/classifiers/change_type.py +468 -0
- gitflow_analytics/qualitative/classifiers/domain_classifier.py +399 -0
- gitflow_analytics/qualitative/classifiers/intent_analyzer.py +436 -0
- gitflow_analytics/qualitative/classifiers/risk_analyzer.py +412 -0
- gitflow_analytics/qualitative/core/__init__.py +13 -0
- gitflow_analytics/qualitative/core/llm_fallback.py +653 -0
- gitflow_analytics/qualitative/core/nlp_engine.py +373 -0
- gitflow_analytics/qualitative/core/pattern_cache.py +457 -0
- gitflow_analytics/qualitative/core/processor.py +540 -0
- gitflow_analytics/qualitative/models/__init__.py +25 -0
- gitflow_analytics/qualitative/models/schemas.py +272 -0
- gitflow_analytics/qualitative/utils/__init__.py +13 -0
- gitflow_analytics/qualitative/utils/batch_processor.py +326 -0
- gitflow_analytics/qualitative/utils/cost_tracker.py +343 -0
- gitflow_analytics/qualitative/utils/metrics.py +347 -0
- gitflow_analytics/qualitative/utils/text_processing.py +243 -0
- gitflow_analytics/reports/analytics_writer.py +25 -8
- gitflow_analytics/reports/csv_writer.py +60 -32
- gitflow_analytics/reports/narrative_writer.py +21 -15
- gitflow_analytics/tui/__init__.py +5 -0
- gitflow_analytics/tui/app.py +721 -0
- gitflow_analytics/tui/screens/__init__.py +8 -0
- gitflow_analytics/tui/screens/analysis_progress_screen.py +487 -0
- gitflow_analytics/tui/screens/configuration_screen.py +547 -0
- gitflow_analytics/tui/screens/loading_screen.py +358 -0
- gitflow_analytics/tui/screens/main_screen.py +304 -0
- gitflow_analytics/tui/screens/results_screen.py +698 -0
- gitflow_analytics/tui/widgets/__init__.py +7 -0
- gitflow_analytics/tui/widgets/data_table.py +257 -0
- gitflow_analytics/tui/widgets/export_modal.py +301 -0
- gitflow_analytics/tui/widgets/progress_widget.py +192 -0
- gitflow_analytics-1.0.3.dist-info/METADATA +490 -0
- gitflow_analytics-1.0.3.dist-info/RECORD +62 -0
- gitflow_analytics-1.0.0.dist-info/METADATA +0 -201
- gitflow_analytics-1.0.0.dist-info/RECORD +0 -30
- {gitflow_analytics-1.0.0.dist-info → gitflow_analytics-1.0.3.dist-info}/WHEEL +0 -0
- {gitflow_analytics-1.0.0.dist-info → gitflow_analytics-1.0.3.dist-info}/entry_points.txt +0 -0
- {gitflow_analytics-1.0.0.dist-info → gitflow_analytics-1.0.3.dist-info}/licenses/LICENSE +0 -0
- {gitflow_analytics-1.0.0.dist-info → gitflow_analytics-1.0.3.dist-info}/top_level.txt +0 -0
|
@@ -1,93 +1,120 @@
|
|
|
1
1
|
"""Integration orchestrator for multiple platforms."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
2
|
+
|
|
4
3
|
import json
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Union
|
|
5
6
|
|
|
6
7
|
from ..core.cache import GitAnalysisCache
|
|
7
8
|
from .github_integration import GitHubIntegration
|
|
9
|
+
from .jira_integration import JIRAIntegration
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
class IntegrationOrchestrator:
|
|
11
13
|
"""Orchestrate integrations with multiple platforms."""
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
def __init__(self, config: Any, cache: GitAnalysisCache):
|
|
14
16
|
"""Initialize integration orchestrator."""
|
|
15
17
|
self.config = config
|
|
16
18
|
self.cache = cache
|
|
17
|
-
self.integrations = {}
|
|
18
|
-
|
|
19
|
+
self.integrations: dict[str, Union[GitHubIntegration, JIRAIntegration]] = {}
|
|
20
|
+
|
|
19
21
|
# Initialize available integrations
|
|
20
22
|
if config.github and config.github.token:
|
|
21
|
-
self.integrations[
|
|
23
|
+
self.integrations["github"] = GitHubIntegration(
|
|
22
24
|
config.github.token,
|
|
23
25
|
cache,
|
|
24
26
|
config.github.max_retries,
|
|
25
|
-
config.github.backoff_factor
|
|
27
|
+
config.github.backoff_factor,
|
|
28
|
+
allowed_ticket_platforms=getattr(config.analysis, "ticket_platforms", None),
|
|
26
29
|
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
|
|
31
|
+
# Initialize JIRA integration if configured
|
|
32
|
+
if config.jira and config.jira.access_user and config.jira.access_token:
|
|
33
|
+
# Get JIRA specific settings if available
|
|
34
|
+
jira_settings = getattr(config, "jira_integration", {})
|
|
35
|
+
if hasattr(jira_settings, "enabled") and jira_settings.enabled:
|
|
36
|
+
base_url = getattr(config.jira, "base_url", None)
|
|
37
|
+
if base_url:
|
|
38
|
+
self.integrations["jira"] = JIRAIntegration(
|
|
39
|
+
base_url,
|
|
40
|
+
config.jira.access_user,
|
|
41
|
+
config.jira.access_token,
|
|
42
|
+
cache,
|
|
43
|
+
story_point_fields=getattr(jira_settings, "story_point_fields", None),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def enrich_repository_data(
|
|
47
|
+
self, repo_config: Any, commits: list[dict[str, Any]], since: datetime
|
|
48
|
+
) -> dict[str, Any]:
|
|
30
49
|
"""Enrich repository data from all available integrations."""
|
|
31
|
-
enrichment = {
|
|
32
|
-
|
|
33
|
-
'issues': [],
|
|
34
|
-
'pr_metrics': {}
|
|
35
|
-
}
|
|
36
|
-
|
|
50
|
+
enrichment: dict[str, Any] = {"prs": [], "issues": [], "pr_metrics": {}}
|
|
51
|
+
|
|
37
52
|
# GitHub enrichment
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
if "github" in self.integrations and repo_config.github_repo:
|
|
54
|
+
github_integration = self.integrations["github"]
|
|
55
|
+
if isinstance(github_integration, GitHubIntegration):
|
|
56
|
+
try:
|
|
57
|
+
# Get PR data
|
|
58
|
+
prs = github_integration.enrich_repository_with_prs(
|
|
59
|
+
repo_config.github_repo, commits, since
|
|
60
|
+
)
|
|
61
|
+
enrichment["prs"] = prs
|
|
62
|
+
|
|
63
|
+
# Calculate PR metrics
|
|
64
|
+
if prs:
|
|
65
|
+
enrichment["pr_metrics"] = github_integration.calculate_pr_metrics(prs)
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(f" ⚠️ GitHub enrichment failed: {e}")
|
|
69
|
+
|
|
70
|
+
# JIRA enrichment for story points
|
|
71
|
+
if "jira" in self.integrations:
|
|
72
|
+
jira_integration = self.integrations["jira"]
|
|
73
|
+
if isinstance(jira_integration, JIRAIntegration):
|
|
74
|
+
try:
|
|
75
|
+
# Enrich commits with JIRA story points
|
|
76
|
+
jira_integration.enrich_commits_with_jira_data(commits)
|
|
77
|
+
|
|
78
|
+
# Enrich PRs with JIRA story points
|
|
79
|
+
if enrichment["prs"]:
|
|
80
|
+
jira_integration.enrich_prs_with_jira_data(enrichment["prs"])
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f" ⚠️ JIRA enrichment failed: {e}")
|
|
84
|
+
|
|
60
85
|
return enrichment
|
|
61
|
-
|
|
62
|
-
def get_platform_issues(self, project_key: str, since: datetime) ->
|
|
86
|
+
|
|
87
|
+
def get_platform_issues(self, project_key: str, since: datetime) -> list[dict[str, Any]]:
|
|
63
88
|
"""Get issues from all configured platforms."""
|
|
64
|
-
all_issues = []
|
|
65
|
-
|
|
89
|
+
all_issues: list[dict[str, Any]] = []
|
|
90
|
+
|
|
66
91
|
# Check cache first
|
|
67
92
|
cached_issues = []
|
|
68
|
-
for platform in [
|
|
93
|
+
for platform in ["github", "jira", "clickup", "linear"]:
|
|
69
94
|
cached = self.cache.get_cached_issues(platform, project_key)
|
|
70
95
|
cached_issues.extend(cached)
|
|
71
|
-
|
|
96
|
+
|
|
72
97
|
if cached_issues:
|
|
73
98
|
return cached_issues
|
|
74
|
-
|
|
99
|
+
|
|
75
100
|
# Future: Fetch from APIs if not cached
|
|
76
101
|
# This is where we'd add actual API calls to each platform
|
|
77
|
-
|
|
102
|
+
|
|
78
103
|
return all_issues
|
|
79
|
-
|
|
80
|
-
def export_to_json(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
|
|
105
|
+
def export_to_json(
|
|
106
|
+
self,
|
|
107
|
+
commits: list[dict[str, Any]],
|
|
108
|
+
prs: list[dict[str, Any]],
|
|
109
|
+
developer_stats: list[dict[str, Any]],
|
|
110
|
+
project_metrics: dict[str, Any],
|
|
111
|
+
dora_metrics: dict[str, Any],
|
|
112
|
+
output_path: str,
|
|
113
|
+
) -> str:
|
|
87
114
|
"""Export all data to JSON format for API consumption."""
|
|
88
|
-
|
|
115
|
+
|
|
89
116
|
# Prepare data for JSON serialization
|
|
90
|
-
def serialize_dates(obj):
|
|
117
|
+
def serialize_dates(obj: Any) -> Any:
|
|
91
118
|
"""Convert datetime objects to ISO format strings."""
|
|
92
119
|
if isinstance(obj, datetime):
|
|
93
120
|
return obj.isoformat()
|
|
@@ -96,24 +123,24 @@ class IntegrationOrchestrator:
|
|
|
96
123
|
elif isinstance(obj, list):
|
|
97
124
|
return [serialize_dates(item) for item in obj]
|
|
98
125
|
return obj
|
|
99
|
-
|
|
126
|
+
|
|
100
127
|
export_data = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
128
|
+
"metadata": {
|
|
129
|
+
"generated_at": datetime.now().isoformat(),
|
|
130
|
+
"version": "1.0",
|
|
131
|
+
"total_commits": len(commits),
|
|
132
|
+
"total_prs": len(prs),
|
|
133
|
+
"total_developers": len(developer_stats),
|
|
107
134
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
135
|
+
"commits": serialize_dates(commits),
|
|
136
|
+
"pull_requests": serialize_dates(prs),
|
|
137
|
+
"developers": serialize_dates(developer_stats),
|
|
138
|
+
"project_metrics": serialize_dates(project_metrics),
|
|
139
|
+
"dora_metrics": serialize_dates(dora_metrics),
|
|
113
140
|
}
|
|
114
|
-
|
|
141
|
+
|
|
115
142
|
# Write JSON file
|
|
116
|
-
with open(output_path,
|
|
143
|
+
with open(output_path, "w") as f:
|
|
117
144
|
json.dump(export_data, f, indent=2)
|
|
118
|
-
|
|
119
|
-
return output_path
|
|
145
|
+
|
|
146
|
+
return output_path
|