Skip to content
Open
Show file tree
Hide file tree
Changes from 15 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
58 changes: 41 additions & 17 deletions src/VCS/Adapter/Git/GitHub.php
Original file line number Diff line number Diff line change
Expand Up @@ -742,32 +742,58 @@ public function getPullRequestFromBranch(string $owner, string $repositoryName,
}

/**
* Lists branches for a given repository
* Lists branches for a given repository, optionally filtered by a search string.
*
* @param string $owner Owner name of the repository
* @param string $repositoryName Name of the GitHub repository
* @param int $perPage Number of branches to fetch per page
* @param int $page Page number to start fetching from
* @return array<string> List of branch names as array
* @param string $owner
* @param string $repositoryName
* @param int $perPage Clamped to [1, 100]
* @param int $page Page number (1-based)
* @param string $search Substring filter; empty returns all branches
* @return array<string> List of branch names
*/
public function listBranches(string $owner, string $repositoryName, int $perPage = 100, int $page = 1): array
public function listBranches(string $owner, string $repositoryName, int $perPage = 100, int $page = 1, string $search = ''): array
{
$url = "/repos/$owner/$repositoryName/branches";
$perPage = min(max($perPage, 1), 100);

$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"], [
'page' => $page,
'per_page' => $perPage,
$gql = <<<'GRAPHQL'
query ListBranches($owner: String!, $name: String!, $first: Int!, $query: String) {
repository(owner: $owner, name: $name) {
refs(refPrefix: "refs/heads/", first: $first, orderBy: {field: ALPHABETICAL, direction: ASC}, query: $query) {
edges {
node {
name
}
}
}
}
}
GRAPHQL;

$response = $this->call(self::METHOD_POST, '/graphql', ['Authorization' => "Bearer $this->accessToken"], [
'query' => $gql,
'variables' => [
'owner' => $owner,
'name' => $repositoryName,
'first' => $perPage,
'query' => $search !== '' ? $search : null,
],
]);

$statusCode = $response['headers']['status-code'] ?? 0;
$responseBody = $response['body'] ?? [];

if ($statusCode < 200 || $statusCode >= 300 || !is_array($responseBody)) {
if ($statusCode < 200 || $statusCode >= 300 || !is_array($responseBody) || array_key_exists('errors', $responseBody)) {
return [];
}

return array_values(array_map(fn ($branch) => $branch['name'] ?? '', $responseBody));
$repository = $responseBody['data']['repository'] ?? null;
$refs = is_array($repository) ? ($repository['refs'] ?? null) : null;

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

return array_map(fn ($edge) => $edge['node']['name'] ?? '', $refs['edges'] ?? []);
}

/**
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -831,15 +857,13 @@ public function getLatestCommit(string $owner, string $repositoryName, string $b
$responseBody = $response['body'] ?? [];
$responseBodyCommit = $responseBody['commit'] ?? [];
$responseBodyCommitAuthor = $responseBodyCommit['author'] ?? [];
$responseBodyAuthor = $responseBody['author'] ?? [];
$responseBodyAuthor = is_array($responseBody['author'] ?? null) ? $responseBody['author'] : [];

if (
!array_key_exists('name', $responseBodyCommitAuthor) ||
!array_key_exists('message', $responseBodyCommit) ||
!array_key_exists('sha', $responseBody) ||
!array_key_exists('html_url', $responseBody) ||
!array_key_exists('avatar_url', $responseBodyAuthor) ||
!array_key_exists('html_url', $responseBodyAuthor)
!array_key_exists('html_url', $responseBody)
) {
throw new Exception("Latest commit response is missing required information.");
}
Expand Down
13 changes: 7 additions & 6 deletions tests/VCS/Adapter/GitHubTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -540,14 +540,15 @@ public function testListBranchesPagination(): void
/** @var GitHub $adapter */
$adapter = $this->vcsAdapter;

$page1 = $adapter->listBranches(static::$owner, $repositoryName, 1, 1);
$this->assertSame(['branch-a'], $page1);

$page2 = $adapter->listBranches(static::$owner, $repositoryName, 1, 2);
$this->assertSame(['branch-b'], $page2);

$all = $adapter->listBranches(static::$owner, $repositoryName, 100, 1);
$this->assertEqualsCanonicalizing([static::$defaultBranch, 'branch-a', 'branch-b'], $all);

$searchResults = $adapter->listBranches(static::$owner, $repositoryName, 100, 1, 'branch');
$this->assertEqualsCanonicalizing(['branch-a', 'branch-b'], $searchResults);

// GitHub refs(query:) does substring matching, so 'ranch' matches 'branch-a' and 'branch-b'
$substringSearch = $adapter->listBranches(static::$owner, $repositoryName, 100, 1, 'ranch');
$this->assertEqualsCanonicalizing(['branch-a', 'branch-b'], $substringSearch);
} finally {
$this->vcsAdapter->deleteRepository(static::$owner, $repositoryName);
}
Expand Down
Loading