diff --git a/issue_metrics.py b/issue_metrics.py index d8cbe1e..7a60eca 100644 --- a/issue_metrics.py +++ b/issue_metrics.py @@ -265,6 +265,45 @@ def get_average_time_to_close(issues_with_metrics: List[IssueWithMetrics]) -> ti return average_time_to_close +def get_per_issue_metrics( + issues: List[github3.issues.Issue], +) -> tuple[List[IssueWithMetrics], int, int]: + """ + Calculate the metrics for each issue in a list of GitHub issues. + + Args: + issues (List[github3.issues.Issue]): A list of GitHub issues. + + Returns: + tuple[List[IssueWithMetrics], int, int]: A tuple containing a + list of IssueWithMetrics objects, the number of open issues, + and the number of closed issues. + + """ + issues_with_metrics = [] + num_issues_open = 0 + num_issues_closed = 0 + + for issue in issues: + issue_with_metrics = IssueWithMetrics( + issue.title, # type: ignore + issue.html_url, # type: ignore + None, + None, + ) + issue_with_metrics.time_to_first_response = measure_time_to_first_response( + issue + ) + if issue.state == "closed": # type: ignore + issue_with_metrics.time_to_close = measure_time_to_close(issue) # type: ignore + num_issues_closed += 1 + elif issue.state == "open": + num_issues_open += 1 + issues_with_metrics.append(issue_with_metrics) + + return issues_with_metrics, num_issues_open, num_issues_closed + + def main(): """Run the issue-metrics script. @@ -297,27 +336,9 @@ def main(): write_to_markdown(None, None, None, None, None) return - # Find the time to first response, time to close, average, open, and closed issues - issues_with_metrics = [] - num_issues_open = 0 - num_issues_closed = 0 - - for issue in issues: - issue_with_metrics = IssueWithMetrics( - issue.title, # type: ignore - issue.html_url, # type: ignore - None, - None, - ) - issue_with_metrics.time_to_first_response = measure_time_to_first_response( - issue - ) - if issue.state == "closed": # type: ignore - issue_with_metrics.time_to_close = measure_time_to_close(issue) # type: ignore - num_issues_closed += 1 - elif issue.state == "open": - num_issues_open += 1 - issues_with_metrics.append(issue_with_metrics) + issues_with_metrics, num_issues_open, num_issues_closed = get_per_issue_metrics( + issues + ) average_time_to_first_response = get_average_time_to_first_response( issues_with_metrics diff --git a/test_issue_metrics.py b/test_issue_metrics.py index 1d7da37..c48fb94 100644 --- a/test_issue_metrics.py +++ b/test_issue_metrics.py @@ -24,6 +24,7 @@ get_average_time_to_close, get_average_time_to_first_response, get_env_vars, + get_per_issue_metrics, measure_time_to_close, measure_time_to_first_response, search_issues, @@ -464,5 +465,88 @@ def test_main_no_issues_found( mock_write_to_markdown.assert_called_once_with(None, None, None, None, None) +class TestGetPerIssueMetrics(unittest.TestCase): + """Test suite for the get_per_issue_metrics function.""" + + def test_get_per_issue_metrics(self): + """Test that the function correctly calculates the metrics for a list of GitHub issues.""" + # Create mock data + mock_issue1 = MagicMock( + title="Issue 1", + html_url="https://github.com/user/repo/issues/1", + state="open", + comments=1, + created_at="2023-01-01T00:00:00Z", + ) + + mock_comment1 = MagicMock() + mock_comment1.created_at = datetime.fromisoformat("2023-01-02T00:00:00Z") + mock_issue1.issue.comments.return_value = [mock_comment1] + + mock_issue2 = MagicMock( + title="Issue 2", + html_url="https://github.com/user/repo/issues/2", + state="closed", + comments=1, + created_at="2023-01-01T00:00:00Z", + closed_at="2023-01-04T00:00:00Z", + ) + + mock_comment2 = MagicMock() + mock_comment2.created_at = datetime.fromisoformat("2023-01-03T00:00:00Z") + mock_issue2.issue.comments.return_value = [mock_comment2] + issues = [ + mock_issue1, + mock_issue2, + ] + + # Call the function and check the result + with unittest.mock.patch( + "issue_metrics.measure_time_to_first_response", + measure_time_to_first_response, + ), unittest.mock.patch( + "issue_metrics.measure_time_to_close", measure_time_to_close + ): + ( + result_issues_with_metrics, + result_num_issues_open, + result_num_issues_closed, + ) = get_per_issue_metrics(issues) + expected_issues_with_metrics = [ + IssueWithMetrics( + "Issue 1", + "https://github.com/user/repo/issues/1", + timedelta(days=1), + None, + ), + IssueWithMetrics( + "Issue 2", + "https://github.com/user/repo/issues/2", + timedelta(days=2), + timedelta(days=3), + ), + ] + expected_num_issues_open = 1 + expected_num_issues_closed = 1 + self.assertEqual(result_num_issues_open, expected_num_issues_open) + self.assertEqual(result_num_issues_closed, expected_num_issues_closed) + self.assertEqual( + result_issues_with_metrics[0].time_to_first_response, + expected_issues_with_metrics[0].time_to_first_response, + ) + self.assertEqual( + result_issues_with_metrics[0].time_to_close, + expected_issues_with_metrics[0].time_to_close, + ) + self.assertEqual( + result_issues_with_metrics[1].time_to_first_response, + expected_issues_with_metrics[1].time_to_first_response, + ) + self.assertEqual( + result_issues_with_metrics[1].time_to_close, + expected_issues_with_metrics[1].time_to_close, + ) + + if __name__ == "__main__": unittest.main()