Skip to content

refactor(bitbucket): hoist the Data Center non-advancing-pagination guard into one helper #1052

Description

@potiuk

What

tools/bitbucket/src/magpie_bitbucket/datacenter.py repeats the same non-advancing-pagination guard in six functions:

if next_start <= start:
    break
  • get_repository_restrictions
  • list_open_pull_requests
  • get_pull_request_commits
  • get_pull_request_status
  • get_pull_request_reviews
  • get_pull_request_discussion

cloud.py has the equivalent protection — a server that keeps handing back the same page — but centralised in one _validated_next_url() helper that every paginating call routes through.

Why it matters

The duplication is not just untidy; it means each copy needs its own test, and they do not all have one.

#1047 added a test pinning the guard in get_pull_request_commits, which is good. While reviewing it I deleted the same guard from get_repository_restrictions instead, by mistake — and the entire 101-test suite still passed. So at least one copy is completely unpinned: it can be removed and nothing notices.

The failure it protects against is an infinite request loop against a remote server, which is the kind of bug you want a test to catch rather than a user.

The contrast with cloud.py is the useful part. Because cloud's guard lives in one helper, a single test covers every caller, and a newly added paginating endpoint inherits the protection for free — as #1041 demonstrated when it added get_pull_request_tasks and got the repeated-URL check without doing anything.

Suggested fix

Hoist the datacenter guard into a shared helper the way cloud.py does — something that owns the "advance start, or stop" decision and is called by all six paginators. That would:

  • make one test cover all six call sites, rather than needing five more tests;
  • mean the next Data Center paginator cannot be written without the guard;
  • bring the two backends' pagination handling into the same shape, which makes them easier to compare when either changes.

Worth doing as its own change rather than folded into a feature PR, since it touches six functions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions