Skip to content

Commit 00db877

Browse files
committed
feat: add affectedFiles to parsed pull_request event
1 parent 0efe842 commit 00db877

6 files changed

Lines changed: 196 additions & 68 deletions

File tree

src/VCS/Adapter.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ abstract public function getPullRequestFromBranch(string $owner, string $reposit
150150
*/
151151
abstract public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array;
152152

153+
/**
154+
* Get files changed in a pull request
155+
*
156+
* @param string $owner Owner name of the repository
157+
* @param string $repositoryName Name of the repository
158+
* @param int $pullRequestNumber The pull request number
159+
* @return array<mixed> List of files changed in the pull request
160+
*/
161+
abstract public function getPullRequestFiles(string $owner, string $repositoryName, int $pullRequestNumber): array;
162+
153163
/**
154164
* Add Comment to Pull Request
155165
*

src/VCS/Adapter/Git/GitHub.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,38 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR
670670
return $response['body'] ?? [];
671671
}
672672

673+
/**
674+
* Get files changed in a pull request
675+
*
676+
* @return array<mixed> List of files changed in the pull request
677+
*/
678+
public function getPullRequestFiles(string $owner, string $repositoryName, int $pullRequestNumber): array
679+
{
680+
$allFiles = [];
681+
$perPage = 30;
682+
$currentPage = 1;
683+
684+
while (true) {
685+
$url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}/files";
686+
687+
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"], [
688+
'per_page' => $perPage,
689+
'page' => $currentPage,
690+
]);
691+
692+
$files = $response['body'] ?? [];
693+
$allFiles = array_merge($allFiles, $files);
694+
695+
if (\count($files) < $perPage) {
696+
break;
697+
}
698+
699+
$currentPage++;
700+
}
701+
702+
return $allFiles;
703+
}
704+
673705
/**
674706
* Get latest opened pull request with specific base branch
675707
* @return array<mixed>
@@ -957,6 +989,9 @@ public function getEvent(string $event, string $payload): array
957989
$baseLogin = $payloadPullRequestBaseUser['login'] ?? '';
958990
$external = $headLogin !== $baseLogin;
959991

992+
$prFiles = $this->getPullRequestFiles($owner, $repositoryName, (int)$pullRequestNumber);
993+
$affectedFiles = array_column($prFiles, 'filename');
994+
960995
return [
961996
'branch' => $branch,
962997
'branchUrl' => $branchUrl,
@@ -972,6 +1007,7 @@ public function getEvent(string $event, string $payload): array
9721007
'external' => $external,
9731008
'pullRequestNumber' => $pullRequestNumber,
9741009
'action' => $action,
1010+
'affectedFiles' => $affectedFiles,
9751011
];
9761012
case 'installation':
9771013
case 'installation_repositories':

src/VCS/Adapter/Git/Gitea.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,39 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR
651651
return $response['body'] ?? [];
652652
}
653653

654+
/**
655+
* Get files changed in a pull request
656+
*
657+
* @return array<mixed> List of files changed in the pull request
658+
*/
659+
public function getPullRequestFiles(string $owner, string $repositoryName, int $pullRequestNumber): array
660+
{
661+
$allFiles = [];
662+
$limit = 30;
663+
$maxPages = 100;
664+
665+
for ($currentPage = 1; $currentPage <= $maxPages; $currentPage++) {
666+
$url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}/files?page={$currentPage}&limit={$limit}";
667+
668+
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);
669+
670+
$responseHeaders = $response['headers'] ?? [];
671+
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
672+
if ($responseHeadersStatusCode >= 400) {
673+
throw new Exception("Failed to get pull request files: HTTP {$responseHeadersStatusCode}");
674+
}
675+
676+
$files = $response['body'] ?? [];
677+
$allFiles = array_merge($allFiles, $files);
678+
679+
if (\count($files) < $limit) {
680+
break;
681+
}
682+
}
683+
684+
return $allFiles;
685+
}
686+
654687
public function getPullRequestFromBranch(string $owner, string $repositoryName, string $branch): array
655688
{
656689

@@ -1004,6 +1037,9 @@ public function getEvent(string $event, string $payload): array
10041037
$baseRepoFullName = $payloadRepository['full_name'] ?? '';
10051038
$external = !empty($headRepoFullName) && !empty($baseRepoFullName) && $headRepoFullName !== $baseRepoFullName;
10061039

1040+
$prFiles = $this->getPullRequestFiles($owner, $repositoryName, (int)$pullRequestNumber);
1041+
$affectedFiles = array_column($prFiles, 'filename');
1042+
10071043
return [
10081044
'branch' => $branch,
10091045
'branchUrl' => $branchUrl,
@@ -1019,6 +1055,7 @@ public function getEvent(string $event, string $payload): array
10191055
'external' => $external,
10201056
'pullRequestNumber' => $pullRequestNumber,
10211057
'action' => $action,
1058+
'affectedFiles' => $affectedFiles,
10221059
];
10231060
}
10241061

tests/VCS/Adapter/GitHubTest.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public function testGetEventPullRequest(): void
109109
"pull_request": {
110110
"id": 1303283688,
111111
"state": "open",
112-
"html_url": "https://github.com/vermakhushboo/g4-node-function/pull/17",
112+
"html_url": "https://github.com/vermakhushboo/basic-js-crud/pull/1",
113113
"head": {
114114
"ref": "test",
115115
"sha": "a27dbe54b17032ee35a16c24bac151e5c2b33328",
@@ -131,11 +131,11 @@ public function testGetEventPullRequest(): void
131131
},
132132
"repository": {
133133
"id": 3498,
134-
"name": "functions-example",
134+
"name": "basic-js-crud",
135135
"owner": {
136136
"login": "vermakhushboo"
137137
},
138-
"html_url": "https://github.com/vermakhushboo/g4-node-function"
138+
"html_url": "https://github.com/vermakhushboo/basic-js-crud"
139139
},
140140
"installation": {
141141
"id": 9876
@@ -149,6 +149,8 @@ public function testGetEventPullRequest(): void
149149

150150
$this->assertSame('opened', $result['action']);
151151
$this->assertSame(1, $result['pullRequestNumber']);
152+
$this->assertCount(1, $result['affectedFiles']);
153+
$this->assertContains('README.md', $result['affectedFiles']);
152154
}
153155

154156
public function testGetEventInstallation(): void
@@ -355,6 +357,21 @@ public function testGetPullRequest(): void
355357
$this->assertSame($repositoryName, $result['base']['repo']['name']);
356358
}
357359

360+
public function testGetPullRequestFiles(): void
361+
{
362+
$owner = 'vermakhushboo';
363+
$repositoryName = 'basic-js-crud';
364+
$pullRequestNumber = 1;
365+
366+
$result = $this->vcsAdapter->getPullRequestFiles($owner, $repositoryName, $pullRequestNumber);
367+
368+
$this->assertIsArray($result);
369+
$this->assertNotEmpty($result);
370+
371+
$filenames = array_column($result, 'filename');
372+
$this->assertContains('README.md', $filenames);
373+
}
374+
358375
public function testGenerateCloneCommand(): void
359376
{
360377
\exec('rm -rf /tmp/clone-branch');

tests/VCS/Adapter/GiteaTest.php

Lines changed: 91 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,37 @@ public function testGetPullRequest(): void
479479
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
480480
}
481481

482+
public function testGetPullRequestFiles(): void
483+
{
484+
$repositoryName = 'test-get-pull-request-files-' . \uniqid();
485+
$this->vcsAdapter->createRepository(self::$owner, $repositoryName, false);
486+
487+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test');
488+
$this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-branch', 'main');
489+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch');
490+
491+
$pr = $this->vcsAdapter->createPullRequest(
492+
self::$owner,
493+
$repositoryName,
494+
'Test PR Files',
495+
'feature-branch',
496+
'main'
497+
);
498+
499+
$prNumber = $pr['number'] ?? 0;
500+
$this->assertGreaterThan(0, $prNumber);
501+
502+
$result = $this->vcsAdapter->getPullRequestFiles(self::$owner, $repositoryName, $prNumber);
503+
504+
$this->assertIsArray($result);
505+
$this->assertNotEmpty($result);
506+
507+
$filenames = array_column($result, 'filename');
508+
$this->assertContains('feature.txt', $filenames);
509+
510+
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
511+
}
512+
482513
public function testGetPullRequestWithInvalidNumber(): void
483514
{
484515
$repositoryName = 'test-get-pull-request-invalid-' . \uniqid();
@@ -891,114 +922,109 @@ public function testGetEventPush(): void
891922

892923
public function testGetEventPullRequest(): void
893924
{
925+
$repositoryName = 'test-get-event-pull-request-' . \uniqid();
926+
$this->vcsAdapter->createRepository(self::$owner, $repositoryName, false);
927+
928+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test');
929+
$this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-branch', 'main');
930+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch');
931+
932+
$pr = $this->vcsAdapter->createPullRequest(self::$owner, $repositoryName, 'Test PR', 'feature-branch', 'main');
933+
$prNumber = $pr['number'] ?? 0;
934+
$commitHash = $pr['head']['sha'] ?? 'abc123';
935+
936+
$fullName = self::$owner . '/' . $repositoryName;
937+
$giteaUrl = System::getEnv('TESTS_GITEA_URL', 'http://gitea:3000') ?? '';
938+
894939
$payload = json_encode([
895940
'action' => 'opened',
896-
'number' => 42,
941+
'number' => $prNumber,
897942
'pull_request' => [
898-
'id' => 1,
899-
'number' => 42,
900-
'state' => 'open',
901-
'title' => 'Test PR',
902943
'head' => [
903944
'ref' => 'feature-branch',
904-
'sha' => 'abc123',
905-
'repo' => [
906-
'full_name' => 'test-owner/test-repo',
907-
],
908-
'user' => [
909-
'login' => 'pr-author',
910-
],
945+
'sha' => $commitHash,
946+
'repo' => ['full_name' => $fullName],
947+
'user' => ['login' => self::$owner],
911948
],
912949
'base' => [
913950
'ref' => 'main',
914-
'sha' => 'def456',
915-
'user' => [
916-
'login' => 'base-owner',
917-
],
918-
],
919-
'user' => [
920-
'login' => 'pr-author',
921-
'avatar_url' => 'http://gitea:3000/avatars/pr-author',
951+
'user' => ['login' => self::$owner],
922952
],
953+
'user' => ['login' => self::$owner, 'avatar_url' => "{$giteaUrl}/avatars/" . self::$owner],
923954
],
924955
'repository' => [
925956
'id' => 123,
926-
'name' => 'test-repo',
927-
'full_name' => 'test-owner/test-repo',
928-
'html_url' => 'http://gitea:3000/test-owner/test-repo',
929-
'owner' => [
930-
'login' => 'test-owner',
931-
],
932-
],
933-
'sender' => [
934-
'login' => 'sender-user',
935-
'html_url' => 'http://gitea:3000/sender-user',
957+
'name' => $repositoryName,
958+
'full_name' => $fullName,
959+
'html_url' => "{$giteaUrl}/" . self::$owner . "/{$repositoryName}",
960+
'owner' => ['login' => self::$owner],
936961
],
962+
'sender' => ['html_url' => "{$giteaUrl}/" . self::$owner],
937963
]);
938964

939-
if ($payload === false) {
940-
$this->fail('Failed to encode JSON payload');
941-
}
942-
943965
$result = $this->vcsAdapter->getEvent('pull_request', $payload);
944966

945967
$this->assertIsArray($result);
946-
$this->assertArrayHasKey('branch', $result);
947-
$this->assertArrayHasKey('pullRequestNumber', $result);
948-
$this->assertArrayHasKey('action', $result);
949-
$this->assertArrayHasKey('commitHash', $result);
950-
$this->assertArrayHasKey('external', $result);
951-
952968
$this->assertSame('feature-branch', $result['branch']);
953-
$this->assertSame(42, $result['pullRequestNumber']);
969+
$this->assertSame($prNumber, $result['pullRequestNumber']);
954970
$this->assertSame('opened', $result['action']);
955-
$this->assertSame('abc123', $result['commitHash']);
956-
$this->assertSame('test-repo', $result['repositoryName']);
957-
$this->assertSame('test-owner', $result['owner']);
971+
$this->assertSame($repositoryName, $result['repositoryName']);
972+
$this->assertSame(self::$owner, $result['owner']);
958973
$this->assertFalse($result['external']);
974+
$this->assertCount(1, $result['affectedFiles']);
975+
$this->assertContains('feature.txt', $result['affectedFiles']);
976+
977+
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
959978
}
960979

961980
public function testGetEventPullRequestExternal(): void
962981
{
982+
$repositoryName = 'test-get-event-pr-external-' . \uniqid();
983+
$this->vcsAdapter->createRepository(self::$owner, $repositoryName, false);
984+
985+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test');
986+
$this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-branch', 'main');
987+
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch');
988+
989+
$pr = $this->vcsAdapter->createPullRequest(self::$owner, $repositoryName, 'External PR', 'feature-branch', 'main');
990+
$prNumber = $pr['number'] ?? 0;
991+
$commitHash = $pr['head']['sha'] ?? 'abc123';
992+
993+
$giteaUrl = System::getEnv('TESTS_GITEA_URL', 'http://gitea:3000') ?? '';
994+
963995
$payload = json_encode([
964996
'action' => 'opened',
965-
'number' => 42,
997+
'number' => $prNumber,
966998
'pull_request' => [
967999
'head' => [
9681000
'ref' => 'feature-branch',
969-
'sha' => 'abc123',
970-
'repo' => [
971-
'full_name' => 'external-user/forked-repo',
972-
],
1001+
'sha' => $commitHash,
1002+
'repo' => ['full_name' => 'external-user/' . $repositoryName],
1003+
'user' => ['login' => 'external-user'],
9731004
],
9741005
'base' => [
9751006
'ref' => 'main',
1007+
'user' => ['login' => self::$owner],
9761008
],
977-
'user' => [
978-
'avatar_url' => 'http://gitea:3000/avatars/external',
979-
],
1009+
'user' => ['avatar_url' => "{$giteaUrl}/avatars/external-user"],
9801010
],
9811011
'repository' => [
9821012
'id' => 123,
983-
'name' => 'test-repo',
984-
'full_name' => 'test-owner/test-repo',
985-
'html_url' => 'http://gitea:3000/test-owner/test-repo',
986-
'owner' => [
987-
'login' => 'test-owner',
988-
],
989-
],
990-
'sender' => [
991-
'html_url' => 'http://gitea:3000/external-user',
1013+
'name' => $repositoryName,
1014+
'full_name' => self::$owner . '/' . $repositoryName,
1015+
'html_url' => "{$giteaUrl}/" . self::$owner . "/{$repositoryName}",
1016+
'owner' => ['login' => self::$owner],
9921017
],
1018+
'sender' => ['html_url' => "{$giteaUrl}/external-user"],
9931019
]);
9941020

995-
if ($payload === false) {
996-
$this->fail('Failed to encode JSON payload');
997-
}
998-
9991021
$result = $this->vcsAdapter->getEvent('pull_request', $payload);
10001022

10011023
$this->assertTrue($result['external']);
1024+
$this->assertCount(1, $result['affectedFiles']);
1025+
$this->assertContains('feature.txt', $result['affectedFiles']);
1026+
1027+
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
10021028
}
10031029

10041030
public function testValidateWebhookEvent(): void

0 commit comments

Comments
 (0)