Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/Contracts/IssuesServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

namespace ConduitUI\Issue\Contracts;

interface IssuesServiceInterface extends ManagesIssueAssigneesInterface, ManagesIssueLabelsInterface, ManagesIssuesInterface {}
interface IssuesServiceInterface extends ManagesIssueAssigneesInterface, ManagesIssueEventsInterface, ManagesIssueLabelsInterface, ManagesIssuesInterface {}
23 changes: 23 additions & 0 deletions src/Contracts/ManagesIssueEventsInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace ConduitUI\Issue\Contracts;

use ConduitUI\Issue\Data\Event;
use Illuminate\Support\Collection;

interface ManagesIssueEventsInterface
{
/**
* @return \Illuminate\Support\Collection<int, \ConduitUI\Issue\Data\Event>
*/
public function listIssueEvents(string $owner, string $repo, int $issueNumber, array $filters = []): Collection;

public function getIssueEvent(string $owner, string $repo, int $eventId): Event;

/**
* @return \Illuminate\Support\Collection<int, \ConduitUI\Issue\Data\TimelineEvent>
*/
public function listIssueTimeline(string $owner, string $repo, int $issueNumber, array $filters = []): Collection;
}
75 changes: 75 additions & 0 deletions src/Data/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace ConduitUI\Issue\Data;

use DateTime;

readonly class Event
{
public function __construct(
public int $id,
public string $event,
public ?User $actor,
public ?string $commitId,
public ?string $commitUrl,
public DateTime $createdAt,
public ?Label $label = null,
public ?User $assignee = null,
public ?array $milestone = null,
public ?array $rename = null,
) {}

public static function fromArray(array $data): self
{
return new self(
id: $data['id'],
event: $data['event'],
actor: isset($data['actor']) ? User::fromArray($data['actor']) : null,
commitId: $data['commit_id'] ?? null,
commitUrl: $data['commit_url'] ?? null,
createdAt: new DateTime($data['created_at']),
label: isset($data['label']) ? Label::fromArray($data['label']) : null,
assignee: isset($data['assignee']) ? User::fromArray($data['assignee']) : null,
milestone: $data['milestone'] ?? null,
rename: $data['rename'] ?? null,
);
}

public function toArray(): array
{
return array_filter([
'id' => $this->id,
'event' => $this->event,
'actor' => $this->actor?->toArray(),
'commit_id' => $this->commitId,
'commit_url' => $this->commitUrl,
'created_at' => $this->createdAt->format('c'),
'label' => $this->label?->toArray(),
'assignee' => $this->assignee?->toArray(),
'milestone' => $this->milestone,
'rename' => $this->rename,
], fn ($value) => $value !== null);
}

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

public function isAssigneeEvent(): bool
{
return in_array($this->event, ['assigned', 'unassigned']);
}

public function isMilestoneEvent(): bool
{
return in_array($this->event, ['milestoned', 'demilestoned']);
}

public function isStateEvent(): bool
{
return in_array($this->event, ['closed', 'reopened']);
}
}
106 changes: 106 additions & 0 deletions src/Data/TimelineEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace ConduitUI\Issue\Data;

use DateTime;

readonly class TimelineEvent
{
public function __construct(
public int $id,
public string $event,
public ?User $actor,
public DateTime $createdAt,
public ?string $commitId = null,
public ?string $commitUrl = null,
public ?Label $label = null,
public ?User $assignee = null,
public ?array $milestone = null,
public ?array $rename = null,
public ?string $body = null,
public ?User $user = null,
public ?DateTime $updatedAt = null,
public ?string $authorAssociation = null,
public ?array $source = null,
public ?string $state = null,
public ?string $stateReason = null,
) {}

public static function fromArray(array $data): self
{
return new self(
id: $data['id'],
event: $data['event'],
actor: isset($data['actor']) ? User::fromArray($data['actor']) : null,
createdAt: new DateTime($data['created_at']),
commitId: $data['commit_id'] ?? null,
commitUrl: $data['commit_url'] ?? null,
label: isset($data['label']) ? Label::fromArray($data['label']) : null,
assignee: isset($data['assignee']) ? User::fromArray($data['assignee']) : null,
milestone: $data['milestone'] ?? null,
rename: $data['rename'] ?? null,
body: $data['body'] ?? null,
user: isset($data['user']) ? User::fromArray($data['user']) : null,
updatedAt: isset($data['updated_at']) ? new DateTime($data['updated_at']) : null,
authorAssociation: $data['author_association'] ?? null,
source: $data['source'] ?? null,
state: $data['state'] ?? null,
stateReason: $data['state_reason'] ?? null,
);
}

public function toArray(): array
{
return array_filter([
'id' => $this->id,
'event' => $this->event,
'actor' => $this->actor?->toArray(),
'created_at' => $this->createdAt->format('c'),
'commit_id' => $this->commitId,
'commit_url' => $this->commitUrl,
'label' => $this->label?->toArray(),
'assignee' => $this->assignee?->toArray(),
'milestone' => $this->milestone,
'rename' => $this->rename,
'body' => $this->body,
'user' => $this->user?->toArray(),
'updated_at' => $this->updatedAt?->format('c'),
'author_association' => $this->authorAssociation,
'source' => $this->source,
'state' => $this->state,
'state_reason' => $this->stateReason,
], fn ($value) => $value !== null);
}

public function isComment(): bool
{
return $this->event === 'commented';
}

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

public function isAssigneeEvent(): bool
{
return in_array($this->event, ['assigned', 'unassigned']);
}

public function isMilestoneEvent(): bool
{
return in_array($this->event, ['milestoned', 'demilestoned']);
}

public function isStateEvent(): bool
{
return in_array($this->event, ['closed', 'reopened']);
}

public function isCrossReferenced(): bool
{
return $this->event === 'cross-referenced';
}
}
2 changes: 2 additions & 0 deletions src/Services/IssuesService.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

declare(strict_types=1);
Expand All @@ -7,12 +7,14 @@
use ConduitUi\GitHubConnector\Connector;
use ConduitUI\Issue\Contracts\IssuesServiceInterface;
use ConduitUI\Issue\Traits\ManagesIssueAssignees;
use ConduitUI\Issue\Traits\ManagesIssueEvents;
use ConduitUI\Issue\Traits\ManagesIssueLabels;
use ConduitUI\Issue\Traits\ManagesIssues;

class IssuesService implements IssuesServiceInterface
{
use ManagesIssueAssignees;
use ManagesIssueEvents;
use ManagesIssueLabels;
use ManagesIssues;

Expand Down
47 changes: 47 additions & 0 deletions src/Traits/ManagesIssueEvents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace ConduitUI\Issue\Traits;

use ConduitUI\Issue\Data\Event;
use ConduitUI\Issue\Data\TimelineEvent;
use Illuminate\Support\Collection;

trait ManagesIssueEvents
{
/**
* @return \Illuminate\Support\Collection<int, \ConduitUI\Issue\Data\Event>
*/
public function listIssueEvents(string $owner, string $repo, int $issueNumber, array $filters = []): Collection
{
$response = $this->connector->send(
$this->connector->get("/repos/{$owner}/{$repo}/issues/{$issueNumber}/events", $filters)
);

return collect($response->json())
->map(fn (array $data) => Event::fromArray($data));
}

public function getIssueEvent(string $owner, string $repo, int $eventId): Event
{
$response = $this->connector->send(
$this->connector->get("/repos/{$owner}/{$repo}/issues/events/{$eventId}")
);

return Event::fromArray($response->json());
}

/**
* @return \Illuminate\Support\Collection<int, \ConduitUI\Issue\Data\TimelineEvent>
*/
public function listIssueTimeline(string $owner, string $repo, int $issueNumber, array $filters = []): Collection
{
$response = $this->connector->send(
$this->connector->get("/repos/{$owner}/{$repo}/issues/{$issueNumber}/timeline", $filters)
);

return collect($response->json())
->map(fn (array $data) => TimelineEvent::fromArray($data));
}
}
Loading
Loading