Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always expect pagination for GETs #358

Merged
merged 1 commit into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion docs/IMPLEMENTATION_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ With the basics for making requests to the GitLab API covered in the `GitLabCore
is simple (most of the time).

Almost all methods in other classes end up calling `self._make_requests_to_api`, which takes care of making the HTTP
GitLab API requests with proper authentication, sometimes pagination, if needed retries & timeouts support, and more.
GitLab API requests with proper authentication, pagination, retries, timeouts and more.

Sometimes there is some logic in these methods if:
* we only need a specific part of the response from GitLab API - see `GitLabProjects.get_all_projects()` as an example,
Expand Down
6 changes: 3 additions & 3 deletions gitlabform/gitlab/branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def unprotect_branch_new_api(self, project_and_group_name, branch):

def get_branches(self, project_and_group_name):
result = self._make_requests_to_api(
"projects/%s/repository/branches", project_and_group_name, paginated=True
"projects/%s/repository/branches", project_and_group_name
)
return sorted(map(lambda x: x["name"], result))

Expand Down Expand Up @@ -170,7 +170,7 @@ def delete_branch(self, project_and_group_name, branch):

def get_protected_branches(self, project_and_group_name):
branches = self._make_requests_to_api(
"projects/%s/repository/branches", project_and_group_name, paginated=True
"projects/%s/repository/branches", project_and_group_name
)

protected_branches = []
Expand All @@ -183,7 +183,7 @@ def get_protected_branches(self, project_and_group_name):

def get_unprotected_branches(self, project_and_group_name):
branches = self._make_requests_to_api(
"projects/%s/repository/branches", project_and_group_name, paginated=True
"projects/%s/repository/branches", project_and_group_name
)

unprotected_branches = []
Expand Down
15 changes: 6 additions & 9 deletions gitlabform/gitlab/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,11 @@ def _make_requests_to_api(
method="GET",
data=None,
expected_codes=200,
paginated=False,
json=None,
):
"""
Makes a HTTP request (or requests) to the GitLab API endpoint. It takes case of making as many requests as
needed in case we are using a paginated endpoint. (See underlying method for authentication, retries,
timeout etc.)
Makes an HTTP request or requests to the GitLab API endpoint. More than one request is made automatically
if the endpoint is paginated. (See underlying method for authentication, retries, timeout etc.)

:param path_as_format_string: path with parts to be replaced by values from `args` replaced by '%s'
(aka the old-style Python string formatting, see:
Expand All @@ -119,14 +117,13 @@ def _make_requests_to_api(
:param data: dict with data to be 'PUT'ted or 'POST'ed
:param expected_codes: a single HTTP code (like: 200) or a list of accepted HTTP codes
- if the call to the API will return other code an exception will be thrown
:param paginated: if given API is paginated (see https://docs.gitlab.com/ee/api/#pagination )
:param json: alternatively to `dict` you can set this to a string that can be parsed as JSON that will
be used as data to be 'PUT'ted or 'POST'ed
:return: data returned by the endpoint, as a JSON object. If the API is paginated the it returns JSONs with
:return: data returned by the endpoint, as a JSON object. If the API is paginated, it returns JSONs with
arrays of objects and then this method returns JSON with a single array that contains all of those
objects.
"""
if not paginated:
if method != "GET":
response = self._make_request_to_api(
path_as_format_string, args, method, data, expected_codes, json
)
Expand All @@ -142,9 +139,9 @@ def _make_requests_to_api(
)
results = first_response.json()

# In newer versions of GitLab the 'X-Total-Pages' may not be available
# In newer versions of GitLab the 'x-total-pages' may not be available
# anymore, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43159
# so let's switch to thew newer style.
# so let's use the 'x-next-page' header instead

response = first_response
while True:
Expand Down
4 changes: 2 additions & 2 deletions gitlabform/gitlab/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def get_groups(self):
"""
:return: sorted list of groups
"""
result = self._make_requests_to_api("groups?all_available=true", paginated=True)
result = self._make_requests_to_api("groups?all_available=true")
return sorted(map(lambda x: x["full_path"], result))

def get_projects(self, group, include_archived=False, only_names=True):
Expand All @@ -81,7 +81,7 @@ def get_projects(self, group, include_archived=False, only_names=True):
query_string = "include_subgroups=true&archived=false"

projects = self._make_requests_to_api(
f"groups/%s/projects?{query_string}", group, paginated=True
f"groups/%s/projects?{query_string}", group
)
except NotFoundException:
projects = []
Expand Down
8 changes: 3 additions & 5 deletions gitlabform/gitlab/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ def get_project_members(self, project_and_group_name, all=False):
if all:
url_template += "/all"

return self._make_requests_to_api(
url_template, project_and_group_name, paginated=True
)
return self._make_requests_to_api(url_template, project_and_group_name)

def get_shared_with_groups(self, project_and_group_name):
# a dict with groups that this project has been shared with
Expand Down Expand Up @@ -57,12 +55,12 @@ def get_group_members(self, group_name, with_inherited=False):
if with_inherited:
url_template += "/all"

return self._make_requests_to_api(url_template, group_name, paginated=True)
return self._make_requests_to_api(url_template, group_name)

def get_members_from_project(self, project_and_group_name):
# note that this DOES NOT return inherited users
members = self._make_requests_to_api(
"projects/%s/members", project_and_group_name, paginated=True
"projects/%s/members", project_and_group_name
)
# it will return {username1: {...api info about username1...}, username2: {...}}
# otherwise it can get very long to iterate when checking if a user
Expand Down
1 change: 0 additions & 1 deletion gitlabform/gitlab/merge_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def get_mrs(self, project_and_group_name):
return self._make_requests_to_api(
"projects/%s/merge_requests?scope=all&state=opened",
project_and_group_name,
paginated=True,
)

def get_mr(self, project_and_group_name, mr_iid):
Expand Down
1 change: 0 additions & 1 deletion gitlabform/gitlab/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ def get_pipelines(self, project_and_group_name, branch):
pipelines = self._make_requests_to_api(
"projects/%s/pipelines?ref=%s",
(project_and_group_name, branch),
paginated=True,
)
return pipelines

Expand Down
4 changes: 1 addition & 3 deletions gitlabform/gitlab/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@ def get_all_projects(self, include_archived=False):
query_string = "order_by=name&sort=asc"
else:
query_string = "order_by=name&sort=asc&archived=false"
result = self._make_requests_to_api(
f"projects?{query_string}", paginated=True
)
result = self._make_requests_to_api(f"projects?{query_string}")
return sorted(map(lambda x: x["path_with_namespace"], result))
except NotFoundException:
return []
Expand Down
1 change: 0 additions & 1 deletion gitlabform/gitlab/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def get_protected_tags(self, project_and_group_name):
return self._make_requests_to_api(
"projects/%s/protected_tags",
project_and_group_name,
paginated=True,
)

def protect_tag(self, project_and_group_name, tag_name, create_access_level):
Expand Down