|
1 | 1 | import contextlib
|
2 | 2 | from datetime import datetime
|
3 | 3 | from http import HTTPStatus
|
4 |
| -from typing import Any, Optional, Dict, Tuple, List, cast |
| 4 | +from typing import Optional, Dict, Tuple, List, cast |
5 | 5 |
|
6 | 6 | import requests
|
7 | 7 |
|
|
16 | 16 | GitHubPullTimelineEvent,
|
17 | 17 | GitHubPrTimelineEventsDict,
|
18 | 18 | )
|
19 |
| -from mhq.exapi.models.timeline import GithubPRTimelineEvent |
20 |
| -from mhq.store.models.code.enums import PullRequestEventType |
21 | 19 | from mhq.exapi.models.github import GitHubContributor
|
| 20 | +from mhq.exapi.models.github_timeline import GithubPullRequestTimelineEvents |
22 | 21 | from mhq.utils.log import LOG
|
23 |
| -from mhq.utils.time import dt_from_iso_time_string |
24 | 22 |
|
25 | 23 | PAGE_SIZE = 100
|
26 | 24 |
|
@@ -282,7 +280,7 @@ def _fetch_workflow_runs(page: int = 1):
|
282 | 280 |
|
283 | 281 | def get_pr_timeline_events(
|
284 | 282 | self, repo_name: str, pr_number: int
|
285 |
| - ) -> List[GithubPRTimelineEvent]: |
| 283 | + ) -> List[GithubPullRequestTimelineEvents]: |
286 | 284 |
|
287 | 285 | def _fetch_timeline_events(page: int = 1) -> List[Dict]:
|
288 | 286 | github_url = (
|
@@ -354,154 +352,30 @@ def _create_timeline_event(event_data: Dict) -> GitHubPrTimelineEventsDict:
|
354 | 352 | HTTPStatus.INTERNAL_SERVER_ERROR, f"Unexpected error: {str(e)}"
|
355 | 353 | ) from e
|
356 | 354 |
|
357 |
| - return adapt_github_timeline_events(all_timeline_events) |
358 |
| - |
359 |
| - |
360 |
| -class Event: |
361 |
| - EVENT_CONFIG = { |
362 |
| - "reviewed": { |
363 |
| - "actor_path": "user", |
364 |
| - "timestamp_field": "submitted_at", |
365 |
| - "id_path": "id", |
366 |
| - }, |
367 |
| - "ready_for_review": { |
368 |
| - "actor_path": "actor", |
369 |
| - "timestamp_field": "created_at", |
370 |
| - "id_path": "id", |
371 |
| - }, |
372 |
| - "commented": { |
373 |
| - "actor_path": "user", |
374 |
| - "timestamp_field": "created_at", |
375 |
| - "id_path": "id", |
376 |
| - }, |
377 |
| - "committed": { |
378 |
| - "actor_path": "author.name", |
379 |
| - "timestamp_field": "author.date", |
380 |
| - "id_path": "sha", |
381 |
| - }, |
382 |
| - "default": { |
383 |
| - "actor_path": "actor", |
384 |
| - "timestamp_field": "created_at", |
385 |
| - "id_path": "id", |
386 |
| - }, |
387 |
| - } |
388 |
| - |
389 |
| - def __init__(self, event_type: str, data: GitHubPullTimelineEvent): |
390 |
| - self.event_type = event_type |
391 |
| - self.data = data |
392 |
| - |
393 |
| - def _get_nested_value(self, path: str) -> Optional[Any]: |
394 |
| - keys = path.split(".") |
395 |
| - current = self.data |
396 |
| - |
397 |
| - for key in keys: |
398 |
| - if isinstance(current, dict) and key in current: |
399 |
| - current = current[key] |
400 |
| - else: |
401 |
| - return None |
402 |
| - return current |
| 355 | + return self._adapt_github_timeline_events(all_timeline_events) |
403 | 356 |
|
404 |
| - @property |
405 |
| - def user(self) -> Optional[str]: |
406 |
| - config = self.EVENT_CONFIG.get(self.event_type, self.EVENT_CONFIG["default"]) |
407 |
| - actor_path = config["actor_path"] |
| 357 | + @staticmethod |
| 358 | + def _adapt_github_timeline_events( |
| 359 | + timeline_events: List[GitHubPrTimelineEventsDict], |
| 360 | + ) -> List[GithubPullRequestTimelineEvents]: |
| 361 | + adapted_timeline_events: List[GithubPullRequestTimelineEvents] = [] |
408 | 362 |
|
409 |
| - if not actor_path: |
410 |
| - return None |
| 363 | + for timeline_event in timeline_events: |
| 364 | + event_data = timeline_event.get("data") |
| 365 | + if not event_data: |
| 366 | + continue |
411 | 367 |
|
412 |
| - if self.event_type == "committed": |
413 |
| - return self._get_nested_value(actor_path) |
| 368 | + event_type = timeline_event.get("event") |
| 369 | + if not event_type: |
| 370 | + continue |
414 | 371 |
|
415 |
| - user_data = self._get_nested_value(actor_path) |
416 |
| - if not user_data: |
417 |
| - return None |
418 |
| - if isinstance(user_data, dict) and "login" in user_data: |
419 |
| - return user_data["login"] |
420 |
| - elif hasattr(user_data, "login"): |
421 |
| - return user_data.login |
422 |
| - |
423 |
| - LOG.warning( |
424 |
| - f"User data does not contain login field for event type: {self.event_type}" |
425 |
| - ) |
426 |
| - return None |
427 |
| - |
428 |
| - @property |
429 |
| - def timestamp(self) -> Optional[datetime]: |
430 |
| - config = self.EVENT_CONFIG.get(self.event_type, self.EVENT_CONFIG["default"]) |
431 |
| - timestamp_field = config["timestamp_field"] |
432 |
| - timestamp_value = self._get_nested_value(timestamp_field) |
433 |
| - |
434 |
| - if timestamp_value: |
435 |
| - timestamp_str = str(timestamp_value) |
436 |
| - return dt_from_iso_time_string(timestamp_str) |
437 |
| - return None |
438 |
| - |
439 |
| - @property |
440 |
| - def raw_data(self) -> Dict: |
441 |
| - return cast(Dict, self.data) |
442 |
| - |
443 |
| - @property |
444 |
| - def id(self) -> Optional[str]: |
445 |
| - config = self.EVENT_CONFIG.get(self.event_type, self.EVENT_CONFIG["default"]) |
446 |
| - id_path = config["id_path"] |
447 |
| - id_value = self._get_nested_value(id_path) |
448 |
| - return str(id_value) if id_value is not None else None |
449 |
| - |
450 |
| - @property |
451 |
| - def type(self) -> Optional[PullRequestEventType]: |
452 |
| - event_type_mapping = { |
453 |
| - "assigned": PullRequestEventType.ASSIGNED, |
454 |
| - "closed": PullRequestEventType.CLOSED, |
455 |
| - "commented": PullRequestEventType.COMMENTED, |
456 |
| - "committed": PullRequestEventType.COMMITTED, |
457 |
| - "convert_to_draft": PullRequestEventType.CONVERT_TO_DRAFT, |
458 |
| - "head_ref_deleted": PullRequestEventType.HEAD_REF_DELETED, |
459 |
| - "head_ref_force_pushed": PullRequestEventType.HEAD_REF_FORCE_PUSHED, |
460 |
| - "labeled": PullRequestEventType.LABELED, |
461 |
| - "locked": PullRequestEventType.LOCKED, |
462 |
| - "merged": PullRequestEventType.MERGED, |
463 |
| - "ready_for_review": PullRequestEventType.READY_FOR_REVIEW, |
464 |
| - "referenced": PullRequestEventType.REFERENCED, |
465 |
| - "reopened": PullRequestEventType.REOPENED, |
466 |
| - "review_dismissed": PullRequestEventType.REVIEW_DISMISSED, |
467 |
| - "review_requested": PullRequestEventType.REVIEW_REQUESTED, |
468 |
| - "review_request_removed": PullRequestEventType.REVIEW_REQUEST_REMOVED, |
469 |
| - "reviewed": PullRequestEventType.REVIEW, |
470 |
| - "unassigned": PullRequestEventType.UNASSIGNED, |
471 |
| - "unlabeled": PullRequestEventType.UNLABELED, |
472 |
| - "unlocked": PullRequestEventType.UNLOCKED, |
473 |
| - } |
474 |
| - return event_type_mapping.get(self.event_type, PullRequestEventType.UNKNOWN) |
475 |
| - |
476 |
| - |
477 |
| -def adapt_github_timeline_events( |
478 |
| - timeline_events: List[GitHubPrTimelineEventsDict], |
479 |
| -) -> List[GithubPRTimelineEvent]: |
480 |
| - normalized: List[GithubPRTimelineEvent] = [] |
481 |
| - |
482 |
| - for timeline_event in timeline_events: |
483 |
| - event_data = timeline_event.get("data") |
484 |
| - if not event_data: |
485 |
| - continue |
486 |
| - |
487 |
| - event_type = timeline_event.get("event") |
488 |
| - if not event_type: |
489 |
| - continue |
490 |
| - |
491 |
| - event = Event(event_type, event_data) |
492 |
| - |
493 |
| - if all([event.timestamp, event.type, event.id, event.user]): |
494 |
| - adapted_event = GithubPRTimelineEvent( |
495 |
| - id=cast(str, event.id), |
496 |
| - user_login=cast(str, event.user), |
497 |
| - type=cast(PullRequestEventType, event.type), |
498 |
| - timestamp=cast(datetime, event.timestamp), |
499 |
| - raw_data=cast(GitHubPullTimelineEvent, event.raw_data), |
500 |
| - ) |
501 |
| - normalized.append(adapted_event) |
502 |
| - else: |
503 |
| - LOG.warning( |
504 |
| - f"Skipping incomplete timeline event: {event_type} with id: {event.id}" |
505 |
| - ) |
| 372 | + event = GithubPullRequestTimelineEvents(event_type, event_data) |
| 373 | + |
| 374 | + if all([event.timestamp, event.type, event.id, event.user]): |
| 375 | + adapted_timeline_events.append(event) |
| 376 | + else: |
| 377 | + LOG.warning( |
| 378 | + f"Skipping incomplete timeline event: {event_type} with id: {event.id}" |
| 379 | + ) |
506 | 380 |
|
507 |
| - return normalized |
| 381 | + return adapted_timeline_events |
0 commit comments