From 15dde1095463a181f5d7118f91725f97ccfcc5cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:49:51 +0000 Subject: [PATCH 01/10] Add Forgejo adapter, tests, and docker-compose support Co-authored-by: Meldiron <19310830+Meldiron@users.noreply.github.com> Agent-Logs-Url: https://github.com/utopia-php/vcs/sessions/b7718762-2b6f-4dc1-8f0d-3561ae2b01e4 --- docker-compose.yml | 51 +++- src/VCS/Adapter/Git/Forgejo.php | 57 ++++ tests/VCS/Adapter/ForgejoTest.php | 169 +++++++++++ tests/VCS/Adapter/GiteaTest.php | 488 +++++++++++++++--------------- 4 files changed, 519 insertions(+), 246 deletions(-) create mode 100644 src/VCS/Adapter/Git/Forgejo.php create mode 100644 tests/VCS/Adapter/ForgejoTest.php diff --git a/docker-compose.yml b/docker-compose.yml index 77a3aa8e..f70ad2f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,17 +7,23 @@ services: - ./tests:/usr/local/src/tests - ./phpunit.xml:/usr/local/src/phpunit.xml - gitea-data:/data:ro + - forgejo-data:/forgejo-data:ro environment: - TESTS_GITHUB_PRIVATE_KEY - TESTS_GITHUB_APP_IDENTIFIER - TESTS_GITHUB_INSTALLATION_ID - TESTS_GITEA_URL=http://gitea:3000 - - TESTS_GITEA_REQUEST_CATCHER_URL=http://request-catcher:5000 + - TESTS_GITEA_REQUEST_CATCHER_URL=http://request-catcher:5000 + - TESTS_FORGEJO_URL=http://forgejo:3000 depends_on: gitea: condition: service_healthy gitea-bootstrap: condition: service_completed_successfully + forgejo: + condition: service_healthy + forgejo-bootstrap: + condition: service_completed_successfully request-catcher: condition: service_started @@ -65,5 +71,46 @@ services: image: appwrite/requestcatcher:1.1.0 ports: - "5000:5000" + + forgejo: + image: codeberg.org/forgejo/forgejo:9 + environment: + - USER_UID=1000 + - USER_GID=1000 + - FORGEJO__database__DB_TYPE=sqlite3 + - FORGEJO__security__INSTALL_LOCK=true + - FORGEJO__webhook__ALLOWED_HOST_LIST=* + - FORGEJO__webhook__SKIP_TLS_VERIFY=true + - FORGEJO__webhook__DELIVER_TIMEOUT=10 + - FORGEJO__server__LOCAL_ROOT_URL=http://forgejo:3000/ + volumes: + - forgejo-data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 10s + + forgejo-bootstrap: + image: codeberg.org/forgejo/forgejo:9 + volumes: + - forgejo-data:/data + depends_on: + forgejo: + condition: service_healthy + entrypoint: /bin/sh + environment: + - FORGEJO_ADMIN_USERNAME=${FORGEJO_ADMIN_USERNAME:-utopia} + - FORGEJO_ADMIN_PASSWORD=${FORGEJO_ADMIN_PASSWORD:-password} + - FORGEJO_ADMIN_EMAIL=${FORGEJO_ADMIN_EMAIL:-utopia@example.com} + command: > + -c " + su git -c \"forgejo admin user create --username $$FORGEJO_ADMIN_USERNAME --password $$FORGEJO_ADMIN_PASSWORD --email $$FORGEJO_ADMIN_EMAIL --admin --must-change-password=false\" || true && + TOKEN=$$(su git -c \"forgejo admin user generate-access-token --username $$FORGEJO_ADMIN_USERNAME --token-name $$FORGEJO_ADMIN_USERNAME-token --scopes all --raw\") && + echo $$TOKEN > /data/forgejo/token.txt + " + volumes: - gitea-data: \ No newline at end of file + gitea-data: + forgejo-data: \ No newline at end of file diff --git a/src/VCS/Adapter/Git/Forgejo.php b/src/VCS/Adapter/Git/Forgejo.php new file mode 100644 index 00000000..1be90351 --- /dev/null +++ b/src/VCS/Adapter/Git/Forgejo.php @@ -0,0 +1,57 @@ + $events Events to trigger the webhook + * @return int Webhook ID + */ + public function createWebhook(string $owner, string $repositoryName, string $url, string $secret, array $events = ['push', 'pull_request']): int + { + $response = $this->call( + self::METHOD_POST, + "/repos/{$owner}/{$repositoryName}/hooks", + ['Authorization' => "token $this->accessToken"], + [ + 'type' => 'forgejo', + 'active' => true, + 'events' => $events, + 'config' => [ + 'url' => $url, + 'content_type' => 'json', + 'secret' => $secret, + ], + ] + ); + + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { + throw new Exception("Failed to create webhook: HTTP {$responseHeadersStatusCode}"); + } + + return (int) ($response['body']['id'] ?? 0); + } +} diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php new file mode 100644 index 00000000..833a6093 --- /dev/null +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -0,0 +1,169 @@ +setupForgejo(); + } + + $adapter = new Forgejo(new Cache(new None())); + $forgejoUrl = System::getEnv('TESTS_FORGEJO_URL', 'http://forgejo:3000') ?? ''; + + $adapter->initializeVariables( + installationId: '', + privateKey: '', + appId: '', + accessToken: static::$accessToken, + refreshToken: '' + ); + $adapter->setEndpoint($forgejoUrl); + if (empty(static::$owner)) { + $orgName = 'test-org-' . \uniqid(); + static::$owner = $adapter->createOrganization($orgName); + } + + $this->vcsAdapter = $adapter; + } + + protected function setupForgejo(): void + { + $tokenFile = '/forgejo-data/forgejo/token.txt'; + + if (file_exists($tokenFile)) { + $contents = file_get_contents($tokenFile); + if ($contents !== false) { + static::$accessToken = trim($contents); + } + } + } + + public function testWebhookPushEvent(): void + { + $repositoryName = 'test-webhook-push-' . \uniqid(); + $secret = 'test-webhook-secret-' . \uniqid(); + + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; + $this->deleteLastWebhookRequest(); + $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); + + // Trigger a real push by creating a file + $this->vcsAdapter->createFile( + static::$owner, + $repositoryName, + 'README.md', + '# Webhook Test', + 'Initial commit' + ); + + // Wait for push webhook to arrive automatically + $webhookData = []; + $this->assertEventually(function () use (&$webhookData) { + $webhookData = $this->getLastWebhookRequest(); + $this->assertNotEmpty($webhookData, 'No webhook received'); + $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); + $this->assertSame('push', $webhookData['headers']['X-Forgejo-Event'] ?? '', 'Expected push event'); + }, 15000, 500); + + $payload = $webhookData['data']; + $headers = $webhookData['headers'] ?? []; + $signature = $headers['X-Forgejo-Signature'] ?? ''; + + $this->assertNotEmpty($signature, 'Missing X-Forgejo-Signature header'); + $this->assertTrue( + $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), + 'Webhook signature validation failed' + ); + + $event = $this->vcsAdapter->getEvent('push', $payload); + $this->assertIsArray($event); + $this->assertSame('main', $event['branch']); + $this->assertSame($repositoryName, $event['repositoryName']); + $this->assertSame(static::$owner, $event['owner']); + $this->assertNotEmpty($event['commitHash']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } + + public function testWebhookPullRequestEvent(): void + { + $repositoryName = 'test-webhook-pr-' . \uniqid(); + $secret = 'test-webhook-secret-' . \uniqid(); + + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + + try { + // Create all files BEFORE configuring webhook + // so those push events don't pollute the catcher + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'feature-branch'); + + $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; + $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); + + // Clear after setup so only PR event will arrive + $this->deleteLastWebhookRequest(); + + // Trigger real PR event + $this->vcsAdapter->createPullRequest( + static::$owner, + $repositoryName, + 'Test Webhook PR', + 'feature-branch', + 'main' + ); + + // Wait for pull_request webhook to arrive automatically + $webhookData = []; + $this->assertEventually(function () use (&$webhookData) { + $webhookData = $this->getLastWebhookRequest(); + $this->assertNotEmpty($webhookData, 'No webhook received'); + $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); + $this->assertSame('pull_request', $webhookData['headers']['X-Forgejo-Event'] ?? '', 'Expected pull_request event'); + }, 15000, 500); + + $payload = $webhookData['data']; + $headers = $webhookData['headers'] ?? []; + $signature = $headers['X-Forgejo-Signature'] ?? ''; + + $this->assertNotEmpty($signature, 'Missing X-Forgejo-Signature header'); + $this->assertTrue( + $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), + 'Webhook signature validation failed' + ); + + $event = $this->vcsAdapter->getEvent('pull_request', $payload); + $this->assertIsArray($event); + $this->assertSame('feature-branch', $event['branch']); + $this->assertSame($repositoryName, $event['repositoryName']); + $this->assertSame(static::$owner, $event['owner']); + $this->assertContains($event['action'], ['opened', 'synchronized']); + $this->assertGreaterThan(0, $event['pullRequestNumber']); + } finally { + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); + } + } +} diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index 4697de47..4b8431cf 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -11,8 +11,8 @@ class GiteaTest extends Base { - private static string $accessToken = ''; - private static string $owner = ''; + protected static string $accessToken = ''; + protected static string $owner = ''; protected function createVCSAdapter(): Git { @@ -21,7 +21,7 @@ protected function createVCSAdapter(): Git public function setUp(): void { - if (empty(self::$accessToken)) { + if (empty(static::$accessToken)) { $this->setupGitea(); } @@ -32,33 +32,33 @@ public function setUp(): void installationId: '', privateKey: '', appId: '', - accessToken: self::$accessToken, + accessToken: static::$accessToken, refreshToken: '' ); $adapter->setEndpoint($giteaUrl); - if (empty(self::$owner)) { + if (empty(static::$owner)) { $orgName = 'test-org-' . \uniqid(); - self::$owner = $adapter->createOrganization($orgName); + static::$owner = $adapter->createOrganization($orgName); } $this->vcsAdapter = $adapter; } - private function setupGitea(): void + protected function setupGitea(): void { $tokenFile = '/data/gitea/token.txt'; if (file_exists($tokenFile)) { $contents = file_get_contents($tokenFile); if ($contents !== false) { - self::$accessToken = trim($contents); + static::$accessToken = trim($contents); } } } public function testCreateRepository(): void { - $owner = self::$owner; + $owner = static::$owner; $repositoryName = 'test-create-repository-' . \uniqid(); $result = $this->vcsAdapter->createRepository($owner, $repositoryName, false); @@ -70,47 +70,47 @@ public function testCreateRepository(): void $this->assertSame($owner, $result['owner']['login']); $this->assertFalse($result['private']); - $this->assertTrue($this->vcsAdapter->deleteRepository(self::$owner, $repositoryName)); + $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); } public function testGetDeletedRepositoryFails(): void { $repositoryName = 'test-get-deleted-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); $this->expectException(\Exception::class); - $this->vcsAdapter->getRepository(self::$owner, $repositoryName); + $this->vcsAdapter->getRepository(static::$owner, $repositoryName); } public function testCreatePrivateRepository(): void { $repositoryName = 'test-create-private-repository-' . \uniqid(); - $result = $this->vcsAdapter->createRepository(self::$owner, $repositoryName, true); + $result = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, true); $this->assertIsArray($result); $this->assertTrue($result['private']); // Verify with getRepository - $fetched = $this->vcsAdapter->getRepository(self::$owner, $repositoryName); + $fetched = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); $this->assertTrue($fetched['private']); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testCommentWorkflow(): void { $repositoryName = 'test-comment-workflow-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'comment-test', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'test', 'Add test file', 'comment-test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'comment-test', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test file', 'comment-test'); $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Comment Test PR', 'comment-test', @@ -121,38 +121,38 @@ public function testCommentWorkflow(): void $this->assertGreaterThan(0, $prNumber); $originalComment = 'This is a test comment'; - $commentId = $this->vcsAdapter->createComment(self::$owner, $repositoryName, $prNumber, $originalComment); + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, $originalComment); $this->assertNotEmpty($commentId); $this->assertIsString($commentId); - $retrievedComment = $this->vcsAdapter->getComment(self::$owner, $repositoryName, $commentId); + $retrievedComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); $this->assertSame($originalComment, $retrievedComment); $updatedCommentText = 'This comment has been updated'; - $updatedCommentId = $this->vcsAdapter->updateComment(self::$owner, $repositoryName, (int)$commentId, $updatedCommentText); + $updatedCommentId = $this->vcsAdapter->updateComment(static::$owner, $repositoryName, (int)$commentId, $updatedCommentText); $this->assertSame($commentId, $updatedCommentId); - $finalComment = $this->vcsAdapter->getComment(self::$owner, $repositoryName, $commentId); + $finalComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); $this->assertSame($updatedCommentText, $finalComment); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testGetComment(): void { $repositoryName = 'test-get-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'test-branch', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); // Create PR $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Test PR', 'test-branch', @@ -162,43 +162,43 @@ public function testGetComment(): void $prNumber = $pr['number'] ?? 0; // Create a comment - $commentId = $this->vcsAdapter->createComment(self::$owner, $repositoryName, $prNumber, 'Test comment'); + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); // Test getComment - $result = $this->vcsAdapter->getComment(self::$owner, $repositoryName, $commentId); + $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); $this->assertIsString($result); $this->assertSame('Test comment', $result); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testCreateCommentInvalidPR(): void { $repositoryName = 'test-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); try { $this->expectException(\Exception::class); - $this->vcsAdapter->createComment(self::$owner, $repositoryName, 99999, 'Test comment'); + $this->vcsAdapter->createComment(static::$owner, $repositoryName, 99999, 'Test comment'); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testGetCommentInvalidId(): void { $repositoryName = 'test-get-comment-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $result = $this->vcsAdapter->getComment(self::$owner, $repositoryName, '99999999'); + $result = $this->vcsAdapter->getComment(static::$owner, $repositoryName, '99999999'); $this->assertIsString($result); $this->assertSame('', $result); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testHasAccessToAllRepositories(): void @@ -209,37 +209,37 @@ public function testHasAccessToAllRepositories(): void public function testGetRepositoryTreeWithSlashInBranchName(): void { $repositoryName = 'test-branch-with-slash-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature/test-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature/test-branch', 'main'); - $tree = $this->vcsAdapter->getRepositoryTree(self::$owner, $repositoryName, 'feature/test-branch'); + $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'feature/test-branch'); $this->assertIsArray($tree); $this->assertNotEmpty($tree); $this->assertContains('README.md', $tree); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetRepository(): void { $repositoryName = 'test-get-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $result = $this->vcsAdapter->getRepository(self::$owner, $repositoryName); + $result = $this->vcsAdapter->getRepository(static::$owner, $repositoryName); $this->assertIsArray($result); $this->assertSame($repositoryName, $result['name']); - $this->assertSame(self::$owner, $result['owner']['login']); - $this->assertTrue($this->vcsAdapter->deleteRepository(self::$owner, $repositoryName)); + $this->assertSame(static::$owner, $result['owner']['login']); + $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); } public function testGetRepositoryName(): void { $repositoryName = 'test-get-repository-name-' . \uniqid(); - $created = $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $created = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); $this->assertIsArray($created); $this->assertArrayHasKey('id', $created); @@ -248,7 +248,7 @@ public function testGetRepositoryName(): void $result = $this->vcsAdapter->getRepositoryName($repositoryId); $this->assertSame($repositoryName, $result); - $this->assertTrue($this->vcsAdapter->deleteRepository(self::$owner, $repositoryName)); + $this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName)); } public function testGetRepositoryNameWithInvalidId(): void @@ -266,7 +266,7 @@ public function testCreateRepositoryWithInvalidName(): void $repositoryName = 'invalid name with spaces'; try { - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); $this->fail('Expected exception for invalid repository name'); } catch (\Exception $e) { $this->assertTrue(true); @@ -288,15 +288,15 @@ public function testGetRepositoryWithNonExistingOwner(): void public function testGetRepositoryTree(): void { $repositoryName = 'test-get-repository-tree-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); // Create files in repo - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test Repo'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(self::$owner, $repositoryName, 'src/lib.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test Repo'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/lib.php', 'vcsAdapter->getRepositoryTree(self::$owner, $repositoryName, 'main', false); + $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'main', false); $this->assertIsArray($tree); $this->assertContains('README.md', $tree); @@ -304,7 +304,7 @@ public function testGetRepositoryTree(): void $this->assertCount(2, $tree); // Only README.md and src folder at root // Test recursive (should show all files including nested) - $treeRecursive = $this->vcsAdapter->getRepositoryTree(self::$owner, $repositoryName, 'main', true); + $treeRecursive = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'main', true); $this->assertIsArray($treeRecursive); $this->assertContains('README.md', $treeRecursive); @@ -313,32 +313,32 @@ public function testGetRepositoryTree(): void $this->assertContains('src/lib.php', $treeRecursive); $this->assertGreaterThanOrEqual(4, count($treeRecursive)); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetRepositoryTreeWithInvalidBranch(): void { $repositoryName = 'test-get-repository-tree-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $tree = $this->vcsAdapter->getRepositoryTree(self::$owner, $repositoryName, 'non-existing-branch', false); + $tree = $this->vcsAdapter->getRepositoryTree(static::$owner, $repositoryName, 'non-existing-branch', false); $this->assertIsArray($tree); $this->assertEmpty($tree); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetRepositoryContent(): void { $repositoryName = 'test-get-repository-content-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); $fileContent = '# Hello World'; - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', $fileContent); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', $fileContent); - $result = $this->vcsAdapter->getRepositoryContent(self::$owner, $repositoryName, 'README.md'); + $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'README.md'); $this->assertIsArray($result); $this->assertArrayHasKey('content', $result); @@ -348,46 +348,46 @@ public function testGetRepositoryContent(): void $this->assertIsString($result['sha']); $this->assertGreaterThan(0, $result['size']); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetRepositoryContentWithRef(): void { $repositoryName = 'test-get-repository-content-ref-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'main branch content'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'main branch content'); - $result = $this->vcsAdapter->getRepositoryContent(self::$owner, $repositoryName, 'test.txt', 'main'); + $result = $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'test.txt', 'main'); $this->assertIsArray($result); $this->assertSame('main branch content', $result['content']); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetRepositoryContentFileNotFound(): void { $repositoryName = 'test-get-repository-content-not-found-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); $this->expectException(\Utopia\VCS\Exception\FileNotFound::class); - $this->vcsAdapter->getRepositoryContent(self::$owner, $repositoryName, 'non-existing.txt'); + $this->vcsAdapter->getRepositoryContent(static::$owner, $repositoryName, 'non-existing.txt'); } public function testListRepositoryContents(): void { $repositoryName = 'test-list-repository-contents-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'file1.txt', 'content1'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'file1.txt', 'content1'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'src/main.php', 'vcsAdapter->listRepositoryContents(self::$owner, $repositoryName); + $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName); $this->assertIsArray($contents); $this->assertCount(3, $contents); // README.md, file1.txt, src folder @@ -404,18 +404,18 @@ public function testListRepositoryContents(): void $this->assertArrayHasKey('size', $item); } - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testListRepositoryContentsInSubdirectory(): void { $repositoryName = 'test-list-repository-contents-subdir-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'src/file1.php', 'vcsAdapter->createFile(self::$owner, $repositoryName, 'src/file2.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/file1.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'src/file2.php', 'vcsAdapter->listRepositoryContents(self::$owner, $repositoryName, 'src'); + $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName, 'src'); $this->assertIsArray($contents); $this->assertCount(2, $contents); @@ -424,34 +424,34 @@ public function testListRepositoryContentsInSubdirectory(): void $this->assertContains('file1.php', $names); $this->assertContains('file2.php', $names); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testListRepositoryContentsNonExistingPath(): void { $repositoryName = 'test-list-repository-contents-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $contents = $this->vcsAdapter->listRepositoryContents(self::$owner, $repositoryName, 'non-existing-path'); + $contents = $this->vcsAdapter->listRepositoryContents(static::$owner, $repositoryName, 'non-existing-path'); $this->assertIsArray($contents); $this->assertEmpty($contents); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetPullRequest(): void { $repositoryName = 'test-get-pull-request-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-branch', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'feature content', 'Add feature', 'feature-branch'); $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Test PR', 'feature-branch', @@ -463,7 +463,7 @@ public function testGetPullRequest(): void $this->assertGreaterThan(0, $prNumber); // Now test getPullRequest - $result = $this->vcsAdapter->getPullRequest(self::$owner, $repositoryName, $prNumber); + $result = $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, $prNumber); $this->assertIsArray($result); $this->assertArrayHasKey('number', $result); @@ -476,20 +476,20 @@ public function testGetPullRequest(): void $this->assertSame('Test PR', $result['title']); $this->assertSame('open', $result['state']); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetPullRequestWithInvalidNumber(): void { $repositoryName = 'test-get-pull-request-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); try { $this->expectException(\Exception::class); - $this->vcsAdapter->getPullRequest(self::$owner, $repositoryName, 99999); + $this->vcsAdapter->getPullRequest(static::$owner, $repositoryName, 99999); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -497,13 +497,13 @@ public function testGetPullRequestWithInvalidNumber(): void public function testGenerateCloneCommand(): void { $repositoryName = 'test-clone-command-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); $command = $this->vcsAdapter->generateCloneCommand( - self::$owner, + static::$owner, $repositoryName, 'main', \Utopia\VCS\Adapter\Git::CLONE_TYPE_BRANCH, @@ -517,23 +517,23 @@ public function testGenerateCloneCommand(): void $this->assertStringContainsString('git config core.sparseCheckout true', $command); $this->assertStringContainsString($repositoryName, $command); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testGenerateCloneCommandWithCommitHash(): void { $repositoryName = 'test-clone-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $commit = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $commitHash = $commit['commitHash']; $command = $this->vcsAdapter->generateCloneCommand( - self::$owner, + static::$owner, $repositoryName, $commitHash, \Utopia\VCS\Adapter\Git::CLONE_TYPE_COMMIT, @@ -544,27 +544,27 @@ public function testGenerateCloneCommandWithCommitHash(): void $this->assertStringContainsString('git fetch --depth=1', $command); $this->assertStringContainsString($commitHash, $command); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testGenerateCloneCommandWithTag(): void { $repositoryName = 'test-clone-tag-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { // Create initial file and get commit hash - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test Tag'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test Tag'); - $commit = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $commitHash = $commit['commitHash']; // Create a tag - $this->vcsAdapter->createTag(self::$owner, $repositoryName, 'v1.0.0', $commitHash, 'Release v1.0.0'); + $this->vcsAdapter->createTag(static::$owner, $repositoryName, 'v1.0.0', $commitHash, 'Release v1.0.0'); $command = $this->vcsAdapter->generateCloneCommand( - self::$owner, + static::$owner, $repositoryName, 'v1.0.0', \Utopia\VCS\Adapter\Git::CLONE_TYPE_TAG, @@ -581,7 +581,7 @@ public function testGenerateCloneCommandWithTag(): void $this->assertStringContainsString('v1.0.0', $command); $this->assertStringContainsString('git checkout FETCH_HEAD', $command); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -618,16 +618,16 @@ public function testGenerateCloneCommandWithInvalidRepository(): void public function testUpdateComment(): void { $repositoryName = 'test-update-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'test-branch', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); // Create PR $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Test PR', 'test-branch', @@ -638,43 +638,43 @@ public function testUpdateComment(): void $this->assertGreaterThan(0, $prNumber); // Create comment - $commentId = $this->vcsAdapter->createComment(self::$owner, $repositoryName, $prNumber, 'Original comment'); + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Original comment'); // Test updateComment - $updatedCommentId = $this->vcsAdapter->updateComment(self::$owner, $repositoryName, (int)$commentId, 'Updated comment'); + $updatedCommentId = $this->vcsAdapter->updateComment(static::$owner, $repositoryName, (int)$commentId, 'Updated comment'); $this->assertSame($commentId, $updatedCommentId); // Verify comment was updated - $finalComment = $this->vcsAdapter->getComment(self::$owner, $repositoryName, $commentId); + $finalComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); $this->assertSame('Updated comment', $finalComment); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testUpdateCommitStatus(): void { $repositoryName = 'test-update-commit-status-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $commit = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $commitHash = $commit['commitHash']; $this->vcsAdapter->updateCommitStatus( $repositoryName, $commitHash, - self::$owner, + static::$owner, 'success', 'Tests passed', 'https://example.com/build/123', 'ci/tests' ); - $statuses = $this->vcsAdapter->getCommitStatuses(self::$owner, $repositoryName, $commitHash); + $statuses = $this->vcsAdapter->getCommitStatuses(static::$owner, $repositoryName, $commitHash); $this->assertIsArray($statuses); $this->assertNotEmpty($statuses); @@ -689,25 +689,25 @@ public function testUpdateCommitStatus(): void } $this->assertTrue($found, 'Expected status with context ci/tests was not found'); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testUpdateCommitStatusWithInvalidCommit(): void { $repositoryName = 'test-update-status-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { $this->expectException(\Exception::class); $this->vcsAdapter->updateCommitStatus( $repositoryName, 'invalid-commit-hash', - self::$owner, + static::$owner, 'success' ); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -717,7 +717,7 @@ public function testUpdateCommitStatusWithNonExistingRepository(): void $this->vcsAdapter->updateCommitStatus( 'nonexistent-repo-' . \uniqid(), 'abc123def456abc123def456abc123def456abc123', - self::$owner, + static::$owner, 'success' ); } @@ -725,15 +725,15 @@ public function testUpdateCommitStatusWithNonExistingRepository(): void public function testGetCommit(): void { $repositoryName = 'test-get-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); $customMessage = 'Test commit message'; - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test Commit', $customMessage); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test Commit', $customMessage); - $latestCommit = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $latestCommit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $commitHash = $latestCommit['commitHash']; - $result = $this->vcsAdapter->getCommit(self::$owner, $repositoryName, $commitHash); + $result = $this->vcsAdapter->getCommit(static::$owner, $repositoryName, $commitHash); $this->assertIsArray($result); $this->assertArrayHasKey('commitHash', $result); @@ -749,19 +749,19 @@ public function testGetCommit(): void $this->assertStringContainsString('gravatar.com', $result['commitAuthorAvatar']); $this->assertNotEmpty($result['commitUrl']); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetLatestCommit(): void { $repositoryName = 'test-get-latest-commit-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); $firstMessage = 'First commit'; $secondMessage = 'Second commit'; - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test', $firstMessage); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test', $firstMessage); - $commit1 = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit1 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $this->assertIsArray($commit1); $this->assertArrayHasKey('commitHash', $commit1); @@ -779,9 +779,9 @@ public function testGetLatestCommit(): void $commit1Hash = $commit1['commitHash']; - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'test content', $secondMessage); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test content', $secondMessage); - $commit2 = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit2 = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $this->assertIsArray($commit2); $this->assertNotEmpty($commit2['commitHash']); @@ -791,34 +791,34 @@ public function testGetLatestCommit(): void $this->assertNotSame($commit1Hash, $commit2Hash); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetCommitWithInvalidSha(): void { $repositoryName = 'test-get-commit-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); try { $this->expectException(\Exception::class); - $this->vcsAdapter->getCommit(self::$owner, $repositoryName, 'invalid-sha-12345'); + $this->vcsAdapter->getCommit(static::$owner, $repositoryName, 'invalid-sha-12345'); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testGetLatestCommitWithInvalidBranch(): void { $repositoryName = 'test-get-latest-commit-invalid-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); try { $this->expectException(\Exception::class); - $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'non-existing-branch'); + $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'non-existing-branch'); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -1052,13 +1052,13 @@ public function testSearchRepositories(): void $repo2Name = 'test-search-repo2-' . \uniqid(); $repo3Name = 'other-repo-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repo1Name, false); - $this->vcsAdapter->createRepository(self::$owner, $repo2Name, false); - $this->vcsAdapter->createRepository(self::$owner, $repo3Name, false); + $this->vcsAdapter->createRepository(static::$owner, $repo1Name, false); + $this->vcsAdapter->createRepository(static::$owner, $repo2Name, false); + $this->vcsAdapter->createRepository(static::$owner, $repo3Name, false); try { // Search without filter - should return all - $result = $this->vcsAdapter->searchRepositories(self::$owner, 1, 10); + $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10); $this->assertIsArray($result); $this->assertArrayHasKey('items', $result); @@ -1066,7 +1066,7 @@ public function testSearchRepositories(): void $this->assertGreaterThanOrEqual(3, $result['total']); // Search with filter - $result = $this->vcsAdapter->searchRepositories(self::$owner, 1, 10, 'test-search'); + $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10, 'test-search'); $this->assertIsArray($result); $this->assertGreaterThanOrEqual(2, $result['total']); @@ -1076,9 +1076,9 @@ public function testSearchRepositories(): void $this->assertContains($repo1Name, $repoNames); $this->assertContains($repo2Name, $repoNames); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repo1Name); - $this->vcsAdapter->deleteRepository(self::$owner, $repo2Name); - $this->vcsAdapter->deleteRepository(self::$owner, $repo3Name); + $this->vcsAdapter->deleteRepository(static::$owner, $repo1Name); + $this->vcsAdapter->deleteRepository(static::$owner, $repo2Name); + $this->vcsAdapter->deleteRepository(static::$owner, $repo3Name); } } @@ -1087,31 +1087,31 @@ public function testSearchRepositoriesPagination(): void $repo1 = 'test-pagination-1-' . \uniqid(); $repo2 = 'test-pagination-2-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repo1, false); - $this->vcsAdapter->createRepository(self::$owner, $repo2, false); + $this->vcsAdapter->createRepository(static::$owner, $repo1, false); + $this->vcsAdapter->createRepository(static::$owner, $repo2, false); try { - $result = $this->vcsAdapter->searchRepositories(self::$owner, 1, 1, 'test-pagination'); + $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 1, 'test-pagination'); $this->assertSame(1, count($result['items'])); $this->assertGreaterThanOrEqual(2, $result['total']); - $result2 = $this->vcsAdapter->searchRepositories(self::$owner, 2, 1, 'test-pagination'); + $result2 = $this->vcsAdapter->searchRepositories(static::$owner, 2, 1, 'test-pagination'); $this->assertSame(1, count($result2['items'])); - $result20 = $this->vcsAdapter->searchRepositories(self::$owner, 20, 1, 'test-pagination'); + $result20 = $this->vcsAdapter->searchRepositories(static::$owner, 20, 1, 'test-pagination'); $this->assertIsArray($result20); $this->assertEmpty($result20['items']); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repo1); - $this->vcsAdapter->deleteRepository(self::$owner, $repo2); + $this->vcsAdapter->deleteRepository(static::$owner, $repo1); + $this->vcsAdapter->deleteRepository(static::$owner, $repo2); } } public function testSearchRepositoriesNoResults(): void { - $result = $this->vcsAdapter->searchRepositories(self::$owner, 1, 10, 'nonexistent-repo-xyz-' . \uniqid()); + $result = $this->vcsAdapter->searchRepositories(static::$owner, 1, 10, 'nonexistent-repo-xyz-' . \uniqid()); $this->assertIsArray($result); $this->assertEmpty($result['items']); @@ -1130,9 +1130,9 @@ public function testSearchRepositoriesInvalidOwner(): void public function testDeleteRepository(): void { $repositoryName = 'test-delete-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $result = $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $result = $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); $this->assertTrue($result); } @@ -1140,23 +1140,23 @@ public function testDeleteRepository(): void public function testDeleteRepositoryTwiceFails(): void { $repositoryName = 'test-delete-repository-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testDeleteNonExistingRepositoryFails(): void { $this->expectException(\Exception::class); - $this->vcsAdapter->deleteRepository(self::$owner, 'non-existing-repo-' . \uniqid()); + $this->vcsAdapter->deleteRepository(static::$owner, 'non-existing-repo-' . \uniqid()); } public function testGetOwnerName(): void { $repositoryName = 'test-get-owner-name-' . \uniqid(); - $created = $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $created = $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { $this->assertIsArray($created); @@ -1166,9 +1166,9 @@ public function testGetOwnerName(): void $ownerName = $this->vcsAdapter->getOwnerName('', $repositoryId); - $this->assertSame(self::$owner, $ownerName); + $this->assertSame(static::$owner, $ownerName); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -1206,12 +1206,12 @@ public function testGetOwnerNameWithNullRepositoryId(): void public function testGetUser(): void { // Get current authenticated user's info - $ownerInfo = $this->vcsAdapter->getUser(self::$owner); + $ownerInfo = $this->vcsAdapter->getUser(static::$owner); $this->assertIsArray($ownerInfo); $this->assertArrayHasKey('login', $ownerInfo); $this->assertArrayHasKey('id', $ownerInfo); - $this->assertSame(self::$owner, $ownerInfo['login']); + $this->assertSame(static::$owner, $ownerInfo['login']); } public function testGetUserWithInvalidUsername(): void @@ -1232,15 +1232,15 @@ public function testGetInstallationRepository(): void public function testGetPullRequestFromBranch(): void { $repositoryName = 'test-get-pr-from-branch-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'my-feature', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'my-feature'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'my-feature', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'my-feature'); // Create PR $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Feature PR', 'my-feature', @@ -1250,7 +1250,7 @@ public function testGetPullRequestFromBranch(): void $this->assertArrayHasKey('number', $pr); // Test getPullRequestFromBranch - $result = $this->vcsAdapter->getPullRequestFromBranch(self::$owner, $repositoryName, 'my-feature'); + $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'my-feature'); $this->assertIsArray($result); $this->assertNotEmpty($result); @@ -1259,39 +1259,39 @@ public function testGetPullRequestFromBranch(): void $resultHead = $result['head'] ?? []; $this->assertSame('my-feature', $resultHead['ref'] ?? ''); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testGetPullRequestFromBranchNoPR(): void { $repositoryName = 'test-get-pr-no-pr-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'lonely-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'lonely-branch', 'main'); // Don't create a PR - just test the method - $result = $this->vcsAdapter->getPullRequestFromBranch(self::$owner, $repositoryName, 'lonely-branch'); + $result = $this->vcsAdapter->getPullRequestFromBranch(static::$owner, $repositoryName, 'lonely-branch'); $this->assertIsArray($result); $this->assertEmpty($result); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testCreateComment(): void { $repositoryName = 'test-create-comment-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'test-branch', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'test-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'test.txt', 'test', 'Add test', 'test-branch'); // Create PR $pr = $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Test PR', 'test-branch', @@ -1302,28 +1302,28 @@ public function testCreateComment(): void $this->assertGreaterThan(0, $prNumber); // Test createComment - $commentId = $this->vcsAdapter->createComment(self::$owner, $repositoryName, $prNumber, 'Test comment'); + $commentId = $this->vcsAdapter->createComment(static::$owner, $repositoryName, $prNumber, 'Test comment'); $this->assertNotEquals('', $commentId); $this->assertIsString($commentId); $this->assertIsNumeric($commentId); // Verify comment was created - $retrievedComment = $this->vcsAdapter->getComment(self::$owner, $repositoryName, $commentId); + $retrievedComment = $this->vcsAdapter->getComment(static::$owner, $repositoryName, $commentId); $this->assertSame('Test comment', $retrievedComment); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testCreateFile(): void { $repositoryName = 'test-create-file-'.\uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { $result = $this->vcsAdapter->createFile( - self::$owner, + static::$owner, $repositoryName, 'test.md', '# Test', @@ -1333,22 +1333,22 @@ public function testCreateFile(): void $this->assertIsArray($result); $this->assertNotEmpty($result); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testCreateFileOnBranch(): void { $repositoryName = 'test-create-file-branch-'.\uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Main'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Main'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature', 'main'); // Create file on specific branch $result = $this->vcsAdapter->createFile( - self::$owner, + static::$owner, $repositoryName, 'feature.md', '# Feature', @@ -1360,34 +1360,34 @@ public function testCreateFileOnBranch(): void // Verify it's on the right branch $content = $this->vcsAdapter->getRepositoryContent( - self::$owner, + static::$owner, $repositoryName, 'feature.md', 'feature' ); $this->assertSame('# Feature', $content['content']); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testListBranches(): void { $repositoryName = 'test-list-branches-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { // Create initial file on main branch - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); // Create additional branches - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-1', 'main'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-2', 'main'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-1', 'main'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-2', 'main'); $branches = []; $maxAttempts = 10; for ($attempt = 0; $attempt < $maxAttempts; $attempt++) { - $branches = $this->vcsAdapter->listBranches(self::$owner, $repositoryName); + $branches = $this->vcsAdapter->listBranches(static::$owner, $repositoryName); if (in_array('feature-1', $branches, true) && in_array('feature-2', $branches, true)) { break; @@ -1403,23 +1403,23 @@ public function testListBranches(): void $this->assertContains('feature-2', $branches); $this->assertGreaterThanOrEqual(3, count($branches)); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testCreateTag(): void { $repositoryName = 'test-create-tag-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $commit = $this->vcsAdapter->getLatestCommit(self::$owner, $repositoryName, 'main'); + $commit = $this->vcsAdapter->getLatestCommit(static::$owner, $repositoryName, 'main'); $commitHash = $commit['commitHash']; $result = $this->vcsAdapter->createTag( - self::$owner, + static::$owner, $repositoryName, 'v1.0.0', $commitHash, @@ -1434,41 +1434,41 @@ public function testCreateTag(): void $this->assertArrayHasKey('sha', $result['commit']); $this->assertSame($commitHash, $result['commit']['sha']); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } public function testListRepositoryLanguages(): void { $repositoryName = 'test-list-repository-languages-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'main.php', 'vcsAdapter->createFile(self::$owner, $repositoryName, 'script.js', 'console.log("test");'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'style.css', 'body { margin: 0; }'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'main.php', 'vcsAdapter->createFile(static::$owner, $repositoryName, 'script.js', 'console.log("test");'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'style.css', 'body { margin: 0; }'); sleep(2); - $languages = $this->vcsAdapter->listRepositoryLanguages(self::$owner, $repositoryName); + $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); $this->assertIsArray($languages); $this->assertNotEmpty($languages); $this->assertContains('PHP', $languages); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testListRepositoryLanguagesEmptyRepo(): void { $repositoryName = 'test-list-repository-languages-empty-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - $languages = $this->vcsAdapter->listRepositoryLanguages(self::$owner, $repositoryName); + $languages = $this->vcsAdapter->listRepositoryLanguages(static::$owner, $repositoryName); $this->assertIsArray($languages); $this->assertEmpty($languages); - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } public function testWebhookPushEvent(): void @@ -1476,16 +1476,16 @@ public function testWebhookPushEvent(): void $repositoryName = 'test-webhook-push-' . \uniqid(); $secret = 'test-webhook-secret-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; $this->deleteLastWebhookRequest(); - $this->vcsAdapter->createWebhook(self::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); + $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); // Trigger a real push by creating a file $this->vcsAdapter->createFile( - self::$owner, + static::$owner, $repositoryName, 'README.md', '# Webhook Test', @@ -1515,10 +1515,10 @@ public function testWebhookPushEvent(): void $this->assertIsArray($event); $this->assertSame('main', $event['branch']); $this->assertSame($repositoryName, $event['repositoryName']); - $this->assertSame(self::$owner, $event['owner']); + $this->assertSame(static::$owner, $event['owner']); $this->assertNotEmpty($event['commitHash']); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } @@ -1527,24 +1527,24 @@ public function testWebhookPullRequestEvent(): void $repositoryName = 'test-webhook-pr-' . \uniqid(); $secret = 'test-webhook-secret-' . \uniqid(); - $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false); + $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); try { // Create all files BEFORE configuring webhook // so those push events don't pollute the catcher - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-branch', 'main'); - $this->vcsAdapter->createFile(self::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'feature-branch'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); + $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', 'main'); + $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'feature-branch'); $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; - $this->vcsAdapter->createWebhook(self::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); + $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); // Clear after setup so only PR event will arrive $this->deleteLastWebhookRequest(); // Trigger real PR event $this->vcsAdapter->createPullRequest( - self::$owner, + static::$owner, $repositoryName, 'Test Webhook PR', 'feature-branch', @@ -1574,11 +1574,11 @@ public function testWebhookPullRequestEvent(): void $this->assertIsArray($event); $this->assertSame('feature-branch', $event['branch']); $this->assertSame($repositoryName, $event['repositoryName']); - $this->assertSame(self::$owner, $event['owner']); + $this->assertSame(static::$owner, $event['owner']); $this->assertContains($event['action'], ['opened', 'synchronized']); $this->assertGreaterThan(0, $event['pullRequestNumber']); } finally { - $this->vcsAdapter->deleteRepository(self::$owner, $repositoryName); + $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); } } From d96a96a15ab8d7c94f6378292ec2be272b7dcca5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:57:02 +0000 Subject: [PATCH 02/10] Fix Forgejo token path to use /data/gitea/ directory (Forgejo 9 uses same dir structure as Gitea) Co-authored-by: Meldiron <19310830+Meldiron@users.noreply.github.com> Agent-Logs-Url: https://github.com/utopia-php/vcs/sessions/b7718762-2b6f-4dc1-8f0d-3561ae2b01e4 --- docker-compose.yml | 2 +- tests/VCS/Adapter/ForgejoTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f70ad2f5..af236d20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -108,7 +108,7 @@ services: -c " su git -c \"forgejo admin user create --username $$FORGEJO_ADMIN_USERNAME --password $$FORGEJO_ADMIN_PASSWORD --email $$FORGEJO_ADMIN_EMAIL --admin --must-change-password=false\" || true && TOKEN=$$(su git -c \"forgejo admin user generate-access-token --username $$FORGEJO_ADMIN_USERNAME --token-name $$FORGEJO_ADMIN_USERNAME-token --scopes all --raw\") && - echo $$TOKEN > /data/forgejo/token.txt + echo $$TOKEN > /data/gitea/token.txt " volumes: diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index 833a6093..f62167f5 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -46,7 +46,7 @@ public function setUp(): void protected function setupForgejo(): void { - $tokenFile = '/forgejo-data/forgejo/token.txt'; + $tokenFile = '/forgejo-data/gitea/token.txt'; if (file_exists($tokenFile)) { $contents = file_get_contents($tokenFile); From 279ffa355eb0970750a6f3d21b5e45d3e8119d70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:19:57 +0000 Subject: [PATCH 03/10] Plan: extract getHookType() + fix PSR-4 + refactor webhook header properties Co-authored-by: Meldiron <19310830+Meldiron@users.noreply.github.com> Agent-Logs-Url: https://github.com/utopia-php/vcs/sessions/9018a712-0c46-43ff-9933-d768660aaebe --- composer.json | 3 +- tests/VCS/Adapter/ForgejoTest.php | 114 +----------------------------- tests/VCS/Adapter/GiteaTest.php | 15 ++-- 3 files changed, 14 insertions(+), 118 deletions(-) diff --git a/composer.json b/composer.json index 12a47c75..e8c8de79 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ }, "autoload-dev": { "psr-4": { - "Utopia\\Tests\\": "tests/VCS" + "Utopia\\Tests\\": "tests/VCS", + "Utopia\\Tests\\VCS\\": "tests/VCS" } }, "require": { diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index f62167f5..4331917a 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -14,6 +14,9 @@ class ForgejoTest extends GiteaTest protected static string $owner = ''; + protected string $webhookEventHeader = 'X-Forgejo-Event'; + protected string $webhookSignatureHeader = 'X-Forgejo-Signature'; + protected function createVCSAdapter(): Git { return new Forgejo(new Cache(new None())); @@ -55,115 +58,4 @@ protected function setupForgejo(): void } } } - - public function testWebhookPushEvent(): void - { - $repositoryName = 'test-webhook-push-' . \uniqid(); - $secret = 'test-webhook-secret-' . \uniqid(); - - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; - $this->deleteLastWebhookRequest(); - $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); - - // Trigger a real push by creating a file - $this->vcsAdapter->createFile( - static::$owner, - $repositoryName, - 'README.md', - '# Webhook Test', - 'Initial commit' - ); - - // Wait for push webhook to arrive automatically - $webhookData = []; - $this->assertEventually(function () use (&$webhookData) { - $webhookData = $this->getLastWebhookRequest(); - $this->assertNotEmpty($webhookData, 'No webhook received'); - $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); - $this->assertSame('push', $webhookData['headers']['X-Forgejo-Event'] ?? '', 'Expected push event'); - }, 15000, 500); - - $payload = $webhookData['data']; - $headers = $webhookData['headers'] ?? []; - $signature = $headers['X-Forgejo-Signature'] ?? ''; - - $this->assertNotEmpty($signature, 'Missing X-Forgejo-Signature header'); - $this->assertTrue( - $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), - 'Webhook signature validation failed' - ); - - $event = $this->vcsAdapter->getEvent('push', $payload); - $this->assertIsArray($event); - $this->assertSame('main', $event['branch']); - $this->assertSame($repositoryName, $event['repositoryName']); - $this->assertSame(static::$owner, $event['owner']); - $this->assertNotEmpty($event['commitHash']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } - - public function testWebhookPullRequestEvent(): void - { - $repositoryName = 'test-webhook-pr-' . \uniqid(); - $secret = 'test-webhook-secret-' . \uniqid(); - - $this->vcsAdapter->createRepository(static::$owner, $repositoryName, false); - - try { - // Create all files BEFORE configuring webhook - // so those push events don't pollute the catcher - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'README.md', '# Test'); - $this->vcsAdapter->createBranch(static::$owner, $repositoryName, 'feature-branch', 'main'); - $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'feature-branch'); - - $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000') ?? ''; - $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); - - // Clear after setup so only PR event will arrive - $this->deleteLastWebhookRequest(); - - // Trigger real PR event - $this->vcsAdapter->createPullRequest( - static::$owner, - $repositoryName, - 'Test Webhook PR', - 'feature-branch', - 'main' - ); - - // Wait for pull_request webhook to arrive automatically - $webhookData = []; - $this->assertEventually(function () use (&$webhookData) { - $webhookData = $this->getLastWebhookRequest(); - $this->assertNotEmpty($webhookData, 'No webhook received'); - $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); - $this->assertSame('pull_request', $webhookData['headers']['X-Forgejo-Event'] ?? '', 'Expected pull_request event'); - }, 15000, 500); - - $payload = $webhookData['data']; - $headers = $webhookData['headers'] ?? []; - $signature = $headers['X-Forgejo-Signature'] ?? ''; - - $this->assertNotEmpty($signature, 'Missing X-Forgejo-Signature header'); - $this->assertTrue( - $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), - 'Webhook signature validation failed' - ); - - $event = $this->vcsAdapter->getEvent('pull_request', $payload); - $this->assertIsArray($event); - $this->assertSame('feature-branch', $event['branch']); - $this->assertSame($repositoryName, $event['repositoryName']); - $this->assertSame(static::$owner, $event['owner']); - $this->assertContains($event['action'], ['opened', 'synchronized']); - $this->assertGreaterThan(0, $event['pullRequestNumber']); - } finally { - $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); - } - } } diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index 4b8431cf..117ebdd4 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -14,6 +14,9 @@ class GiteaTest extends Base protected static string $accessToken = ''; protected static string $owner = ''; + protected string $webhookEventHeader = 'X-Gitea-Event'; + protected string $webhookSignatureHeader = 'X-Gitea-Signature'; + protected function createVCSAdapter(): Git { return new Gitea(new Cache(new None())); @@ -1498,14 +1501,14 @@ public function testWebhookPushEvent(): void $webhookData = $this->getLastWebhookRequest(); $this->assertNotEmpty($webhookData, 'No webhook received'); $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); - $this->assertSame('push', $webhookData['headers']['X-Gitea-Event'] ?? '', 'Expected push event'); + $this->assertSame('push', $webhookData['headers'][$this->webhookEventHeader] ?? '', 'Expected push event'); }, 15000, 500); $payload = $webhookData['data']; $headers = $webhookData['headers'] ?? []; - $signature = $headers['X-Gitea-Signature'] ?? ''; + $signature = $headers[$this->webhookSignatureHeader] ?? ''; - $this->assertNotEmpty($signature, 'Missing X-Gitea-Signature header'); + $this->assertNotEmpty($signature, 'Missing ' . $this->webhookSignatureHeader . ' header'); $this->assertTrue( $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), 'Webhook signature validation failed' @@ -1557,14 +1560,14 @@ public function testWebhookPullRequestEvent(): void $webhookData = $this->getLastWebhookRequest(); $this->assertNotEmpty($webhookData, 'No webhook received'); $this->assertNotEmpty($webhookData['data'] ?? '', 'Webhook payload is empty'); - $this->assertSame('pull_request', $webhookData['headers']['X-Gitea-Event'] ?? '', 'Expected pull_request event'); + $this->assertSame('pull_request', $webhookData['headers'][$this->webhookEventHeader] ?? '', 'Expected pull_request event'); }, 15000, 500); $payload = $webhookData['data']; $headers = $webhookData['headers'] ?? []; - $signature = $headers['X-Gitea-Signature'] ?? ''; + $signature = $headers[$this->webhookSignatureHeader] ?? ''; - $this->assertNotEmpty($signature, 'Missing X-Gitea-Signature header'); + $this->assertNotEmpty($signature, 'Missing ' . $this->webhookSignatureHeader . ' header'); $this->assertTrue( $this->vcsAdapter->validateWebhookEvent($payload, $signature, $secret), 'Webhook signature validation failed' From e854b0349163846f28f6a9853c2a74bbd6f7f721 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:24:01 +0000 Subject: [PATCH 04/10] Extract getHookType() in Gitea; override in Forgejo; remove duplicated createWebhook() Co-authored-by: Meldiron <19310830+Meldiron@users.noreply.github.com> Agent-Logs-Url: https://github.com/utopia-php/vcs/sessions/9018a712-0c46-43ff-9933-d768660aaebe --- src/VCS/Adapter/Git/Forgejo.php | 38 ++------------------------------- src/VCS/Adapter/Git/Gitea.php | 7 +++++- 2 files changed, 8 insertions(+), 37 deletions(-) diff --git a/src/VCS/Adapter/Git/Forgejo.php b/src/VCS/Adapter/Git/Forgejo.php index 1be90351..c7f09fee 100644 --- a/src/VCS/Adapter/Git/Forgejo.php +++ b/src/VCS/Adapter/Git/Forgejo.php @@ -2,8 +2,6 @@ namespace Utopia\VCS\Adapter\Git; -use Exception; - class Forgejo extends Gitea { protected string $endpoint = 'http://forgejo:3000/api/v1'; @@ -18,40 +16,8 @@ public function getName(): string return 'forgejo'; } - /** - * Create a webhook on a repository - * - * @param string $owner Owner of the repository - * @param string $repositoryName Name of the repository - * @param string $url Webhook URL to send events to - * @param string $secret Webhook secret for signature validation - * @param array $events Events to trigger the webhook - * @return int Webhook ID - */ - public function createWebhook(string $owner, string $repositoryName, string $url, string $secret, array $events = ['push', 'pull_request']): int + protected function getHookType(): string { - $response = $this->call( - self::METHOD_POST, - "/repos/{$owner}/{$repositoryName}/hooks", - ['Authorization' => "token $this->accessToken"], - [ - 'type' => 'forgejo', - 'active' => true, - 'events' => $events, - 'config' => [ - 'url' => $url, - 'content_type' => 'json', - 'secret' => $secret, - ], - ] - ); - - $responseHeaders = $response['headers'] ?? []; - $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; - if ($responseHeadersStatusCode >= 400) { - throw new Exception("Failed to create webhook: HTTP {$responseHeadersStatusCode}"); - } - - return (int) ($response['body']['id'] ?? 0); + return 'forgejo'; } } diff --git a/src/VCS/Adapter/Git/Gitea.php b/src/VCS/Adapter/Git/Gitea.php index d6ed8e13..33d5e495 100644 --- a/src/VCS/Adapter/Git/Gitea.php +++ b/src/VCS/Adapter/Git/Gitea.php @@ -494,6 +494,11 @@ public function createPullRequest(string $owner, string $repositoryName, string return $responseBody; } + protected function getHookType(): string + { + return 'gitea'; + } + /** * Create a webhook on a repository * @@ -511,7 +516,7 @@ public function createWebhook(string $owner, string $repositoryName, string $url "/repos/{$owner}/{$repositoryName}/hooks", ['Authorization' => "token $this->accessToken"], [ - 'type' => 'gitea', + 'type' => $this->getHookType(), 'active' => true, 'events' => $events, 'config' => [ From 3d133ccc9fd35c351be86db32527c2c38cc63a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 23 Mar 2026 17:27:48 +0100 Subject: [PATCH 05/10] Revert unwatned changes --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e8c8de79..12a47c75 100644 --- a/composer.json +++ b/composer.json @@ -23,8 +23,7 @@ }, "autoload-dev": { "psr-4": { - "Utopia\\Tests\\": "tests/VCS", - "Utopia\\Tests\\VCS\\": "tests/VCS" + "Utopia\\Tests\\": "tests/VCS" } }, "require": { From ca20dfae7d8321cade3d26a6e4863f5933962923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 23 Mar 2026 17:30:22 +0100 Subject: [PATCH 06/10] Fix test namespaces --- tests/VCS/Adapter/ForgejoTest.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 2 +- tests/VCS/Adapter/GiteaTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index 4331917a..e868bb1a 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -1,6 +1,6 @@ Date: Mon, 23 Mar 2026 17:44:25 +0100 Subject: [PATCH 07/10] Fix avatar tests --- docker-compose.yml | 12 ++++++++---- tests/VCS/Adapter/ForgejoTest.php | 1 + tests/VCS/Adapter/GiteaTest.php | 5 +++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index af236d20..b7bc513f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -64,8 +64,10 @@ services: command: > -c " su git -c \"gitea admin user create --username $$GITEA_ADMIN_USERNAME --password $$GITEA_ADMIN_PASSWORD --email $$GITEA_ADMIN_EMAIL --admin --must-change-password=false\" || true && - TOKEN=$$(su git -c \"gitea admin user generate-access-token --username $$GITEA_ADMIN_USERNAME --token-name $$GITEA_ADMIN_USERNAME-token --scopes all --raw\") && - echo $$TOKEN > /data/gitea/token.txt + if [ ! -f /data/gitea/token.txt ]; then + TOKEN=$$(su git -c \"gitea admin user generate-access-token --username $$GITEA_ADMIN_USERNAME --token-name $$GITEA_ADMIN_USERNAME-token --scopes all --raw\") && + echo $$TOKEN > /data/gitea/token.txt; + fi " request-catcher: image: appwrite/requestcatcher:1.1.0 @@ -107,8 +109,10 @@ services: command: > -c " su git -c \"forgejo admin user create --username $$FORGEJO_ADMIN_USERNAME --password $$FORGEJO_ADMIN_PASSWORD --email $$FORGEJO_ADMIN_EMAIL --admin --must-change-password=false\" || true && - TOKEN=$$(su git -c \"forgejo admin user generate-access-token --username $$FORGEJO_ADMIN_USERNAME --token-name $$FORGEJO_ADMIN_USERNAME-token --scopes all --raw\") && - echo $$TOKEN > /data/gitea/token.txt + if [ ! -f /data/gitea/token.txt ]; then + TOKEN=$$(su git -c \"forgejo admin user generate-access-token --username $$FORGEJO_ADMIN_USERNAME --token-name $$FORGEJO_ADMIN_USERNAME-token --scopes all --raw\") && + echo $$TOKEN > /data/gitea/token.txt; + fi " volumes: diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index e868bb1a..4917a849 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -16,6 +16,7 @@ class ForgejoTest extends GiteaTest protected string $webhookEventHeader = 'X-Forgejo-Event'; protected string $webhookSignatureHeader = 'X-Forgejo-Signature'; + protected string $avatarDomain = 'http://localhost:3000/avatars/'; protected function createVCSAdapter(): Git { diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index 57a29cdd..fabc431b 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -16,6 +16,7 @@ class GiteaTest extends Base protected string $webhookEventHeader = 'X-Gitea-Event'; protected string $webhookSignatureHeader = 'X-Gitea-Signature'; + protected string $avatarDomain = 'gravatar.com'; protected function createVCSAdapter(): Git { @@ -749,7 +750,7 @@ public function testGetCommit(): void $this->assertSame($commitHash, $result['commitHash']); $this->assertSame('utopia', $result['commitAuthor']); $this->assertStringStartsWith($customMessage, $result['commitMessage']); - $this->assertStringContainsString('gravatar.com', $result['commitAuthorAvatar']); + $this->assertStringContainsString($this->avatarDomain, $result['commitAuthorAvatar']); $this->assertNotEmpty($result['commitUrl']); $this->vcsAdapter->deleteRepository(static::$owner, $repositoryName); @@ -777,7 +778,7 @@ public function testGetLatestCommit(): void $this->assertNotEmpty($commit1['commitHash']); $this->assertSame('utopia', $commit1['commitAuthor']); $this->assertStringStartsWith($firstMessage, $commit1['commitMessage']); - $this->assertStringContainsString('gravatar.com', $commit1['commitAuthorAvatar']); + $this->assertStringContainsString($this->avatarDomain, $commit1['commitAuthorAvatar']); $this->assertNotEmpty($commit1['commitUrl']); $commit1Hash = $commit1['commitHash']; From a282d25f58ef656fc80171d74d01de9ba5eaa317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 23 Mar 2026 21:42:03 +0100 Subject: [PATCH 08/10] Fix tests --- src/VCS/Adapter/Git/Gitea.php | 8 ++++---- tests/VCS/Adapter/GiteaTest.php | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/VCS/Adapter/Git/Gitea.php b/src/VCS/Adapter/Git/Gitea.php index 33d5e495..5edfb6b8 100644 --- a/src/VCS/Adapter/Git/Gitea.php +++ b/src/VCS/Adapter/Git/Gitea.php @@ -71,7 +71,7 @@ public function initializeVariables(string $installationId, string $privateKey, return; } - throw new Exception("accessToken is required for Gitea adapter."); + throw new Exception("accessToken is required for this adapter."); } /** @@ -82,7 +82,7 @@ public function initializeVariables(string $installationId, string $privateKey, */ protected function generateAccessToken(string $privateKey, string $appId): void { - // Not applicable for Gitea - OAuth2 tokens are passed directly + // Not applicable for this adapter - OAuth2 tokens are passed directly return; } @@ -224,7 +224,7 @@ public function searchRepositories(string $owner, int $page, int $per_page, stri */ public function getInstallationRepository(string $repositoryName): array { - throw new Exception("getInstallationRepository is not applicable for Gitea - use getRepository() with owner and repo name instead"); + throw new Exception("getInstallationRepository is not applicable for this adapter - use getRepository() with owner and repo name instead"); } public function getRepository(string $owner, string $repositoryName): array @@ -613,7 +613,7 @@ public function getUser(string $username): array public function getOwnerName(string $installationId, ?int $repositoryId = null): string { if ($repositoryId === null || $repositoryId <= 0) { - throw new Exception("repositoryId is required for Gitea"); + throw new Exception("repositoryId is required for this adapter"); } $url = "/repositories/{$repositoryId}"; diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index fabc431b..c362df0a 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -1179,7 +1179,7 @@ public function testGetOwnerName(): void public function testGetOwnerNameWithZeroRepositoryId(): void { $this->expectException(\Exception::class); - $this->expectExceptionMessage('repositoryId is required for Gitea'); + $this->expectExceptionMessage('repositoryId is required for this adapter'); $this->vcsAdapter->getOwnerName('', 0); } @@ -1187,7 +1187,7 @@ public function testGetOwnerNameWithZeroRepositoryId(): void public function testGetOwnerNameWithoutRepositoryId(): void { $this->expectException(\Exception::class); - $this->expectExceptionMessage('repositoryId is required for Gitea'); + $this->expectExceptionMessage('repositoryId is required for this adapter'); $this->vcsAdapter->getOwnerName(''); } @@ -1202,7 +1202,7 @@ public function testGetOwnerNameWithInvalidRepositoryId(): void public function testGetOwnerNameWithNullRepositoryId(): void { $this->expectException(\Exception::class); - $this->expectExceptionMessage('repositoryId is required for Gitea'); + $this->expectExceptionMessage('repositoryId is required for this adapter'); $this->vcsAdapter->getOwnerName('', null); } @@ -1226,9 +1226,9 @@ public function testGetUserWithInvalidUsername(): void public function testGetInstallationRepository(): void { - // This method is not applicable for Gitea + // This method is not applicable for this adapter $this->expectException(\Exception::class); - $this->expectExceptionMessage('not applicable for Gitea'); + $this->expectExceptionMessage('not applicable for this adapter'); $this->vcsAdapter->getInstallationRepository('any-repo-name'); } From 5dc55f3b6cc09e5c26844902f1ba7dc38640a481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 23 Mar 2026 21:46:06 +0100 Subject: [PATCH 09/10] Fix linter --- tests/VCS/Adapter/ForgejoTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/VCS/Adapter/ForgejoTest.php b/tests/VCS/Adapter/ForgejoTest.php index 4917a849..ad1ec502 100644 --- a/tests/VCS/Adapter/ForgejoTest.php +++ b/tests/VCS/Adapter/ForgejoTest.php @@ -30,7 +30,7 @@ public function setUp(): void } $adapter = new Forgejo(new Cache(new None())); - $forgejoUrl = System::getEnv('TESTS_FORGEJO_URL', 'http://forgejo:3000') ?? ''; + $forgejoUrl = System::getEnv('TESTS_FORGEJO_URL', 'http://forgejo:3000'); $adapter->initializeVariables( installationId: '', From 89ede13790ebccaf3b4e0e045c1554152fd94e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 23 Mar 2026 21:55:04 +0100 Subject: [PATCH 10/10] fix tests --- tests/VCS/Adapter/GiteaTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/VCS/Adapter/GiteaTest.php b/tests/VCS/Adapter/GiteaTest.php index 4354e6d7..c0ae2d21 100644 --- a/tests/VCS/Adapter/GiteaTest.php +++ b/tests/VCS/Adapter/GiteaTest.php @@ -1542,7 +1542,7 @@ public function testWebhookPullRequestEvent(): void $this->vcsAdapter->createFile(static::$owner, $repositoryName, 'feature.txt', 'content', 'Add feature', 'feature-branch'); $catcherUrl = System::getEnv('TESTS_GITEA_REQUEST_CATCHER_URL', 'http://request-catcher:5000'); - $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret); + $this->vcsAdapter->createWebhook(static::$owner, $repositoryName, $catcherUrl . '/webhook', $secret, ['pull_request']); // Clear after setup so only PR event will arrive $this->deleteLastWebhookRequest();