fix(bitbucket): Bitbucket Cloud pagination not working beyond first page (#502)

This commit is contained in:
Fede Sanchez 2025-09-15 23:43:50 -03:00 committed by GitHub
parent aab4a92a87
commit 7cbda320cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 12 deletions

View file

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Fixed
- Fixed Bitbucket Cloud pagination not working beyond first page. [#295](https://github.com/sourcebot-dev/sourcebot/issues/295)
## [4.6.7] - 2025-09-08
### Added

View file

@ -148,13 +148,14 @@ function cloudClient(user: string | undefined, token: string | undefined): Bitbu
**/
const getPaginatedCloud = async <T>(
path: CloudGetRequestPath,
get: (url: CloudGetRequestPath) => Promise<CloudPaginatedResponse<T>>
get: (path: CloudGetRequestPath, query?: Record<string, string>) => Promise<CloudPaginatedResponse<T>>
): Promise<T[]> => {
const results: T[] = [];
let url = path;
let nextPath = path;
let nextQuery = undefined;
while (true) {
const response = await get(url);
const response = await get(nextPath, nextQuery);
if (!response.values || response.values.length === 0) {
break;
@ -166,25 +167,38 @@ const getPaginatedCloud = async <T>(
break;
}
url = response.next as CloudGetRequestPath;
const parsedUrl = parseUrl(response.next);
nextPath = parsedUrl.path as CloudGetRequestPath;
nextQuery = parsedUrl.query;
}
return results;
}
/**
* Parse the url into a path and query parameters to be used with the api client (openapi-fetch)
*/
function parseUrl(url: string): { path: string; query: Record<string, string>; } {
const fullUrl = new URL(url);
const path = fullUrl.pathname.replace(/^\/\d+(\.\d+)*/, ''); // remove version number in the beginning of the path
const query = Object.fromEntries(fullUrl.searchParams);
logger.debug(`Parsed url ${url} into path ${path} and query ${JSON.stringify(query)}`);
return { path, query };
}
async function cloudGetReposForWorkspace(client: BitbucketClient, workspaces: string[]): Promise<{validRepos: CloudRepository[], notFoundWorkspaces: string[]}> {
const results = await Promise.allSettled(workspaces.map(async (workspace) => {
try {
logger.debug(`Fetching all repos for workspace ${workspace}...`);
const path = `/repositories/${workspace}` as CloudGetRequestPath;
const { durationMs, data } = await measure(async () => {
const fetchFn = () => getPaginatedCloud<CloudRepository>(path, async (url) => {
const response = await client.apiClient.GET(url, {
const fetchFn = () => getPaginatedCloud<CloudRepository>(`/repositories/${workspace}` as CloudGetRequestPath, async (path, query) => {
const response = await client.apiClient.GET(path, {
params: {
path: {
workspace,
}
},
query: query,
}
});
const { data, error } = response;
@ -238,11 +252,14 @@ async function cloudGetReposForProjects(client: BitbucketClient, projects: strin
logger.debug(`Fetching all repos for project ${project} for workspace ${workspace}...`);
try {
const path = `/repositories/${workspace}` as CloudGetRequestPath;
const repos = await getPaginatedCloud<CloudRepository>(path, async (url) => {
const response = await client.apiClient.GET(url, {
const repos = await getPaginatedCloud<CloudRepository>(`/repositories/${workspace}` as CloudGetRequestPath, async (path, query) => {
const response = await client.apiClient.GET(path, {
params: {
path: {
workspace,
},
query: {
...query,
q: `project.key="${project_name}"`
}
}