mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
fix(bitbucket): Bitbucket Cloud pagination not working beyond first page (#502)
This commit is contained in:
parent
aab4a92a87
commit
7cbda320cb
2 changed files with 32 additions and 12 deletions
|
|
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [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
|
## [4.6.7] - 2025-09-08
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -148,13 +148,14 @@ function cloudClient(user: string | undefined, token: string | undefined): Bitbu
|
||||||
**/
|
**/
|
||||||
const getPaginatedCloud = async <T>(
|
const getPaginatedCloud = async <T>(
|
||||||
path: CloudGetRequestPath,
|
path: CloudGetRequestPath,
|
||||||
get: (url: CloudGetRequestPath) => Promise<CloudPaginatedResponse<T>>
|
get: (path: CloudGetRequestPath, query?: Record<string, string>) => Promise<CloudPaginatedResponse<T>>
|
||||||
): Promise<T[]> => {
|
): Promise<T[]> => {
|
||||||
const results: T[] = [];
|
const results: T[] = [];
|
||||||
let url = path;
|
let nextPath = path;
|
||||||
|
let nextQuery = undefined;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const response = await get(url);
|
const response = await get(nextPath, nextQuery);
|
||||||
|
|
||||||
if (!response.values || response.values.length === 0) {
|
if (!response.values || response.values.length === 0) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -166,25 +167,38 @@ const getPaginatedCloud = async <T>(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
url = response.next as CloudGetRequestPath;
|
const parsedUrl = parseUrl(response.next);
|
||||||
|
nextPath = parsedUrl.path as CloudGetRequestPath;
|
||||||
|
nextQuery = parsedUrl.query;
|
||||||
}
|
}
|
||||||
return results;
|
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[]}> {
|
async function cloudGetReposForWorkspace(client: BitbucketClient, workspaces: string[]): Promise<{validRepos: CloudRepository[], notFoundWorkspaces: string[]}> {
|
||||||
const results = await Promise.allSettled(workspaces.map(async (workspace) => {
|
const results = await Promise.allSettled(workspaces.map(async (workspace) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`Fetching all repos for workspace ${workspace}...`);
|
logger.debug(`Fetching all repos for workspace ${workspace}...`);
|
||||||
|
|
||||||
const path = `/repositories/${workspace}` as CloudGetRequestPath;
|
|
||||||
const { durationMs, data } = await measure(async () => {
|
const { durationMs, data } = await measure(async () => {
|
||||||
const fetchFn = () => getPaginatedCloud<CloudRepository>(path, async (url) => {
|
const fetchFn = () => getPaginatedCloud<CloudRepository>(`/repositories/${workspace}` as CloudGetRequestPath, async (path, query) => {
|
||||||
const response = await client.apiClient.GET(url, {
|
const response = await client.apiClient.GET(path, {
|
||||||
params: {
|
params: {
|
||||||
path: {
|
path: {
|
||||||
workspace,
|
workspace,
|
||||||
}
|
},
|
||||||
|
query: query,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const { data, error } = response;
|
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}...`);
|
logger.debug(`Fetching all repos for project ${project} for workspace ${workspace}...`);
|
||||||
try {
|
try {
|
||||||
const path = `/repositories/${workspace}` as CloudGetRequestPath;
|
const repos = await getPaginatedCloud<CloudRepository>(`/repositories/${workspace}` as CloudGetRequestPath, async (path, query) => {
|
||||||
const repos = await getPaginatedCloud<CloudRepository>(path, async (url) => {
|
const response = await client.apiClient.GET(path, {
|
||||||
const response = await client.apiClient.GET(url, {
|
|
||||||
params: {
|
params: {
|
||||||
|
path: {
|
||||||
|
workspace,
|
||||||
|
},
|
||||||
query: {
|
query: {
|
||||||
|
...query,
|
||||||
q: `project.key="${project_name}"`
|
q: `project.key="${project_name}"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue