/
github_prs.py
205 lines (167 loc) · 6.58 KB
/
github_prs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# Copyright (C) 2014 Bitergia
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# This file is a part of GrimoireLib
# (an Python library for the MetricsGrimoire and vizGrimoire systems)
#
#
# Authors:
# Alvaro del Castillo <acs@bitergia.com>
# Daniel Izquierdo <dizquierdo@bitergia.com>
from .metrics import Metrics
class GitHubPRs():
name = "github_prs"
@classmethod
def get_section_metrics(cls):
"""
Get the mapping between metrics and sections in Manuscripts report
:return: a dict with the mapping between metrics and sections in Manuscripts report
"""
# Those metrics are only for Pull Requests
# github issues is covered as ITS
return {
"overview": {
"activity_metrics": [ClosedPR, SubmittedPR],
"author_metrics": [],
"bmi_metrics": [BMIPR],
"time_to_close_metrics": [DaysToClosePRMedian],
"projects_metrics": [Projects]
},
"com_channels": {
"activity_metrics": [],
"author_metrics": []
},
"project_activity": {
"metrics": [SubmittedPR, ClosedPR]
},
"project_community": {
"author_metrics": [],
"people_top_metrics": [],
"orgs_top_metrics": [],
},
"project_process": {
"bmi_metrics": [BMIPR],
"time_to_close_metrics": [],
"time_to_close_title": "Days to close (median and average)",
"time_to_close_review_metrics": [DaysToClosePRAverage, DaysToClosePRMedian],
"time_to_close_review_title": "Days to close review (median and average)",
"patchsets_metrics": []
}
}
class GitHubPRsMetrics(Metrics):
""" This class is the root one for all GitHubPRs (pull requests) metrics """
ds = GitHubPRs
class SubmittedPR(GitHubPRsMetrics):
id = "submitted"
name = "Submitted reviews"
desc = "Number of submitted code review processes"
FIELD_NAME = 'id'
FIELD_COUNT = 'id'
filters = {"pull_request": "true"}
class ClosedPR(GitHubPRsMetrics):
id = "closed"
name = "Closed reviews"
desc = "Number of closed review processes (merged or abandoned)"
FIELD_NAME = 'id'
FIELD_COUNT = 'id'
filters = {"pull_request": "true", "state": "closed"}
class DaysToClosePRMedian(GitHubPRsMetrics):
id = "days_to_close_pr_median"
name = "Days to close reviews (median)"
desc = "Number of days needed to close a review (median)"
FIELD_COUNT = 'time_to_close_days'
AGG_TYPE = 'median'
filters = {"pull_request": "true", "state": "closed"}
def get_agg(self):
agg = super(type(self), self).get_agg()
if agg is None:
agg = 0 # None is because NaN in ES. Let's convert to 0
return agg
class DaysToClosePRAverage(GitHubPRsMetrics):
id = "days_to_close_pr_avg"
name = "Days to close reviews (avg)"
desc = "Number of days needed to close a review (average)"
FIELD_COUNT = 'time_to_close_days'
AGG_TYPE = 'average'
filters = {"pull_request": "true", "state": "closed"}
class Projects(GitHubPRsMetrics):
""" Projects in the review code management system """
id = "projects"
name = "Projects"
desc = "Projects in the review code management system"
FIELD_NAME = 'project' # field used to list projects
class BMIPR(GitHubPRsMetrics):
"""This class calculates the efficiency closing reviews
It is calculated as the number of closed issues out of the total number
of opened ones in a period.
"""
id = "bmipr"
name = "BMI Pull Requests"
desc = "Efficiency reviewing: (closed prs)/(submitted prs)"
def __get_metrics(self):
""" Each metric must have its own filters copy to modify it freely"""
esfilters_close = None
esfilters_submit = None
if self.esfilters:
esfilters_close = self.esfilters.copy()
esfilters_submit = self.esfilters.copy()
closed = ClosedPR(self.es_url, self.es_index,
start=self.start, end=self.end,
esfilters=esfilters_close, interval=self.interval)
# For BMI we need when the ticket was closed
closed.DATE_FIELD = 'updated_at'
submitted = SubmittedPR(self.es_url, self.es_index,
start=self.start, end=self.end,
esfilters=esfilters_submit,
interval=self.interval)
return (closed, submitted)
def get_agg(self):
(closed, submitted) = self.__get_metrics()
closed_agg = closed.get_agg()
submitted_agg = submitted.get_agg()
if submitted_agg == 0:
bmi = 1 # if no submitted prs, bmi is at 100%
else:
bmi = closed_agg / submitted_agg
return bmi
def get_ts(self):
bmi = {}
(closed, submitted) = self.__get_metrics()
closed_ts = closed.get_ts()
submitted_ts = submitted.get_ts()
bmi['date'] = closed_ts['date']
bmi['unixtime'] = closed_ts['unixtime']
bmi['value'] = []
for i in range(0, len(submitted_ts['value'])):
if submitted_ts['value'][i] == 0:
bmi['value'].append(0)
else:
bmi['value'].append(closed_ts['value'][i] / submitted_ts['value'][i])
return bmi
class Reviewers(GitHubPRsMetrics):
""" People assigned to pull requests """
id = "reviewers"
name = "Reviewers"
desc = "Number of persons reviewing code review activities"
class Closers(GitHubPRsMetrics):
id = "closers"
name = "Closers"
desc = "Number of persons closing code review activities"
# Pretty similar to ITS openers
class Submitters(GitHubPRsMetrics):
id = "submitters"
name = "Submitters"
desc = "Number of persons submitting code review processes"