Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: Fix time_in_draft iterator exhaustion and misnamed event#610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
zkoppert merged 4 commits intomainfromcopilot/fix-draft-pr-metrics-issue
Oct 4, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modifiedissue_metrics.py
100644 → 100755
View file
Open in desktop
Empty file.
54 changes: 44 additions & 10 deletionstest_time_in_draft.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,7 +28,7 @@ def test_time_in_draft_with_ready_for_review(self):
"""
self.issue.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
MagicMock(
Expand All@@ -46,7 +46,7 @@ def test_time_in_draft_without_ready_for_review(self):
"""
self.issue.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
]
Expand All@@ -63,15 +63,15 @@ def test_time_in_draft_multiple_intervals(self):
"""
self.issue.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
MagicMock(
event="ready_for_review",
created_at=datetime(2021, 1, 3, tzinfo=pytz.utc),
),
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 5, tzinfo=pytz.utc),
),
MagicMock(
Expand All@@ -89,7 +89,7 @@ def test_time_in_draft_ongoing_draft(self):
"""
self.issue.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
]
Expand DownExpand Up@@ -117,7 +117,7 @@ def test_time_in_draft_without_ready_for_review_and_closed(self):
"""
self.issue.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
]
Expand All@@ -133,9 +133,9 @@ def test_time_in_draft_initially_created_as_draft(self):
Test measure_time_in_draft with a PR initially created as draft.
"""
# Set up issue created_at time
self.issue.issue.created_at ="2021-01-01T00:00:00Z"
self.issue.issue.created_at =datetime(2021, 1, 1, tzinfo=pytz.utc)

# Mock events with only ready_for_review (noconverted_to_draft)
# Mock events with only ready_for_review (noconvert_to_draft)
self.issue.issue.events.return_value = [
MagicMock(
event="ready_for_review",
Expand All@@ -159,7 +159,7 @@ def test_time_in_draft_initially_created_as_draft_still_open(self):
Test measure_time_in_draft with a PR initially created as draft and still in draft.
"""
# Set up issue created_at time
self.issue.issue.created_at ="2021-01-01T00:00:00Z"
self.issue.issue.created_at =datetime(2021, 1, 1, tzinfo=pytz.utc)

# Mock events with no ready_for_review events (still draft)
self.issue.issue.events.return_value = []
Expand DownExpand Up@@ -192,7 +192,7 @@ def test_time_in_draft_with_attribute_error_scenario(self):
issue_search_result.issue.state = "open"
issue_search_result.issue.events.return_value = [
MagicMock(
event="converted_to_draft",
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
]
Expand All@@ -204,6 +204,40 @@ def test_time_in_draft_with_attribute_error_scenario(self):
expected = timedelta(days=3)
self.assertEqual(result, expected, "The time in draft should be 3 days.")

def test_time_in_draft_with_iterator_events(self):
"""
Test measure_time_in_draft with events() returning an iterator instead of a list.
This test ensures the function works correctly when events() returns an iterator
(as it does in the real GitHub API), which can only be consumed once.
"""
# Set up issue created_at time
self.issue.issue.created_at = datetime(2021, 1, 1, tzinfo=pytz.utc)

# Create an iterator of events (simulating real GitHub API behavior)
def events_iterator():
return iter(
[
MagicMock(
event="convert_to_draft",
created_at=datetime(2021, 1, 1, tzinfo=pytz.utc),
),
MagicMock(
event="ready_for_review",
created_at=datetime(2021, 1, 3, tzinfo=pytz.utc),
),
]
)

self.issue.issue.events = events_iterator

result = measure_time_in_draft(self.issue)
expected = timedelta(days=2)
self.assertEqual(
result,
expected,
"The time in draft should be 2 days when events() returns an iterator.",
)


class TestGetStatsTimeInDraft(unittest.TestCase):
"""
Expand Down
25 changes: 14 additions & 11 deletionstime_in_draft.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,7 +24,7 @@ def measure_time_in_draft(
returns:
Union[timedelta, None]: Total time the pull request has spent in draft state.
"""
events = issue.issue.events()
events =list(issue.issue.events())
draft_start = None
total_draft_time = timedelta(0)

Expand All@@ -35,25 +35,23 @@ def measure_time_in_draft(
if pull_request is None:
pull_request = issue.issue.pull_request()

pr_created_at = datetime.fromisoformat(
issue.issue.created_at.replace("Z", "+00:00")
)
pr_created_at = issue.issue.created_at

# Look for ready_for_review events to determine if PR was initially draft
ready_for_review_events = []
converted_to_draft_events = []
convert_to_draft_events = []
for event in events:
if event.event == "ready_for_review":
ready_for_review_events.append(event)
elif event.event == "converted_to_draft":
converted_to_draft_events.append(event)
elif event.event == "convert_to_draft":
convert_to_draft_events.append(event)

# If there are ready_for_review events, check if PR was initially draft
if ready_for_review_events:
first_ready_event = min(ready_for_review_events, key=lambda x: x.created_at)
prior_draft_events = [
e
for e inconverted_to_draft_events
for e inconvert_to_draft_events
if e.created_at < first_ready_event.created_at
]

Expand All@@ -62,7 +60,7 @@ def measure_time_in_draft(
total_draft_time += first_ready_event.created_at - pr_created_at

# If there are no ready_for_review events but the PR is currently draft, it might be initially draft and still open
elif not ready_for_review_events and notconverted_to_draft_events:
elif not ready_for_review_events and notconvert_to_draft_events:
# Check if PR is currently draft and open
if (
hasattr(pull_request, "draft")
Expand All@@ -77,7 +75,7 @@ def measure_time_in_draft(
pass

for event in events:
if event.event == "converted_to_draft":
if event.event == "convert_to_draft":
draft_start = event.created_at
elif event.event == "ready_for_review" and draft_start:
# Calculate draft time for this interval
Expand All@@ -88,7 +86,12 @@ def measure_time_in_draft(
if draft_start and issue.issue.state == "open":
total_draft_time += datetime.now(pytz.utc) - draft_start

return total_draft_time if total_draft_time > timedelta(0) else None
# Round to the nearest second
return (
timedelta(seconds=round(total_draft_time.total_seconds()))
if total_draft_time > timedelta(0)
else None
)


def get_stats_time_in_draft(
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp