Skip to content

Commit

Permalink
feat: add measure_time_in_draft() and tests
Browse files Browse the repository at this point in the history
Signed-off-by: Zack Koppert <[email protected]>
  • Loading branch information
zkoppert committed Oct 23, 2024
1 parent 2f68484 commit 68a01b4
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 11 deletions.
22 changes: 12 additions & 10 deletions issue_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from markdown_writer import write_to_markdown
from most_active_mentors import count_comments_per_user, get_mentor_count
from search import get_owners_and_repositories, search_issues
from time_in_draft import measure_time_in_draft
from time_to_answer import get_stats_time_to_answer, measure_time_to_answer
from time_to_close import get_stats_time_to_close, measure_time_to_close
from time_to_first_response import (
Expand Down Expand Up @@ -112,20 +113,21 @@ def get_per_issue_metrics(
continue

issue_with_metrics = IssueWithMetrics(
issue.title, # type: ignore
issue.html_url, # type: ignore
issue.user["login"], # type: ignore
None,
None,
None,
None,
title=issue.title, # type: ignore
html_url=issue.html_url, # type: ignore
author=issue.user["login"], # type: ignore
)

# Check if issue is actually a pull request
pull_request, ready_for_review_at = None, None
if issue.issue.pull_request_urls: # type: ignore
pull_request = issue.issue.pull_request() # type: ignore
ready_for_review_at = get_time_to_ready_for_review(issue, pull_request)
if env_vars.draft_pr_tracking:
issue_with_metrics.time_in_draft = measure_time_in_draft(
issue=issue,
ready_for_review_at=ready_for_review_at,
)

if env_vars.hide_time_to_first_response is False:
issue_with_metrics.time_to_first_response = (
Expand Down Expand Up @@ -345,9 +347,9 @@ def main(): # pragma: no cover
shutil.move("issue_metrics_0.md", "issue_metrics.md")
print(
"Issue metrics markdown file is too large for GitHub issue body and has been \
split into multiple files. ie. issue_metrics.md, issue_metrics_1.md, etc. \
The full file is saved as issue_metrics_full.md\n\
See https://github.com/github/issue-metrics/blob/main/docs/dealing-with-large-issue-metrics.md"
split into multiple files. ie. issue_metrics.md, issue_metrics_1.md, etc. \
The full file is saved as issue_metrics_full.md\n\
See https://github.com/github/issue-metrics/blob/main/docs/dealing-with-large-issue-metrics.md"
)


Expand Down
60 changes: 60 additions & 0 deletions test_time_in_draft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""A test suite for the measure_time_in_draft function."""

import unittest
from datetime import datetime, timedelta
from unittest.mock import MagicMock

import pytz
from time_in_draft import measure_time_in_draft


class TestMeasureTimeInDraft(unittest.TestCase):
"""
Unit tests for the measure_time_in_draft function.
"""

def setUp(self):
"""
Setup common test data and mocks.
"""
self.issue = MagicMock()
self.issue.issue.events.return_value = [
MagicMock(
event="created_at", created_at=datetime(2021, 1, 1, tzinfo=pytz.utc)
),
MagicMock(
event="other_event", created_at=datetime(2021, 1, 2, tzinfo=pytz.utc)
),
]

def test_time_in_draft_with_ready_for_review(self):
"""
Test measure_time_in_draft when ready_for_review_at is provided.
"""
ready_for_review_at = datetime(2021, 1, 3, tzinfo=pytz.utc)
result = measure_time_in_draft(self.issue, ready_for_review_at)
expected = timedelta(days=2)
self.assertEqual(result, expected, "The time in draft should be 2 days.")

def test_time_in_draft_without_ready_for_review(self):
"""
Test measure_time_in_draft when ready_for_review_at is not provided.
"""
now = datetime(2021, 1, 4, tzinfo=pytz.utc)
with unittest.mock.patch("time_in_draft.datetime") as mock_datetime:
mock_datetime.now.return_value = now
result = measure_time_in_draft(self.issue, None)
expected = timedelta(days=3)
self.assertEqual(result, expected, "The time in draft should be 3 days.")

def test_time_in_draft_with_no_events(self):
"""
Test measure_time_in_draft when there are no events.
"""
self.issue.issue.events.return_value = []
result = measure_time_in_draft(self.issue, None)
self.assertIsNone(result, "The result should be None when there are no events.")


if __name__ == "__main__":
unittest.main()
43 changes: 43 additions & 0 deletions time_in_draft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
This module contains a function that measures the time a pull request has been in draft state.
"""

from datetime import datetime
from typing import Union

import github3
import pytz


def measure_time_in_draft(
issue: github3.issues.Issue,
ready_for_review_at: Union[datetime, None],
) -> Union[datetime, None]:
"""If a pull request has had time in the draft state, return the amount of time it was in draft.
args:
issue (github3.issues.Issue): A GitHub issue which has been pre-qualified as a pull request.
ready_for_review_at (datetime): The time the pull request was marked as ready for review.
returns:
Union[datetime, None]: The time the pull request was in draft state.
"""
events = issue.issue.events(number=50)
try:
pr_opened_at = None
for event in events:
if event.event == "created_at":
pr_opened_at = event.created_at
if pr_opened_at and ready_for_review_at:
return ready_for_review_at - pr_opened_at
if pr_opened_at and not ready_for_review_at:
return datetime.now(pytz.utc) - pr_opened_at

except TypeError as e:
print(
f"An error occurred processing review events for {issue.issue.html_url}. \
Perhaps issue contains a ghost user. {e}"
)
return None

return None
3 changes: 2 additions & 1 deletion time_to_ready_for_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@


def get_time_to_ready_for_review(
issue: github3.issues.Issue, pull_request: github3.pulls.PullRequest
issue: github3.issues.Issue,
pull_request: github3.pulls.PullRequest,
) -> Union[datetime, None]:
"""If a pull request was formerly a draft, get the time it was marked as ready
for review
Expand Down

0 comments on commit 68a01b4

Please sign in to comment.