Skip to content

Commit d7e5626

Browse files
committed
[metrics] Include mean of commits for month and year
This commit adds the mean number of commits per repository for each week, month, and year. If the number of days requested for metrics is shorter than the interval for the metric, it is not calculated because it would not be meaningful. Signed-off-by: Jose Javier Merchante <[email protected]>
1 parent c407630 commit d7e5626

File tree

5 files changed

+77
-16
lines changed

5 files changed

+77
-16
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ trustable spdx.xml \
5454
--grimoirelab-user user --grimoirelab-password password \
5555
--opensearch-url https://admin:[email protected]:9200 \
5656
--opensearch-index events \
57+
--from-date 2024-01-01 --to-date 2025-01-01 \
5758
--repository-timeout 3600
5859
--code-file-pattern "\.py$|\.js$" \
5960
--binary-file-pattern "\.exe$|\.tar$" \
@@ -106,3 +107,11 @@ This is an example of a valid SPDX file:
106107
This is the list of the metrics generated by this tool:
107108

108109
- Number of commits per repository
110+
- Number of developers per repository
111+
- Number of developers producing up to 50% of the total contributions
112+
- Number of companies producing up to 50% of the total number of code contributions
113+
- File type metrics (code, binaries or other)
114+
- Commit side metrics (added lines and removed lines)
115+
- Message size metrics (total, mean and median)
116+
- Frequency metrics for commits (week, month and year)
117+
- Developer categories (core, regular and casual)

tests/end_to_end/test_cli.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def test_metrics(self):
5050
"--output",
5151
self.temp_file.name,
5252
"--from-date=2000-01-01",
53+
"--to-date=2025-01-01",
5354
],
5455
)
5556
self.assertEqual(result.exit_code, 0)
@@ -82,7 +83,10 @@ def test_metrics(self):
8283
self.assertEqual(quickstart_metrics["developer_categories_core"], 3)
8384
self.assertEqual(quickstart_metrics["developer_categories_regular"], 13)
8485
self.assertEqual(quickstart_metrics["developer_categories_casual"], 9)
85-
self.assertAlmostEqual(quickstart_metrics["commits_week_mean"], 0.06418, delta=0.1)
86+
# From 2000 to 2025 there are 9132 days
87+
self.assertAlmostEqual(quickstart_metrics["commits_per_week"], 164 / (9132 / 7), delta=0.1)
88+
self.assertAlmostEqual(quickstart_metrics["commits_per_month"], 164 / (9132 / 30), delta=0.1)
89+
self.assertAlmostEqual(quickstart_metrics["commits_per_year"], 164 / (9132 / 365), delta=0.1)
8690

8791
self.assertIn("SPDXRef-angular-seed", metrics["packages"])
8892
self.assertEqual(
@@ -104,7 +108,10 @@ def test_metrics(self):
104108
self.assertEqual(angular_metrics["developer_categories_core"], 16)
105109
self.assertEqual(angular_metrics["developer_categories_regular"], 31)
106110
self.assertEqual(angular_metrics["developer_categories_casual"], 11)
107-
self.assertAlmostEqual(angular_metrics["commits_week_mean"], 0.08101, delta=0.1)
111+
# From 2000 to 2025 there are 9132 days
112+
self.assertAlmostEqual(angular_metrics["commits_per_week"], 207 / (9132 / 7), delta=0.1)
113+
self.assertAlmostEqual(angular_metrics["commits_per_month"], 207 / (9132 / 30), delta=0.1)
114+
self.assertAlmostEqual(angular_metrics["commits_per_year"], 207 / (9132 / 365), delta=0.1)
108115

109116
def test_from_date(self):
110117
"""Check if it returns the number of commits of one repository from a particular date"""
@@ -127,6 +134,7 @@ def test_from_date(self):
127134
"--output",
128135
self.temp_file.name,
129136
"--from-date=2017-01-01",
137+
"--to-date=2025-01-01",
130138
],
131139
)
132140
self.assertEqual(result.exit_code, 0)
@@ -159,7 +167,10 @@ def test_from_date(self):
159167
self.assertEqual(quickstart_metrics["developer_categories_core"], 3)
160168
self.assertEqual(quickstart_metrics["developer_categories_regular"], 3)
161169
self.assertEqual(quickstart_metrics["developer_categories_casual"], 2)
162-
self.assertAlmostEqual(quickstart_metrics["commits_week_mean"], 0.00861, delta=0.1)
170+
# From 2017 to 2025 there are 2922 days
171+
self.assertAlmostEqual(quickstart_metrics["commits_per_week"], 22 / (2922 / 7), delta=0.1)
172+
self.assertAlmostEqual(quickstart_metrics["commits_per_month"], 22 / (2922 / 30), delta=0.1)
173+
self.assertAlmostEqual(quickstart_metrics["commits_per_year"], 22 / (2922 / 365), delta=0.1)
163174

164175
self.assertIn("SPDXRef-angular-seed", metrics["packages"])
165176
self.assertEqual(
@@ -181,7 +192,10 @@ def test_from_date(self):
181192
self.assertEqual(angular_metrics["developer_categories_core"], 1)
182193
self.assertEqual(angular_metrics["developer_categories_regular"], 2)
183194
self.assertEqual(angular_metrics["developer_categories_casual"], 1)
184-
self.assertAlmostEqual(angular_metrics["commits_week_mean"], 0.0043, delta=0.1)
195+
# From 2017 to 2025 there are 2922 days
196+
self.assertAlmostEqual(angular_metrics["commits_per_week"], 11 / (2922 / 7), delta=0.1)
197+
self.assertAlmostEqual(angular_metrics["commits_per_month"], 11 / (2922 / 30), delta=0.1)
198+
self.assertAlmostEqual(angular_metrics["commits_per_year"], 11 / (2922 / 365), delta=0.1)
185199

186200
def test_to_date(self):
187201
"""Check if it returns the number of commits of one repository up to a particular date"""
@@ -237,7 +251,10 @@ def test_to_date(self):
237251
self.assertEqual(quickstart_metrics["developer_categories_core"], 3)
238252
self.assertEqual(quickstart_metrics["developer_categories_regular"], 9)
239253
self.assertEqual(quickstart_metrics["developer_categories_casual"], 8)
240-
self.assertAlmostEqual(quickstart_metrics["commits_week_mean"], 0.003266620657925006, delta=0.1)
254+
# From 2000 to 2017 there are 6210 days
255+
self.assertAlmostEqual(quickstart_metrics["commits_per_week"], 142 / (6210 / 7), delta=0.1)
256+
self.assertAlmostEqual(quickstart_metrics["commits_per_month"], 142 / (6210 / 30), delta=0.1)
257+
self.assertAlmostEqual(quickstart_metrics["commits_per_year"], 142 / (6210 / 365), delta=0.1)
241258

242259
self.assertIn("SPDXRef-angular-seed", metrics["packages"])
243260
self.assertEqual(
@@ -259,7 +276,10 @@ def test_to_date(self):
259276
self.assertEqual(angular_metrics["developer_categories_core"], 16)
260277
self.assertEqual(angular_metrics["developer_categories_regular"], 30)
261278
self.assertEqual(angular_metrics["developer_categories_casual"], 10)
262-
self.assertAlmostEqual(angular_metrics["commits_week_mean"], 0.0045088566827697265, delta=0.1)
279+
# From 2000 to 2017 there are 6210 days
280+
self.assertAlmostEqual(angular_metrics["commits_per_week"], 196 / (6210 / 7), delta=0.1)
281+
self.assertAlmostEqual(angular_metrics["commits_per_month"], 196 / (6210 / 30), delta=0.1)
282+
self.assertAlmostEqual(angular_metrics["commits_per_year"], 196 / (6210 / 365), delta=0.1)
263283

264284
def test_duplicate_repo(self):
265285
"""Check if it ignores duplicated URLs"""
@@ -282,6 +302,7 @@ def test_duplicate_repo(self):
282302
"--output",
283303
self.temp_file.name,
284304
"--from-date=2000-01-01",
305+
"--to-date=2025-01-01",
285306
],
286307
)
287308
self.assertEqual(result.exit_code, 0)
@@ -315,7 +336,10 @@ def test_duplicate_repo(self):
315336
self.assertEqual(quickstart_metrics["developer_categories_core"], 3)
316337
self.assertEqual(quickstart_metrics["developer_categories_regular"], 13)
317338
self.assertEqual(quickstart_metrics["developer_categories_casual"], 9)
318-
self.assertAlmostEqual(quickstart_metrics["commits_week_mean"], 0.06418, delta=0.1)
339+
# From 2000 to 2025 there are 9132 days
340+
self.assertAlmostEqual(quickstart_metrics["commits_per_week"], 164 / (9132 / 7), delta=0.1)
341+
self.assertAlmostEqual(quickstart_metrics["commits_per_month"], 164 / (9132 / 30), delta=0.1)
342+
self.assertAlmostEqual(quickstart_metrics["commits_per_year"], 164 / (9132 / 365), delta=0.1)
319343

320344
def test_non_git_repo(self):
321345
"""Check if it flags non-git dependencies"""
@@ -338,6 +362,7 @@ def test_non_git_repo(self):
338362
"--output",
339363
self.temp_file.name,
340364
"--from-date=2000-01-01",
365+
"--to-date=2025-01-01",
341366
],
342367
)
343368
self.assertEqual(result.exit_code, 0)
@@ -371,7 +396,10 @@ def test_non_git_repo(self):
371396
self.assertEqual(quickstart_metrics["developer_categories_core"], 3)
372397
self.assertEqual(quickstart_metrics["developer_categories_regular"], 13)
373398
self.assertEqual(quickstart_metrics["developer_categories_casual"], 9)
374-
self.assertAlmostEqual(quickstart_metrics["commits_week_mean"], 0.06418, delta=0.1)
399+
# From 2000 to 2025 there are 9132 days
400+
self.assertAlmostEqual(quickstart_metrics["commits_per_week"], 164 / (9132 / 7), delta=0.1)
401+
self.assertAlmostEqual(quickstart_metrics["commits_per_month"], 164 / (9132 / 30), delta=0.1)
402+
self.assertAlmostEqual(quickstart_metrics["commits_per_year"], 164 / (9132 / 365), delta=0.1)
375403

376404
self.assertIn("SPDXRef-sql-dk", metrics["packages"])
377405
self.assertEqual(metrics["packages"]["SPDXRef-sql-dk"]["metrics"], None)

tests/unit/test_metrics.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,23 @@ def test_message_size_metrics(self):
164164
self.assertAlmostEqual(metrics["mean"], 210.11, delta=0.1)
165165
self.assertEqual(metrics["median"], 229)
166166

167-
def test_get_commits_week_mean(self):
167+
def test_get_commits_frequency(self):
168168
"""Test whether the average (mean) commits per week is calculated correctly"""
169169

170170
self.analyzer.process_events(self.events)
171-
avg = self.analyzer.get_commits_week_mean(days_interval=30)
172-
self.assertAlmostEqual(avg, 9 / 30 / 7, delta=0.1)
171+
metrics = self.analyzer.get_commit_frequency_metrics(days_interval=30)
172+
self.assertAlmostEqual(metrics["week"], 9 / (30 / 7), delta=0.1)
173+
self.assertAlmostEqual(metrics["month"], 9, delta=0.1)
174+
self.assertIsNone(metrics["year"])
175+
176+
def test_get_all_commits_frequency(self):
177+
"""Test whether the average (mean) commits per week and year is calculated correctly"""
178+
179+
self.analyzer.process_events(self.events)
180+
metrics = self.analyzer.get_commit_frequency_metrics(days_interval=365)
181+
self.assertAlmostEqual(metrics["week"], 9 / (365 / 7), delta=0.1)
182+
self.assertAlmostEqual(metrics["month"], 9 / (365 / 30), delta=0.1)
183+
self.assertAlmostEqual(metrics["year"], 9, delta=0.1)
173184

174185
def test_get_developer_categories(self):
175186
"""Test if the developer categories are calculated correctly"""

trustable_cli/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
@click.option(
7474
"--to-date",
7575
type=click.DateTime(formats=["%Y-%m-%d"]),
76-
help="End date",
76+
help="End date, by default today",
77+
default=datetime.datetime.today().strftime("%Y-%m-%d"),
7778
)
7879
@click.option("--verify-certs", is_flag=True, default=False, help="Verify SSL/TLS certificates")
7980
@click.option("--verbose", is_flag=True, default=False, help="Increase output verbosity")

trustable_cli/metrics.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,25 @@ def get_message_size_metrics(self):
147147
}
148148
return metrics
149149

150-
def get_commits_week_mean(self, days_interval: int):
150+
def get_commit_frequency_metrics(self, days_interval: int):
151151
"""
152-
Get the average (mean) number of commits per week
152+
Get the average (mean) number of commits per week, month and
153+
year if the days of interval is greater than the metrics interval.
153154
154155
:param days_interval: Interval of days to calculate the mean
155156
"""
156-
return self.total_commits / days_interval / 7
157+
metrics = {"week": None, "month": None, "year": None}
158+
159+
if days_interval >= 7:
160+
metrics["week"] = self.total_commits / (days_interval / 7)
161+
162+
if days_interval >= 30:
163+
metrics["month"] = self.total_commits / (days_interval / 30)
164+
165+
if days_interval >= 365:
166+
metrics["year"] = self.total_commits / (days_interval / 365)
167+
168+
return metrics
157169

158170
def get_developer_categories(self):
159171
"""Return the number of core, regular and casual developers"""
@@ -261,14 +273,14 @@ def get_repository_metrics(
261273
days = (to_date - from_date).days
262274
else:
263275
days = 365
264-
metrics["metrics"]["commits_week_mean"] = analyzer.get_commits_week_mean(days)
265276

266277
# Flatten two-level metrics
267278
metrics_to_flatten = {
268279
"file_types": analyzer.get_file_type_metrics(),
269280
"commit_size": analyzer.get_commit_size_metrics(),
270281
"message_size": analyzer.get_message_size_metrics(),
271282
"developer_categories": analyzer.get_developer_categories(),
283+
"commits_per": analyzer.get_commit_frequency_metrics(days),
272284
}
273285

274286
for prefix, metrics_set in metrics_to_flatten.items():

0 commit comments

Comments
 (0)