Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/VCS/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,14 @@ abstract public function getUser(string $username): array;
/**
* Get owner name of the installation
*
* @return string
* For GitHub: Uses installationId to identify the GitHub App installation
* For Gitea: Requires repositoryId since OAuth tokens can access multiple organizations
*
* @param string $installationId Installation ID (GitHub) or empty string (Gitea)
* @param int|null $repositoryId Repository ID (required for Gitea, ignored by GitHub)
* @return string Owner login/username
*/
abstract public function getOwnerName(string $installationId): string;
abstract public function getOwnerName(string $installationId, ?int $repositoryId = null): string;

/**
* Search repositories for GitHub App
Expand Down
7 changes: 5 additions & 2 deletions src/VCS/Adapter/Git/GitHub.php
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,13 @@ public function getUser(string $username): array
/**
* Get owner name of the GitHub installation
*
* @return string
* @param string $installationId GitHub App installation ID
* @param int|null $repositoryId Not used by GitHub (parameter exists for Gitea compatibility)
* @return string Owner login/username
*/
public function getOwnerName(string $installationId): string
public function getOwnerName(string $installationId, ?int $repositoryId = null): string
{
// GitHub doesn't use $repositoryId - only installationId
$url = '/app/installations/' . $installationId;
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]);

Expand Down
30 changes: 28 additions & 2 deletions src/VCS/Adapter/Git/Gitea.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,35 @@ public function getUser(string $username): array
throw new Exception("Not implemented yet");
}

public function getOwnerName(string $installationId): string
public function getOwnerName(string $installationId, ?int $repositoryId = null): string
{
throw new Exception("getOwnerName() is not applicable for Gitea");
if ($repositoryId === null || $repositoryId <= 0) {
throw new Exception("repositoryId is required for Gitea");
}

$url = "/repositories/{$repositoryId}";

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

$responseHeaders = $response['headers'] ?? [];
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;

if ($responseHeadersStatusCode === 404) {
throw new RepositoryNotFound("Repository not found");
}

if ($responseHeadersStatusCode >= 400) {
throw new Exception("Failed to get repository: HTTP {$responseHeadersStatusCode}");
}

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

if (empty($owner['login'])) {
throw new Exception("Owner login missing or empty in response");
}

return $owner['login'];
}

public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array
Expand Down
42 changes: 38 additions & 4 deletions tests/VCS/Adapter/GiteaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -721,19 +721,53 @@ public function testDeleteNonExistingRepositoryFails(): void
}

public function testGetOwnerName(): void
{
$repositoryName = 'test-get-owner-name-' . \uniqid();
$created = $this->vcsAdapter->createRepository(self::$owner, $repositoryName, false);

try {
$this->assertIsArray($created);
$this->assertArrayHasKey('id', $created);
$this->assertIsScalar($created['id']);
$repositoryId = (int) $created['id'];

$ownerName = $this->vcsAdapter->getOwnerName('', $repositoryId);

$this->assertSame(self::$owner, $ownerName);
} finally {
$this->vcsAdapter->deleteRepository(self::$owner, $repositoryName);
}
}

public function testGetOwnerNameWithZeroRepositoryId(): void
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('repositoryId is required for Gitea');

$this->vcsAdapter->getOwnerName('', 0);
}

public function testGetOwnerNameWithoutRepositoryId(): void
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('not applicable for Gitea');
$this->expectExceptionMessage('repositoryId is required for Gitea');

$this->vcsAdapter->getOwnerName('');
}

public function testGetOwnerNameWithRandomInput(): void
public function testGetOwnerNameWithInvalidRepositoryId(): void
{
$this->expectException(\Utopia\VCS\Exception\RepositoryNotFound::class);

$this->vcsAdapter->getOwnerName('', 999999999);
}

public function testGetOwnerNameWithNullRepositoryId(): void
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('not applicable for Gitea');
$this->expectExceptionMessage('repositoryId is required for Gitea');

$this->vcsAdapter->getOwnerName('random-gibberish-' . \uniqid());
$this->vcsAdapter->getOwnerName('', null);
}

public function testGetPullRequestFromBranch(): void
Expand Down
Loading