Skip to content
Merged
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
65 changes: 65 additions & 0 deletions src/CreateIssueParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

/**
* Data transfer object for creating an issue
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateIssueParams
{
/**
* @param string $title Issue title (required)
* @param string $body Issue body; emitted only when non-empty
* @param string[] $assignees Usernames to assign; emitted only when non-empty
* @param string[] $labels Label names; emitted only when non-empty
* @param int|null $milestone Milestone number to assign; emitted only when set
* @param string $type Issue type name; emitted only when non-empty
*/
public function __construct(
public readonly string $title,
public readonly string $body = '',
public readonly array $assignees = [],
public readonly array $labels = [],
public readonly ?int $milestone = null,
public readonly string $type = ''
) {}

/**
* Convert to array for API request body.
*
* @return array<string, mixed>
*/
public function toArray(): array
{
$data = ['title' => $this->title];

if ($this->body !== '') {
$data['body'] = $this->body;
}
if ($this->assignees !== []) {
$data['assignees'] = $this->assignees;
}
if ($this->labels !== []) {
$data['labels'] = $this->labels;
}
if ($this->milestone !== null) {
$data['milestone'] = $this->milestone;
}
if ($this->type !== '') {
$data['type'] = $this->type;
}

return $data;
}
}
54 changes: 54 additions & 0 deletions src/CreateIssueRequestFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* Factory for creating requests to create an issue
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateIssueRequestFactory
{
public function __construct(
private readonly RequestFactoryInterface $requestFactory,
private readonly StreamFactoryInterface $streamFactory,
private readonly GithubApiConfig $config,
private readonly GithubRepository $repo,
private readonly CreateIssueParams $params
) {}

public function create(): RequestInterface
{
$url = sprintf(
'https://api.github.com/repos/%s/%s/issues',
$this->repo->owner,
$this->repo->name
);

$jsonBody = json_encode($this->params->toArray(), JSON_THROW_ON_ERROR);
$stream = $this->streamFactory->createStream($jsonBody);

$request = $this->requestFactory->createRequest('POST', $url);
if ($this->config->accessToken !== '') {
$request = $request->withHeader('Authorization', 'token ' . $this->config->accessToken);
}
$request = $request->withHeader('Accept', 'application/vnd.github.v3+json');
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody($stream);

return $request;
}
}
53 changes: 53 additions & 0 deletions src/CreateIssueTypeParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

/**
* Data transfer object for creating an organization-level issue type
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateIssueTypeParams
{
/**
* @param string $name Type name (required), e.g. "Bug"
* @param string $description Optional description; emitted only when non-empty
* @param string $color One of GitHub's enum colors (gray|blue|green|yellow|orange|red|pink|purple); emitted only when non-empty
* @param bool $isEnabled Whether the type is active in the org's UI (default: true)
*/
public function __construct(
public readonly string $name,
public readonly string $description = '',
public readonly string $color = '',
public readonly bool $isEnabled = true
) {}

/**
* @return array<string, mixed>
*/
public function toArray(): array
{
$data = [
'name' => $this->name,
'is_enabled' => $this->isEnabled,
];

if ($this->description !== '') {
$data['description'] = $this->description;
}
if ($this->color !== '') {
$data['color'] = $this->color;
}

return $data;
}
}
53 changes: 53 additions & 0 deletions src/CreateIssueTypeRequestFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* Factory for creating requests to create an organization-level issue type
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateIssueTypeRequestFactory
{
public function __construct(
private readonly RequestFactoryInterface $requestFactory,
private readonly StreamFactoryInterface $streamFactory,
private readonly GithubApiConfig $config,
private readonly GithubOrganizationId $org,
private readonly CreateIssueTypeParams $params
) {}

public function create(): RequestInterface
{
$url = sprintf(
'https://api.github.com/orgs/%s/issue-types',
(string) $this->org
);

$jsonBody = json_encode($this->params->toArray(), JSON_THROW_ON_ERROR);
$stream = $this->streamFactory->createStream($jsonBody);

$request = $this->requestFactory->createRequest('POST', $url);
if ($this->config->accessToken !== '') {
$request = $request->withHeader('Authorization', 'token ' . $this->config->accessToken);
}
$request = $request->withHeader('Accept', 'application/vnd.github.v3+json');
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody($stream);

return $request;
}
}
57 changes: 57 additions & 0 deletions src/CreateMilestoneParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

use DateTimeImmutable;

/**
* Data transfer object for creating a milestone
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateMilestoneParams
{
/**
* @param string $title Milestone title (required)
* @param string $state 'open' (default) or 'closed'
* @param string $description Optional description; emitted only when non-empty
* @param DateTimeImmutable|null $dueOn Optional due date; emitted as ISO 8601 in due_on
*/
public function __construct(
public readonly string $title,
public readonly string $state = 'open',
public readonly string $description = '',
public readonly ?DateTimeImmutable $dueOn = null
) {}

/**
* Convert to array for API request body.
*
* @return array<string, string>
*/
public function toArray(): array
{
$data = [
'title' => $this->title,
'state' => $this->state,
];

if ($this->description !== '') {
$data['description'] = $this->description;
}
if ($this->dueOn !== null) {
$data['due_on'] = $this->dueOn->format(DATE_ATOM);
}

return $data;
}
}
54 changes: 54 additions & 0 deletions src/CreateMilestoneRequestFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamFactoryInterface;

/**
* Factory for creating requests to create a milestone
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class CreateMilestoneRequestFactory
{
public function __construct(
private readonly RequestFactoryInterface $requestFactory,
private readonly StreamFactoryInterface $streamFactory,
private readonly GithubApiConfig $config,
private readonly GithubRepository $repo,
private readonly CreateMilestoneParams $params
) {}

public function create(): RequestInterface
{
$url = sprintf(
'https://api.github.com/repos/%s/%s/milestones',
$this->repo->owner,
$this->repo->name
);

$jsonBody = json_encode($this->params->toArray(), JSON_THROW_ON_ERROR);
$stream = $this->streamFactory->createStream($jsonBody);

$request = $this->requestFactory->createRequest('POST', $url);
if ($this->config->accessToken !== '') {
$request = $request->withHeader('Authorization', 'token ' . $this->config->accessToken);
}
$request = $request->withHeader('Accept', 'application/vnd.github.v3+json');
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody($stream);

return $request;
}
}
47 changes: 47 additions & 0 deletions src/DeleteIssueTypeRequestFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Horde\GithubApiClient;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;

/**
* Factory for creating requests to delete an organization-level issue type
*
* Copyright 2026 The Horde Project (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package GithubApiClient
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
*/
class DeleteIssueTypeRequestFactory
{
public function __construct(
private readonly RequestFactoryInterface $requestFactory,
private readonly GithubApiConfig $config,
private readonly GithubOrganizationId $org,
private readonly int $issueTypeId
) {}

public function create(): RequestInterface
{
$url = sprintf(
'https://api.github.com/orgs/%s/issue-types/%d',
(string) $this->org,
$this->issueTypeId
);

$request = $this->requestFactory->createRequest('DELETE', $url);
if ($this->config->accessToken !== '') {
$request = $request->withHeader('Authorization', 'token ' . $this->config->accessToken);
}
$request = $request->withHeader('Accept', 'application/vnd.github.v3+json');

return $request;
}
}
Loading
Loading