Skip to content

Commit 9201e5b

Browse files
authored
Merge pull request #68 from jaysomani/feat/gitea-pull-request-endpoints
feat: Add Gitea pull request and comment endpoints
2 parents 5769679 + 01123f5 commit 9201e5b

File tree

5 files changed

+437
-24
lines changed

5 files changed

+437
-24
lines changed

src/VCS/Adapter/Git.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function getType(): string
4545
* @param string $message Commit message
4646
* @return array<mixed> Response from API
4747
*/
48-
abstract public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file'): array;
48+
abstract public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file', string $branch = ''): array;
4949

5050
/**
5151
* Create a branch in a repository
@@ -57,4 +57,17 @@ abstract public function createFile(string $owner, string $repositoryName, strin
5757
* @return array<mixed> Response from API
5858
*/
5959
abstract public function createBranch(string $owner, string $repositoryName, string $newBranchName, string $oldBranchName): array;
60+
61+
/**
62+
* Create a pull request
63+
*
64+
* @param string $owner Owner of the repository
65+
* @param string $repositoryName Name of the repository
66+
* @param string $title PR title
67+
* @param string $head Source branch
68+
* @param string $base Target branch
69+
* @param string $body PR description (optional)
70+
* @return array<mixed> Created PR details
71+
*/
72+
abstract public function createPullRequest(string $owner, string $repositoryName, string $title, string $head, string $base, string $body = ''): array;
6073
}

src/VCS/Adapter/Git/GitHub.php

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,61 @@ public function createRepository(string $owner, string $repositoryName, bool $pr
9393

9494
return $response['body'] ?? [];
9595
}
96+
/**
97+
* Create a pull request
98+
*
99+
* @param string $owner Owner of the repository
100+
* @param string $repositoryName Name of the repository
101+
* @param string $title PR title
102+
* @param string $head Source branch
103+
* @param string $base Target branch
104+
* @param string $body PR description (optional)
105+
* @return array<mixed> Created PR details
106+
*/
107+
public function createPullRequest(string $owner, string $repositoryName, string $title, string $head, string $base, string $body = ''): array
108+
{
109+
throw new Exception('Not implemented');
110+
}
96111

97112
/**
98113
* Create a file in a repository
99114
*
100-
* @param string $owner Owner of the repository
101-
* @param string $repositoryName Name of the repository
102-
* @param string $filepath Path where file should be created
103-
* @param string $content Content of the file
104-
* @param string $message Commit message
115+
* @param string $owner Owner of the repository
116+
* @param string $repositoryName Name of the repository
117+
* @param string $filepath Path where file should be created
118+
* @param string $content Content of the file
119+
* @param string $message Commit message
120+
* @param string $branch Branch to create file on (optional)
105121
* @return array<mixed> Response from API
106122
*/
107-
public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file'): array
123+
public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file', string $branch = ''): array
108124
{
109-
throw new Exception("Not implemented");
125+
$url = "/repos/{$owner}/{$repositoryName}/contents/{$filepath}";
126+
127+
$payload = [
128+
'message' => $message,
129+
'content' => base64_encode($content),
130+
];
131+
132+
// GitHub supports branch parameter
133+
if (! empty($branch)) {
134+
$payload['branch'] = $branch;
135+
}
136+
137+
$response = $this->call(
138+
self::METHOD_PUT,
139+
$url,
140+
['Authorization' => "Bearer $this->accessToken"],
141+
$payload
142+
);
143+
144+
$responseHeaders = $response['headers'] ?? [];
145+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
146+
if ($responseHeadersStatusCode >= 400) {
147+
throw new Exception("Failed to create file {$filepath}: HTTP {$responseHeadersStatusCode}");
148+
}
149+
150+
return $response['body'] ?? [];
110151
}
111152

112153
/**

src/VCS/Adapter/Git/Gitea.php

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,25 @@ public function getRepositoryTree(string $owner, string $repositoryName, string
188188
* @param string $message Commit message
189189
* @return array<mixed> Response from API
190190
*/
191-
public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file'): array
191+
public function createFile(string $owner, string $repositoryName, string $filepath, string $content, string $message = 'Add file', string $branch = ''): array
192192
{
193193
$url = "/repos/{$owner}/{$repositoryName}/contents/{$filepath}";
194194

195+
$payload = [
196+
'content' => base64_encode($content),
197+
'message' => $message
198+
];
199+
200+
// Add branch if specified
201+
if (!empty($branch)) {
202+
$payload['branch'] = $branch;
203+
}
204+
195205
$response = $this->call(
196206
self::METHOD_POST,
197207
$url,
198208
['Authorization' => "token $this->accessToken"],
199-
[
200-
'content' => base64_encode($content),
201-
'message' => $message
202-
]
209+
$payload
203210
);
204211

205212
$responseHeaders = $response['headers'] ?? [];
@@ -347,19 +354,100 @@ public function deleteRepository(string $owner, string $repositoryName): bool
347354
return true;
348355
}
349356

357+
/**
358+
* Create a pull request
359+
*
360+
* @param string $owner Owner of the repository
361+
* @param string $repositoryName Name of the repository
362+
* @param string $title PR title
363+
* @param string $head Source branch
364+
* @param string $base Target branch
365+
* @param string $body PR description (optional)
366+
* @return array<mixed> Created PR details
367+
*/
368+
public function createPullRequest(string $owner, string $repositoryName, string $title, string $head, string $base, string $body = ''): array
369+
{
370+
$url = "/repos/{$owner}/{$repositoryName}/pulls";
371+
372+
$payload = [
373+
'title' => $title,
374+
'head' => $head,
375+
'base' => $base,
376+
];
377+
378+
if (!empty($body)) {
379+
$payload['body'] = $body;
380+
}
381+
382+
$response = $this->call(
383+
self::METHOD_POST,
384+
$url,
385+
['Authorization' => "token $this->accessToken"],
386+
$payload
387+
);
388+
389+
$responseHeaders = $response['headers'] ?? [];
390+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
391+
if ($responseHeadersStatusCode >= 400) {
392+
throw new Exception("Failed to create pull request: HTTP {$responseHeadersStatusCode}");
393+
}
394+
395+
$responseBody = $response['body'] ?? [];
396+
397+
return $responseBody;
398+
}
399+
350400
public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string
351401
{
352-
throw new Exception("Not implemented yet");
402+
$url = "/repos/{$owner}/{$repositoryName}/issues/{$pullRequestNumber}/comments";
403+
404+
$response = $this->call(self::METHOD_POST, $url, ['Authorization' => "token $this->accessToken"], ['body' => $comment]);
405+
406+
$responseHeaders = $response['headers'] ?? [];
407+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
408+
if ($responseHeadersStatusCode >= 400) {
409+
throw new Exception("Failed to create comment: HTTP {$responseHeadersStatusCode}");
410+
}
411+
412+
$responseBody = $response['body'] ?? [];
413+
414+
if (!array_key_exists('id', $responseBody)) {
415+
throw new Exception("Comment creation response is missing comment ID.");
416+
}
417+
418+
return (string) ($responseBody['id'] ?? '');
353419
}
354420

355421
public function getComment(string $owner, string $repositoryName, string $commentId): string
356422
{
357-
throw new Exception("Not implemented yet");
423+
$url = "/repos/{$owner}/{$repositoryName}/issues/comments/{$commentId}";
424+
425+
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);
426+
427+
$responseBody = $response['body'] ?? [];
428+
429+
return $responseBody['body'] ?? '';
358430
}
359431

360432
public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string
361433
{
362-
throw new Exception("Not implemented yet");
434+
$url = "/repos/{$owner}/{$repositoryName}/issues/comments/{$commentId}";
435+
436+
$response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "token $this->accessToken"], ['body' => $comment]);
437+
438+
$responseHeaders = $response['headers'] ?? [];
439+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
440+
if ($responseHeadersStatusCode >= 400) {
441+
throw new Exception("Failed to update comment: HTTP {$responseHeadersStatusCode}");
442+
}
443+
444+
$responseBody = $response['body'] ?? [];
445+
446+
if (!array_key_exists('id', $responseBody)) {
447+
throw new Exception("Comment update response is missing comment ID.");
448+
}
449+
450+
return (string) ($responseBody['id'] ?? '');
363451
}
364452

365453
public function getUser(string $username): array
@@ -374,12 +462,35 @@ public function getOwnerName(string $installationId): string
374462

375463
public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array
376464
{
377-
throw new Exception("Not implemented yet");
465+
$url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}";
466+
467+
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);
468+
469+
$responseHeaders = $response['headers'] ?? [];
470+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
471+
if ($responseHeadersStatusCode >= 400) {
472+
throw new Exception("Failed to get pull request: HTTP {$responseHeadersStatusCode}");
473+
}
474+
475+
return $response['body'] ?? [];
378476
}
379477

380478
public function getPullRequestFromBranch(string $owner, string $repositoryName, string $branch): array
381479
{
382-
throw new Exception("Not implemented yet");
480+
481+
$url = "/repos/{$owner}/{$repositoryName}/pulls?state=open&head=" . urlencode($branch);
482+
483+
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);
484+
485+
$responseHeaders = $response['headers'] ?? [];
486+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
487+
if ($responseHeadersStatusCode >= 400) {
488+
throw new Exception("Failed to list pull requests: HTTP {$responseHeadersStatusCode}");
489+
}
490+
491+
$responseBody = $response['body'] ?? [];
492+
493+
return $responseBody[0] ?? [];
383494
}
384495

385496
public function listBranches(string $owner, string $repositoryName): array

tests/VCS/Adapter/GitHubTest.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ public function testGetPullRequest(): void
344344

345345
public function testGenerateCloneCommand(): void
346346
{
347+
\exec('rm -rf /tmp/clone-branch');
347348
$gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'test', GitHub::CLONE_TYPE_BRANCH, '/tmp/clone-branch', '*');
348349
$this->assertNotEmpty($gitCloneCommand);
349350
$this->assertStringContainsString('sparse-checkout', $gitCloneCommand);
@@ -358,6 +359,7 @@ public function testGenerateCloneCommand(): void
358359

359360
public function testGenerateCloneCommandWithCommitHash(): void
360361
{
362+
\exec('rm -rf /tmp/clone-commit');
361363
$gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', '4fb10447faea8a55c5cad7b5ebdfdbedca349fe4', GitHub::CLONE_TYPE_COMMIT, '/tmp/clone-commit', '*');
362364
$this->assertNotEmpty($gitCloneCommand);
363365
$this->assertStringContainsString('sparse-checkout', $gitCloneCommand);
@@ -372,6 +374,7 @@ public function testGenerateCloneCommandWithCommitHash(): void
372374

373375
public function testGenerateCloneCommandWithTag(): void
374376
{
377+
\exec('rm -rf /tmp/clone-tag /tmp/clone-tag2 /tmp/clone-tag3');
375378
$gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', '0.1.0', GitHub::CLONE_TYPE_TAG, '/tmp/clone-tag', '*');
376379
$this->assertNotEmpty($gitCloneCommand);
377380
$this->assertStringContainsString('sparse-checkout', $gitCloneCommand);
@@ -439,8 +442,8 @@ public function testGetCommit(): void
439442
public function testGetLatestCommit(): void
440443
{
441444
$commitDetails = $this->vcsAdapter->getLatestCommit('test-kh', 'test1', 'test');
442-
$this->assertSame('Khushboo Verma', $commitDetails['commitAuthor']);
443-
$this->assertSame('https://avatars.githubusercontent.com/u/43381712?v=4', $commitDetails['commitAuthorAvatar']);
444-
$this->assertSame('https://github.com/vermakhushboo', $commitDetails['commitAuthorUrl']);
445+
$this->assertSame('appwritedemoapp[bot]', $commitDetails['commitAuthor']);
446+
$this->assertSame('https://avatars.githubusercontent.com/in/287220?v=4', $commitDetails['commitAuthorAvatar']);
447+
$this->assertSame('https://github.com/apps/appwritedemoapp', $commitDetails['commitAuthorUrl']);
445448
}
446449
}

0 commit comments

Comments
 (0)