Repository: github/issue-metrics
Pull request #163 (2023-11-01 12:52:29)

fix: #161 Incorrect output values in issue_metrics.json
<!-- Please ensure your PR title is brief and descriptive for a good changelog entry -->
<!-- Link to issue if there is one -->

<!-- Describe what the changes are -->

## Proposed Changes
For the moment, `med` and `90p` are not supported, but the bug where `avg` is not output correctly has been addressed.

## Readiness Checklist

### Author/Contributor
- [x] If documentation is needed for this change, has that been included in this pull request
- [x] run `make lint` and fix any issues that you have introduced
- [x] run `make test` and ensure you have test coverage for the lines you are introducing

### Reviewer
- [x] Label as either `bug`, `documentation`, `enhancement`, `infrastructure`, or `breaking`



Patch:
diff --git a/json_writer.py b/json_writer.py
index 283f09f..f31e556 100644
--- a/json_writer.py
+++ b/json_writer.py
@@ -25,10 +25,10 @@ from classes import IssueWithMetrics
 
 def write_to_json(
     issues_with_metrics: Union[List[IssueWithMetrics], None],
-    average_time_to_first_response: Union[timedelta, None],
-    average_time_to_close: Union[timedelta, None],
-    average_time_to_answer: Union[timedelta, None],
-    average_time_in_labels: Union[dict, None],
+    stats_time_to_first_response: Union[dict[str, timedelta], None],
+    stats_time_to_close: Union[dict[str, timedelta], None],
+    stats_time_to_answer: Union[dict[str, timedelta], None],
+    stats_time_in_labels: Union[dict[str, dict[str, timedelta]], None],
     num_issues_opened: Union[int, None],
     num_issues_closed: Union[int, None],
     search_query: str,
@@ -76,16 +76,30 @@ def write_to_json(
     if not issues_with_metrics:
         return ""
 
+    average_time_to_first_response = None
+    if stats_time_to_first_response is not None:
+        average_time_to_first_response = stats_time_to_first_response['avg']
+
+    average_time_to_close = None
+    if stats_time_to_close is not None:
+        average_time_to_close = stats_time_to_close['avg']
+
+    average_time_to_answer = None
+    if stats_time_to_answer is not None:
+        average_time_to_answer = stats_time_to_answer['avg']
+
+    average_time_in_labels = {}
+    for stats_type, labels in stats_time_in_labels.items():
+        if stats_type == 'avg':
+            for label, time in labels.items():
+                average_time_in_labels[label] = str(time)
+
     # Create a dictionary with the metrics
-    labels_metrics = {}
-    if average_time_in_labels:
-        for label, time in average_time_in_labels.items():
-            labels_metrics[label] = str(time)
     metrics = {
         "average_time_to_first_response": str(average_time_to_first_response),
         "average_time_to_close": str(average_time_to_close),
         "average_time_to_answer": str(average_time_to_answer),
-        "average_time_in_labels": labels_metrics,
+        "average_time_in_labels": average_time_in_labels,
         "num_items_opened": num_issues_opened,
         "num_items_closed": num_issues_closed,
         "total_item_count": len(issues_with_metrics),
diff --git a/markdown_writer.py b/markdown_writer.py
index 889a525..d94cedb 100644
--- a/markdown_writer.py
+++ b/markdown_writer.py
@@ -70,9 +70,9 @@ def get_non_hidden_columns(labels) -> List[str]:
 
 def write_to_markdown(
     issues_with_metrics: Union[List[IssueWithMetrics], None],
-    average_time_to_first_response: Union[timedelta, None],
-    average_time_to_close: Union[timedelta, None],
-    average_time_to_answer: Union[timedelta, None],
+    average_time_to_first_response: Union[dict[str, timedelta], None],
+    average_time_to_close: Union[dict[str, timedelta], None],
+    average_time_to_answer: Union[dict[str, timedelta], None],
     average_time_in_labels: Union[dict, None],
     num_issues_opened: Union[int, None],
     num_issues_closed: Union[int, None],


Test patch:
diff --git a/test_json_writer.py b/test_json_writer.py
index 1a23e83..99e2b6a 100644
--- a/test_json_writer.py
+++ b/test_json_writer.py
@@ -10,6 +10,9 @@ from json_writer import write_to_json
 class TestWriteToJson(unittest.TestCase):
     """Tests for the write_to_json function."""
 
+    # Show differences without omission in assertion
+    maxDiff = None
+
     def test_write_to_json(self):
         """Test that write_to_json writes the correct JSON file."""
         issues_with_metrics = [
@@ -34,9 +37,27 @@ class TestWriteToJson(unittest.TestCase):
                 labels_metrics={},
             ),
         ]
-        average_time_to_first_response = timedelta(days=2.5)
-        average_time_to_close = timedelta(days=5)
-        average_time_to_answer = timedelta(days=1)
+
+        stats_time_to_first_response = {
+            "avg": timedelta(days=2.5),
+            "med": timedelta(days=2.5),
+            "90p": timedelta(days=1.5),
+        }
+        stats_time_to_close = {
+            "avg": timedelta(days=5),
+            "med": timedelta(days=4),
+            "90p": timedelta(days=3),
+        }
+        stats_time_to_answer = {
+            "avg": timedelta(days=1),
+            "med": timedelta(days=2),
+            "90p": timedelta(days=3),
+        }
+        stats_time_in_labels = {
+            "avg": {"bug": timedelta(days=1, hours=16, minutes=24, seconds=12)},
+            "med": {"bug": timedelta(days=1, hours=16, minutes=24, seconds=12)},
+            "90p": {"bug": timedelta(days=1, hours=16, minutes=24, seconds=12)},
+        }
         num_issues_opened = 2
         num_issues_closed = 1
 
@@ -75,12 +96,90 @@ class TestWriteToJson(unittest.TestCase):
         self.assertEqual(
             write_to_json(
                 issues_with_metrics=issues_with_metrics,
-                average_time_to_first_response=average_time_to_first_response,
-                average_time_to_close=average_time_to_close,
-                average_time_to_answer=average_time_to_answer,
-                average_time_in_labels={
-                    "bug": timedelta(days=1, hours=16, minutes=24, seconds=12)
+                stats_time_to_first_response=stats_time_to_first_response,
+                stats_time_to_close=stats_time_to_close,
+                stats_time_to_answer=stats_time_to_answer,
+                stats_time_in_labels=stats_time_in_labels,
+                num_issues_opened=num_issues_opened,
+                num_issues_closed=num_issues_closed,
+                search_query="is:issue repo:owner/repo",
+            ),
+            json.dumps(expected_output),
+        )
+
+    def test_write_to_json_with_no_response(self):
+        """Test where there is no answer to a issue."""
+        issues_with_metrics = [
+            IssueWithMetrics(
+                title="Issue 1",
+                html_url="https://github.com/owner/repo/issues/1",
+                author="alice",
+                time_to_first_response=None,
+                time_to_close=None,
+                time_to_answer=None,
+                labels_metrics={},
+            ),
+            IssueWithMetrics(
+                title="Issue 2",
+                html_url="https://github.com/owner/repo/issues/2",
+                author="bob",
+                time_to_first_response=None,
+                time_to_close=None,
+                time_to_answer=None,
+                labels_metrics={},
+            ),
+        ]
+
+        stats_time_to_first_response = None
+        stats_time_to_close = None
+        stats_time_to_answer = None
+        stats_time_in_labels = {
+            "avg": {},
+            "med": {},
+            "90p": {},
+        }
+        num_issues_opened = 2
+        num_issues_closed = 0
+
+        expected_output = {
+            "average_time_to_first_response": "None",
+            "average_time_to_close": "None",
+            "average_time_to_answer": "None",
+            "average_time_in_labels": {},
+            "num_items_opened": 2,
+            "num_items_closed": 0,
+            "total_item_count": 2,
+            "issues": [
+                {
+                    "title": "Issue 1",
+                    "html_url": "https://github.com/owner/repo/issues/1",
+                    "author": "alice",
+                    "time_to_first_response": "None",
+                    "time_to_close": "None",
+                    "time_to_answer": "None",
+                    "label_metrics": {},
                 },
+                {
+                    "title": "Issue 2",
+                    "html_url": "https://github.com/owner/repo/issues/2",
+                    "author": "bob",
+                    "time_to_first_response": "None",
+                    "time_to_close": "None",
+                    "time_to_answer": "None",
+                    "label_metrics": {},
+                },
+            ],
+            "search_query": "is:issue repo:owner/repo",
+        }
+
+        # Call the function and check the output
+        self.assertEqual(
+            write_to_json(
+                issues_with_metrics=issues_with_metrics,
+                stats_time_to_first_response=stats_time_to_first_response,
+                stats_time_to_close=stats_time_to_close,
+                stats_time_to_answer=stats_time_to_answer,
+                stats_time_in_labels=stats_time_in_labels,
                 num_issues_opened=num_issues_opened,
                 num_issues_closed=num_issues_closed,
                 search_query="is:issue repo:owner/repo",