Skip to content

Conversation

bardock
Copy link

@bardock bardock commented Sep 9, 2025

Fix: Bitbucket Cloud pagination not working beyond first page

Problem

Issue: #295
When fetching repositories from Bitbucket Cloud workspaces with multiple pages of results, Sourcebot fails on the second page with the following error:

[dev:backend] 2025-09-09T19:11:45.876Z error: [bitbucket] Failed to get repos for workspace emilabs: Error: Failed to fetch projects for workspace emilabs: {"type":"error","error":{"message":"Resource not found","detail":"There is no API hosted at this URL.\n\nFor information about our API's, please refer to the documentation at: https://developer.atlassian.com/bitbucket/api/2/reference/"}}

This is caused by the Bitbucket Cloud API returning full URLs (e.g., https://api.bitbucket.org/2.0/repositories/workspace?page=2) in pagination next responses, but openapi-fetch expects separate path and query parameters. The current implementation was passing the full URL directly to the API client, which doesn't recognize the complete URL format.

Solution

This PR implements proper URL parsing for Bitbucket Cloud pagination to separate paths and query parameters. The implementation includes:

1. URL Parsing Function

  • Created parseUrl() function that properly extracts pathname and query parameters from full URLs
  • Uses the native URL constructor for robust and performant parsing

2. Updated Pagination Handlers

  • Updated cloudGetReposForWorkspace() to use parsed URL components
  • Updated cloudGetReposForProjects() to use parsed URL components
  • Both functions now correctly pass path and query parameters separately to openapi-fetch

Testing

  • Manually tested with Bitbucket Cloud workspaces containing multiple pages of repositories
  • Verified that pagination now works correctly beyond the first page
  • Confirmed that single-page results continue to work as expected
  • All existing tests are still passing

Breaking Changes

None. The changes are backward compatible and only affect the internal pagination URL handling.

Notes

  • This fix specifically addresses Bitbucket Cloud pagination - Bitbucket Server has another implementation for pagination
  • Debug logging includes the parsed path and query for troubleshooting pagination issues

Copy link

coderabbitai bot commented Sep 9, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@WendelBartzUbots
Copy link

WendelBartzUbots commented Sep 10, 2025

@bardock I tested and found the following error:

[dev:backend ] 2025-09-10T18:08:08.875Z error: [bitbucket] Failed to get repos for workspace facebot: TypeError: Invalid URL
[dev:backend ] 2025-09-10T18:08:08.876Z error: [connection-manager] Failed to compile repo data for connection 1 (starter-connection): TypeError: Invalid URL

Apparently, the baseUrl is not being used, and when adjusting it, the issue of duplicating /2.0 occurs.

Copy link
Contributor

@brendan-kellam brendan-kellam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!! Overall LGTM - let's make sure it's working for @WendelBartzUbots, and afterwards will be g2g to merge.

/**
* Parse the url into a path and query parameters to be used with the api client (openapi-fetch)
*/
function parseUrl(url: string, baseUrl: string): { path: string; query: Record<string, string>; } {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are using this in all get callbacks passed to getPaginatedCloud to handle response.next, I wonder if we can just move this logic into getPaginatedCloud directly?

For example, the signature could be:

const getPaginatedCloud = async <T>(
    path: CloudGetRequestPath,
    get: (path: CloudGetRequestPath, query?: string) => Promise<CloudPaginatedResponse<T>>
): Promise<T[]>

And getPaginatedCloud handles deconstructing response.next into path and optionally query.

* Parse the url into a path and query parameters to be used with the api client (openapi-fetch)
*/
function parseUrl(url: string, baseUrl: string): { path: string; query: Record<string, string>; } {
const fullUrl = new URL(url);
Copy link
Contributor

@brendan-kellam brendan-kellam Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bardock I tested and found the following error:

[dev:backend ] 2025-09-10T18:08:08.875Z error: [bitbucket] Failed to get repos for workspace facebot: TypeError: Invalid URL [dev:backend ] 2025-09-10T18:08:08.876Z error: [connection-manager] Failed to compile repo data for connection 1 (starter-connection): TypeError: Invalid URL

Apparently, the baseUrl is not being used, and when adjusting it, the issue of duplicating /2.0 occurs.

RE @WendelBartzUbots @bardock - best guess is that url is /repositories/${workspace} (and not the full url) for the first call of the callback provided to getPaginatedCloud. I think the approach I outlined above should fix this (i.e., just deconstruct response.next and not path)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants