Skip to content
105 changes: 98 additions & 7 deletions src/VCS/Adapter/Git/Gitea.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,68 @@ public function createOrganization(string $orgName): string
return $responseBody['name'] ?? '';
}

// Stub methods to satisfy abstract class requirements
// These will be implemented in follow-up PRs

/**
* Search repositories in organization
*
* @param string $installationId Not used in Gitea (kept for interface compatibility)
* @param string $owner Organization or user name
* @param int $page Page number for pagination
* @param int $per_page Number of results per page
* @param string $search Search query to filter repository names
* @return array<mixed> Array with 'items' (repositories) and 'total' count
*/
public function searchRepositories(string $installationId, string $owner, int $page, int $per_page, string $search = ''): array
{
throw new Exception("Not implemented yet");
}
$allRepos = [];
$currentPage = 1;

while (true) {
$queryParams = [
'page' => $currentPage,
'limit' => 100,
];

if (!empty($search)) {
$queryParams['q'] = $search;
}

$query = http_build_query($queryParams);
$url = "/repos/search?{$query}";

$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);

$responseBody = $response['body'] ?? [];
$repos = $responseBody['data'] ?? [];

Comment thread
jaysomani marked this conversation as resolved.
if (empty($repos)) {
break;
}
Comment thread
jaysomani marked this conversation as resolved.

$allRepos = array_merge($allRepos, $repos);

if (count($repos) < 100) {
break;
}

$currentPage++;
}

$filteredRepos = array_filter($allRepos, function ($repo) use ($owner) {
$repoOwner = $repo['owner']['login'] ?? '';
return $repoOwner === $owner;
});

$filteredRepos = array_values($filteredRepos);

$total = count($filteredRepos);
$offset = ($page - 1) * $per_page;
$pagedRepos = array_slice($filteredRepos, $offset, $per_page);

return [
'items' => $pagedRepos,
'total' => $total,
];
}
public function getInstallationRepository(string $repositoryName): array
{
throw new Exception("Not implemented yet");
Expand Down Expand Up @@ -367,9 +421,16 @@ public function getUser(string $username): array
throw new Exception("Not implemented yet");
}

/**
* Get owner name
* @param string $installationId In Gitea context, this is the owner name itself
* @return string Owner name
*/
public function getOwnerName(string $installationId): string
{
throw new Exception("Not implemented yet");
// Gitea doesn't have GitHub App installation concept
// Return the installationId as-is since it represents the owner
return $installationId;
Comment thread
jaysomani marked this conversation as resolved.
Outdated
Comment thread
jaysomani marked this conversation as resolved.
Outdated
}

public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array
Expand All @@ -382,9 +443,39 @@ public function getPullRequestFromBranch(string $owner, string $repositoryName,
throw new Exception("Not implemented yet");
}

/**
* List all branches in a repository
*
* @param string $owner Owner of the repository
* @param string $repositoryName Name of the repository
* @return array<string> Array of branch names
*/
public function listBranches(string $owner, string $repositoryName): array
{
throw new Exception("Not implemented yet");
$url = "/repos/{$owner}/{$repositoryName}/branches";

$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);

$responseHeaders = $response['headers'] ?? [];
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
if ($responseHeadersStatusCode >= 400) {
return [];
Comment thread
jaysomani marked this conversation as resolved.
Outdated
}

$responseBody = $response['body'] ?? [];

if (!is_array($responseBody)) {
return [];
}

$names = [];
foreach ($responseBody as $branch) {
if (is_array($branch) && array_key_exists('name', $branch)) {
$names[] = $branch['name'] ?? '';
}
}

Comment thread
jaysomani marked this conversation as resolved.
Outdated
return $names;
}

/**
Expand Down
67 changes: 64 additions & 3 deletions tests/VCS/Adapter/GiteaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,39 @@ public function testGetEvent(): void
}
public function testSearchRepositories(): void
{
$this->markTestSkipped('Will be implemented in follow-up PR');
// Create multiple repositories
$repo1Name = 'test-search-repo1-' . \uniqid();
$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);

try {
// Search without filter - should return all
$result = $this->vcsAdapter->searchRepositories('', self::$owner, 1, 10);

$this->assertIsArray($result);
$this->assertArrayHasKey('items', $result);
$this->assertArrayHasKey('total', $result);
$this->assertGreaterThanOrEqual(3, $result['total']);

// Search with filter
$result = $this->vcsAdapter->searchRepositories('', self::$owner, 1, 10, 'test-search');
Comment thread
jaysomani marked this conversation as resolved.

$this->assertIsArray($result);
$this->assertGreaterThanOrEqual(2, $result['total']);

// Verify the filtered repos are in results
$repoNames = array_column($result['items'], 'name');
$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);
}
}

public function testDeleteRepository(): void
Expand Down Expand Up @@ -500,7 +532,12 @@ public function testDeleteNonExistingRepositoryFails(): void

public function testGetOwnerName(): void
{
$this->markTestSkipped('Will be implemented in follow-up PR');
// For Gitea, getOwnerName simply returns the installationId parameter
// since Gitea doesn't have GitHub App installation concept
$result = $this->vcsAdapter->getOwnerName(self::$owner);
Comment thread
jaysomani marked this conversation as resolved.
Outdated

$this->assertIsString($result);
$this->assertSame(self::$owner, $result);
}

public function testGetPullRequestFromBranch(): void
Expand All @@ -515,7 +552,31 @@ public function testCreateComment(): void

public function testListBranches(): void
{
$this->markTestSkipped('Will be implemented in follow-up PR');
$repositoryName = 'test-list-branches-' . \uniqid();
$this->vcsAdapter->createRepository(self::$owner, $repositoryName, false);

try {
// Create initial file on main branch
$this->vcsAdapter->createFile(self::$owner, $repositoryName, 'README.md', '# Test');

// Create additional branches
$this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-1', 'main');
sleep(1);
$this->vcsAdapter->createBranch(self::$owner, $repositoryName, 'feature-2', 'main');
sleep(1);

// Test listBranches
$branches = $this->vcsAdapter->listBranches(self::$owner, $repositoryName);

Comment thread
jaysomani marked this conversation as resolved.
Outdated
$this->assertIsArray($branches);
$this->assertNotEmpty($branches);
$this->assertContains('main', $branches);
$this->assertContains('feature-1', $branches);
$this->assertContains('feature-2', $branches);
$this->assertGreaterThanOrEqual(3, count($branches));
} finally {
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
}
}

public function testListRepositoryLanguages(): void
Expand Down