Skip to content

Conversation

@jordanpartridge
Copy link
Contributor

@jordanpartridge jordanpartridge commented Dec 14, 2025

Summary

Implements comprehensive support for GitHub Issue Events and Timeline tracking to provide complete visibility into issue history.

  • Created Event data object supporting all major event types (labeled, unlabeled, assigned, unassigned, milestoned, demilestoned, closed, reopened)
  • Created TimelineEvent data object with extended properties for comments, cross-references, and state changes
  • Implemented ManagesIssueEvents trait with three API methods:
    • listIssueEvents() - List all events for an issue
    • getIssueEvent() - Get specific event details by ID
    • listIssueTimeline() - Get full timeline with comments and events
  • Added comprehensive test coverage (20 tests, 78 assertions) validating all event types and helper methods
  • Integrated with IssuesService via ManagesIssueEventsInterface

API Coverage

  • GET /repos/{owner}/{repo}/issues/{issue_number}/events
  • GET /repos/{owner}/{repo}/issues/{issue_number}/timeline
  • GET /repos/{owner}/{repo}/issues/events/{event_id}

Test Plan

  • All unit tests passing (30 tests total)
  • Code formatted with Laravel Pint
  • Follows existing package patterns and conventions
  • Strongly-typed DTOs with helper methods

Closes #10

Summary by CodeRabbit

Release Notes

  • New Features
    • Added issue event tracking and timeline management. Users can now view all events associated with issues, retrieve specific event details, access complete issue activity timelines, and apply filters to narrow results based on their needs.

✏️ Tip: You can customize this high-level summary in your review settings.

Implements comprehensive support for GitHub Issue Events and Timeline tracking:

- Event data object with support for labeled, unlabeled, assigned, unassigned, milestoned, demilestoned, closed, and reopened events
- TimelineEvent data object with extended properties for comments, cross-references, and state changes
- ManagesIssueEvents trait with methods to list issue events, get specific events, and list timeline events
- Full test coverage for both data objects with validation of all event types
- Integration with IssuesService via ManagesIssueEventsInterface

API endpoints covered:
- GET /repos/{owner}/{repo}/issues/{issue_number}/events
- GET /repos/{owner}/{repo}/issues/{issue_number}/timeline
- GET /repos/{owner}/{repo}/issues/events/{event_id}

Closes #10
@coderabbitai
Copy link

coderabbitai bot commented Dec 14, 2025

Walkthrough

Introduces GitHub Issue Events and Timeline support by adding a new event management interface, corresponding data models for Events and TimelineEvents, a trait for API integration, and comprehensive unit tests. Updates the IssuesServiceInterface to extend the new ManagesIssueEventsInterface.

Changes

Cohort / File(s) Summary
Contract Definitions
src/Contracts/IssuesServiceInterface.php, src/Contracts/ManagesIssueEventsInterface.php
IssuesServiceInterface now extends ManagesIssueEventsInterface. New ManagesIssueEventsInterface defines three public methods: listIssueEvents, getIssueEvent, and listIssueTimeline with appropriate Collection and Event/TimelineEvent return types.
Data Models
src/Data/Event.php, src/Data/TimelineEvent.php
Two new readonly data classes model GitHub issue events. Event encapsulates issue event data with fields for id, event type, actor, commits, labels, assignees, milestones, and renames. TimelineEvent extends this with additional fields (body, user, updatedAt, authorAssociation, state, source). Both include fromArray/toArray serialization and type-check helper methods (isLabelEvent, isAssigneeEvent, etc.).
Service Implementation
src/Services/IssuesService.php, src/Traits/ManagesIssueEvents.php
IssuesService now composes the new ManagesIssueEvents trait. The trait implements the three event management methods, making HTTP requests to GitHub API endpoints (/repos/{owner}/{repo}/issues/{issueNumber}/events, /repos/{owner}/{repo}/issues/events/{eventId}, /repos/{owner}/{repo}/issues/{issueNumber}/timeline) and mapping responses to Event or TimelineEvent collections.
Unit Tests
tests/Unit/Data/EventTest.php, tests/Unit/Data/TimelineEventTest.php
Comprehensive test suites for Event and TimelineEvent data models, covering fromArray/toArray serialization, type-check predicates, nested object handling (User, Label), optional fields, and various event scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Attention areas:
    • Verify Event and TimelineEvent fromArray/toArray logic correctly handles nested objects (User, Label) and optional fields with proper null handling
    • Confirm API endpoint paths and parameter handling in ManagesIssueEvents trait match GitHub API specifications
    • Validate that all predicate methods (isLabelEvent, isAssigneeEvent, isMilestoneEvent, isStateEvent) cover the expected event type strings
    • Review DateTime parsing and ISO-8601 formatting consistency across both data models
    • Ensure test coverage adequately exercises edge cases for optional fields and nested structures

Possibly related issues

  • 🔒 Security audit for production release #4: Directly implements the same core functionality—ManagesIssueEventsInterface, ManagesIssueEvents trait, Event and TimelineEvent data models, and the corresponding list/get/timeline event methods—and should be linked as a duplicate or closely related implementation.

Poem

🐰 A fluent trail of events now flows,
Where issues dance through time that grows,
Events tracked, timeline bright,
From labeled labels to state's flight!
GitHub history, now in sight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Issue Events and Timeline functionality' is clear, concise, and directly summarizes the main changes in the PR—introducing event and timeline management for GitHub issues.
Linked Issues check ✅ Passed The PR successfully implements all core coding requirements from issue #10: data models for Event and TimelineEvent, three API methods (listIssueEvents, getIssueEvent, listIssueTimeline), endpoint coverage for all three GitHub API endpoints, support for multiple event types, and comprehensive test coverage with 20 tests.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing issue events and timeline functionality as specified in issue #10; no out-of-scope changes are present. The modifications include data models, contracts, service implementation, traits, and corresponding tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-events-timeline

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Contracts/ManagesIssueEventsInterface.php (1)

7-8: Add missing TimelineEvent import for better IDE support.

The interface references TimelineEvent in the PHPDoc at line 20, but the class isn't imported. While this doesn't affect runtime behavior, adding the import improves IDE autocomplete and static analysis.

Apply this diff to add the missing import:

 use ConduitUI\Issue\Data\Event;
+use ConduitUI\Issue\Data\TimelineEvent;
 use Illuminate\Support\Collection;
src/Data/Event.php (1)

56-74: Consider using strict comparison in predicate helpers.

The predicate methods correctly identify event types. For consistency with PHP best practices, consider adding the strict: true parameter to in_array() calls.

Example for isLabelEvent (apply similar pattern to other predicates):

 public function isLabelEvent(): bool
 {
-    return in_array($this->event, ['labeled', 'unlabeled']);
+    return in_array($this->event, ['labeled', 'unlabeled'], strict: true);
 }
src/Data/TimelineEvent.php (1)

77-105: Consider using strict comparison in predicate helpers.

The predicate methods correctly identify event types, including the timeline-specific isCrossReferenced() check. For consistency with PHP best practices, consider adding the strict: true parameter to in_array() calls and using strict equality (===) for the string comparisons.

Example refactor:

 public function isComment(): bool
 {
-    return $this->event === 'commented';
+    return $this->event === 'commented'; // Already strict - good!
 }

 public function isLabelEvent(): bool
 {
-    return in_array($this->event, ['labeled', 'unlabeled']);
+    return in_array($this->event, ['labeled', 'unlabeled'], strict: true);
 }

 public function isCrossReferenced(): bool
 {
-    return $this->event === 'cross-referenced';
+    return $this->event === 'cross-referenced'; // Already strict - good!
 }

Note: isComment() and isCrossReferenced() already use strict equality (===), which is excellent. Only the in_array() calls in the other methods need the strict parameter.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 208da73 and 87fdff7.

📒 Files selected for processing (8)
  • src/Contracts/IssuesServiceInterface.php (1 hunks)
  • src/Contracts/ManagesIssueEventsInterface.php (1 hunks)
  • src/Data/Event.php (1 hunks)
  • src/Data/TimelineEvent.php (1 hunks)
  • src/Services/IssuesService.php (1 hunks)
  • src/Traits/ManagesIssueEvents.php (1 hunks)
  • tests/Unit/Data/EventTest.php (1 hunks)
  • tests/Unit/Data/TimelineEventTest.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/Contracts/ManagesIssueEventsInterface.php (3)
src/Data/Issue.php (1)
  • Issue (9-86)
src/Data/Event.php (1)
  • Event (9-75)
src/Traits/ManagesIssueEvents.php (3)
  • listIssueEvents (16-24)
  • getIssueEvent (26-33)
  • listIssueTimeline (38-46)
tests/Unit/Data/EventTest.php (3)
src/Data/Event.php (7)
  • Event (9-75)
  • fromArray (24-38)
  • toArray (40-54)
  • isLabelEvent (56-59)
  • isAssigneeEvent (61-64)
  • isMilestoneEvent (66-69)
  • isStateEvent (71-74)
src/Data/Label.php (1)
  • Label (7-35)
src/Data/User.php (1)
  • User (7-38)
src/Traits/ManagesIssueEvents.php (4)
src/Data/Issue.php (1)
  • Issue (9-86)
src/Data/Event.php (2)
  • Event (9-75)
  • fromArray (24-38)
src/Data/TimelineEvent.php (2)
  • TimelineEvent (9-106)
  • fromArray (31-52)
src/Contracts/ManagesIssueEventsInterface.php (3)
  • listIssueEvents (15-15)
  • getIssueEvent (17-17)
  • listIssueTimeline (22-22)
tests/Unit/Data/TimelineEventTest.php (1)
src/Data/TimelineEvent.php (9)
  • TimelineEvent (9-106)
  • fromArray (31-52)
  • toArray (54-75)
  • isComment (77-80)
  • isLabelEvent (82-85)
  • isAssigneeEvent (87-90)
  • isMilestoneEvent (92-95)
  • isStateEvent (97-100)
  • isCrossReferenced (102-105)
src/Data/Event.php (2)
src/Data/User.php (1)
  • User (7-38)
src/Data/Label.php (1)
  • Label (7-35)
src/Data/TimelineEvent.php (3)
src/Data/Event.php (3)
  • __construct (11-22)
  • fromArray (24-38)
  • toArray (40-54)
src/Data/User.php (1)
  • User (7-38)
src/Data/Label.php (1)
  • Label (7-35)
🔇 Additional comments (12)
src/Services/IssuesService.php (1)

10-10: LGTM! Clean trait integration.

The ManagesIssueEvents trait is correctly imported and included, following the existing architectural pattern used for other traits in the service.

Also applies to: 17-17

src/Contracts/IssuesServiceInterface.php (1)

7-7: LGTM! Interface extended correctly.

The ManagesIssueEventsInterface is properly added to the interface extension list, expanding the service contract to include event management capabilities.

tests/Unit/Data/TimelineEventTest.php (1)

9-196: Excellent test coverage for TimelineEvent.

The test suite comprehensively validates:

  • Object creation from arrays with nested structures (User, Label)
  • Array serialization with proper snake_case conversion
  • All predicate helpers (isComment, isLabelEvent, isAssigneeEvent, isMilestoneEvent, isStateEvent, isCrossReferenced)
  • Optional fields (body, user, updatedAt, authorAssociation, state, stateReason, source)

This provides strong confidence in the TimelineEvent data model behavior.

tests/Unit/Data/EventTest.php (1)

9-183: Excellent test coverage for Event.

The test suite comprehensively validates:

  • Object creation from arrays with nested structures (User, Label)
  • Array serialization with proper snake_case conversion
  • All predicate helpers (isLabelEvent, isAssigneeEvent, isMilestoneEvent, isStateEvent)
  • Null handling for optional fields (actor, commitId, commitUrl, label)
  • Optional nested structures (assignee, milestone)

This provides strong confidence in the Event data model behavior.

src/Contracts/ManagesIssueEventsInterface.php (1)

15-15: LGTM! Well-defined interface methods.

The interface clearly defines the event management contract with proper type hints and PHPDoc annotations for collection types.

Also applies to: 22-22

src/Traits/ManagesIssueEvents.php (3)

16-24: LGTM! Clean implementation of listIssueEvents.

The method correctly:

  • Constructs the GitHub API endpoint with owner, repo, and issue number
  • Passes filters as query parameters
  • Maps the JSON response array to Event objects using fromArray

26-33: LGTM! Clean implementation of getIssueEvent.

The method correctly fetches a single event by ID and converts it to an Event object.


38-46: LGTM! Clean implementation of listIssueTimeline.

The method correctly fetches the timeline and maps each item to a TimelineEvent object using fromArray.

src/Data/Event.php (2)

24-38: LGTM! Well-structured fromArray factory method.

The method correctly:

  • Handles required fields (id, event, createdAt)
  • Uses isset() for conditional nested object parsing (actor, label, assignee)
  • Uses null coalescing for optional scalar fields
  • Properly delegates to User::fromArray and Label::fromArray

40-54: LGTM! Clean toArray serialization.

The method correctly serializes all fields, including nested objects via their toArray() methods, and filters out null values to produce a clean output matching the GitHub API format.

src/Data/TimelineEvent.php (2)

31-52: LGTM! Comprehensive fromArray factory method.

The method correctly handles:

  • Required fields (id, event, createdAt)
  • Optional nested objects (actor, label, assignee, user) with isset() checks
  • Optional DateTime parsing for updatedAt
  • Multiple optional fields for comments, state changes, and cross-references

This provides excellent flexibility for the diverse timeline event types.


54-75: LGTM! Clean toArray serialization.

The method correctly serializes all fields, including multiple optional nested objects and timestamps, filtering out null values to produce clean output.

@jordanpartridge
Copy link
Contributor Author

Features already shipped in #14 (bundled with gate workflow)

@jordanpartridge jordanpartridge deleted the feature/issue-events-timeline branch December 14, 2025 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Issue Events and Timeline functionality

2 participants