summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/api-objects.rst1
-rw-r--r--docs/gl_objects/search.rst53
-rw-r--r--gitlab/__init__.py19
-rw-r--r--gitlab/exceptions.py4
-rw-r--r--gitlab/v4/objects.py42
5 files changed, 119 insertions, 0 deletions
diff --git a/docs/api-objects.rst b/docs/api-objects.rst
index c4bc421..3c221c6 100644
--- a/docs/api-objects.rst
+++ b/docs/api-objects.rst
@@ -28,6 +28,7 @@ API examples
gl_objects/pagesdomains
gl_objects/projects
gl_objects/runners
+ gl_objects/search
gl_objects/settings
gl_objects/snippets
gl_objects/system_hooks
diff --git a/docs/gl_objects/search.rst b/docs/gl_objects/search.rst
new file mode 100644
index 0000000..750bbe0
--- /dev/null
+++ b/docs/gl_objects/search.rst
@@ -0,0 +1,53 @@
+##########
+Search API
+##########
+
+You can search for resources at the top level, in a project or in a group.
+Searches are based on a scope (issues, merge requests, and so on) and a search
+string.
+
+Reference
+---------
+
+* v4 API:
+
+ + :attr:`gitlab.Gitlab.search`
+ + :attr:`gitlab.v4.objects.Group.search`
+ + :attr:`gitlab.v4.objects.Project.search`
+
+* GitLab API: https://docs.gitlab.com/ce/api/search.html
+
+Examples
+--------
+
+Search for issues matching a specific string::
+
+ # global search
+ gl.search('issues', 'regression')
+
+ # group search
+ group = gl.groups.get('mygroup')
+ group.search('issues', 'regression')
+
+ # project search
+ project = gl.projects.get('myproject')
+ project.search('issues', 'regression')
+
+The ``search()`` methods implement the pagination support::
+
+ # get lists of 10 items, and start at page 2
+ gl.search('issues', search_str, page=2, per_page=10)
+
+ # get a generator that will automatically make required API calls for
+ # pagination
+ for item in gl.search('issues', search_str, as_list=False):
+ do_something(item)
+
+The search API doesn't return objects, but dicts. If you need to act on
+objects, you need to create them explicitly::
+
+ for item in gl.search('issues', search_str, as_list=False):
+ issue_project = gl.projects.get(item['project_id'], lazy=True)
+ issue = issue_project.issues.get(item['iid'])
+ issue.state = 'closed'
+ issue.save()
diff --git a/gitlab/__init__.py b/gitlab/__init__.py
index 3a36bf2..c0562da 100644
--- a/gitlab/__init__.py
+++ b/gitlab/__init__.py
@@ -555,6 +555,25 @@ class Gitlab(object):
"""
return self.http_request('delete', path, **kwargs)
+ @on_http_error(GitlabSearchError)
+ def search(self, scope, search, **kwargs):
+ """Search GitLab resources matching the provided string.'
+
+ Args:
+ scope (str): Scope of the search
+ search (str): Search string
+ **kwargs: Extra options to send to the server (e.g. sudo)
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabSearchError: If the server failed to perform the request
+
+ Returns:
+ GitlabList: A list of dicts describing the resources found.
+ """
+ data = {'scope': scope, 'search': search}
+ return self.http_list('/search', query_data=data, **kwargs)
+
class GitlabList(object):
"""Generator representing a list of remote objects.
diff --git a/gitlab/exceptions.py b/gitlab/exceptions.py
index 744890f..00d99c6 100644
--- a/gitlab/exceptions.py
+++ b/gitlab/exceptions.py
@@ -197,6 +197,10 @@ class GitlabOwnershipError(GitlabOperationError):
pass
+class GitlabSearchError(GitlabOperationError):
+ pass
+
+
def on_http_error(error):
"""Manage GitlabHttpError exceptions.
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index ac25f1e..6f40dc8 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -713,6 +713,27 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
path = '/groups/%d/projects/%d' % (self.id, to_project_id)
self.manager.gitlab.http_post(path, **kwargs)
+ @cli.register_custom_action('Group', ('scope', 'search'))
+ @exc.on_http_error(exc.GitlabSearchError)
+ def search(self, scope, search, **kwargs):
+ """Search the group resources matching the provided string.'
+
+ Args:
+ scope (str): Scope of the search
+ search (str): Search string
+ **kwargs: Extra options to send to the server (e.g. sudo)
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabSearchError: If the server failed to perform the request
+
+ Returns:
+ GitlabList: A list of dicts describing the resources found.
+ """
+ data = {'scope': scope, 'search': search}
+ path = '/groups/%d/search' % self.get_id()
+ return self.manager.gitlab.http_list(path, query_data=data, **kwargs)
+
class GroupManager(CRUDMixin, RESTManager):
_path = '/groups'
@@ -2867,6 +2888,27 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
"markdown": data['markdown']
}
+ @cli.register_custom_action('Project', ('scope', 'search'))
+ @exc.on_http_error(exc.GitlabSearchError)
+ def search(self, scope, search, **kwargs):
+ """Search the project resources matching the provided string.'
+
+ Args:
+ scope (str): Scope of the search
+ search (str): Search string
+ **kwargs: Extra options to send to the server (e.g. sudo)
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabSearchError: If the server failed to perform the request
+
+ Returns:
+ GitlabList: A list of dicts describing the resources found.
+ """
+ data = {'scope': scope, 'search': search}
+ path = '/projects/%d/search' % self.get_id()
+ return self.manager.gitlab.http_list(path, query_data=data, **kwargs)
+
class ProjectManager(CRUDMixin, RESTManager):
_path = '/projects'