summaryrefslogtreecommitdiff
path: root/gitlab
diff options
context:
space:
mode:
Diffstat (limited to 'gitlab')
-rw-r--r--gitlab/base.py2
-rw-r--r--gitlab/cli.py14
-rw-r--r--gitlab/const.py17
-rw-r--r--gitlab/tests/objects/test_bridges.py111
-rw-r--r--gitlab/tests/test_base.py7
-rw-r--r--gitlab/v4/cli.py8
-rw-r--r--gitlab/v4/objects/__init__.py36
7 files changed, 182 insertions, 13 deletions
diff --git a/gitlab/base.py b/gitlab/base.py
index 40bc06c..ad35339 100644
--- a/gitlab/base.py
+++ b/gitlab/base.py
@@ -131,7 +131,7 @@ class RESTObject(object):
def _update_attrs(self, new_attrs):
self.__dict__["_updated_attrs"] = {}
- self.__dict__["_attrs"].update(new_attrs)
+ self.__dict__["_attrs"] = new_attrs
def get_id(self):
"""Returns the id of the resource."""
diff --git a/gitlab/cli.py b/gitlab/cli.py
index d356d16..ff98a4f 100644
--- a/gitlab/cli.py
+++ b/gitlab/cli.py
@@ -149,6 +149,20 @@ def _parse_value(v):
return v
+def docs():
+ """
+ Provide a statically generated parser for sphinx only, so we don't need
+ to provide dummy gitlab config for readthedocs.
+ """
+ if "sphinx" not in sys.modules:
+ sys.exit("Docs parser is only intended for build_sphinx")
+
+ parser = _get_base_parser(add_help=False)
+ cli_module = importlib.import_module("gitlab.v4.cli")
+
+ return _get_parser(cli_module)
+
+
def main():
if "--version" in sys.argv:
print(gitlab.__version__)
diff --git a/gitlab/const.py b/gitlab/const.py
index 7791a39..0d2f421 100644
--- a/gitlab/const.py
+++ b/gitlab/const.py
@@ -33,3 +33,20 @@ NOTIFICATION_LEVEL_WATCH = "watch"
NOTIFICATION_LEVEL_GLOBAL = "global"
NOTIFICATION_LEVEL_MENTION = "mention"
NOTIFICATION_LEVEL_CUSTOM = "custom"
+
+# Search scopes
+# all scopes (global, group and project)
+SEARCH_SCOPE_PROJECTS = "projects"
+SEARCH_SCOPE_ISSUES = "issues"
+SEARCH_SCOPE_MERGE_REQUESTS = "merge_requests"
+SEARCH_SCOPE_MILESTONES = "milestones"
+SEARCH_SCOPE_WIKI_BLOBS = "wiki_blobs"
+SEARCH_SCOPE_COMMITS = "commits"
+SEARCH_SCOPE_BLOBS = "blobs"
+SEARCH_SCOPE_USERS = "users"
+
+# specific global scope
+SEARCH_SCOPE_GLOBAL_SNIPPET_TITLES = "snippet_titles"
+
+# specific project scope
+SEARCH_SCOPE_PROJECT_NOTES = "notes"
diff --git a/gitlab/tests/objects/test_bridges.py b/gitlab/tests/objects/test_bridges.py
new file mode 100644
index 0000000..ea8c634
--- /dev/null
+++ b/gitlab/tests/objects/test_bridges.py
@@ -0,0 +1,111 @@
+"""
+GitLab API: https://docs.gitlab.com/ee/api/jobs.html#list-pipeline-bridges
+"""
+import re
+
+import pytest
+import responses
+
+from gitlab.v4.objects import Project, ProjectPipelineBridge
+
+
+@pytest.fixture
+def resp_list_bridges():
+ export_bridges_content = {
+ "commit": {
+ "author_email": "admin@example.com",
+ "author_name": "Administrator",
+ "created_at": "2015-12-24T16:51:14.000+01:00",
+ "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "message": "Test the CI integration.",
+ "short_id": "0ff3ae19",
+ "title": "Test the CI integration.",
+ },
+ "allow_failure": False,
+ "created_at": "2015-12-24T15:51:21.802Z",
+ "started_at": "2015-12-24T17:54:27.722Z",
+ "finished_at": "2015-12-24T17:58:27.895Z",
+ "duration": 240,
+ "id": 7,
+ "name": "teaspoon",
+ "pipeline": {
+ "id": 6,
+ "ref": "master",
+ "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+ "status": "pending",
+ "created_at": "2015-12-24T15:50:16.123Z",
+ "updated_at": "2015-12-24T18:00:44.432Z",
+ "web_url": "https://example.com/foo/bar/pipelines/6",
+ },
+ "ref": "master",
+ "stage": "test",
+ "status": "pending",
+ "tag": False,
+ "web_url": "https://example.com/foo/bar/-/jobs/7",
+ "user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": "",
+ },
+ "downstream_pipeline": {
+ "id": 5,
+ "sha": "f62a4b2fb89754372a346f24659212eb8da13601",
+ "ref": "master",
+ "status": "pending",
+ "created_at": "2015-12-24T17:54:27.722Z",
+ "updated_at": "2015-12-24T17:58:27.896Z",
+ "web_url": "https://example.com/diaspora/diaspora-client/pipelines/5",
+ },
+ }
+
+ export_pipelines_content = [
+ {
+ "id": 6,
+ "status": "pending",
+ "ref": "new-pipeline",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "web_url": "https://example.com/foo/bar/pipelines/47",
+ "created_at": "2016-08-11T11:28:34.085Z",
+ "updated_at": "2016-08-11T11:32:35.169Z",
+ },
+ ]
+
+ with responses.RequestsMock() as rsps:
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/pipelines/6/bridges",
+ json=[export_bridges_content],
+ content_type="application/json",
+ status=200,
+ )
+ rsps.add(
+ method=responses.GET,
+ url="http://localhost/api/v4/projects/1/pipelines",
+ json=export_pipelines_content,
+ content_type="application/json",
+ status=200,
+ )
+ yield rsps
+
+
+def test_list_projects_pipelines_bridges(project, resp_list_bridges):
+ pipeline = project.pipelines.list()[0]
+ bridges = pipeline.bridges.list()
+
+ assert isinstance(bridges, list)
+ assert isinstance(bridges[0], ProjectPipelineBridge)
+ assert bridges[0].downstream_pipeline["id"] == 5
+ assert (
+ bridges[0].downstream_pipeline["sha"]
+ == "f62a4b2fb89754372a346f24659212eb8da13601"
+ )
diff --git a/gitlab/tests/test_base.py b/gitlab/tests/test_base.py
index 58c0d47..a0adcb0 100644
--- a/gitlab/tests/test_base.py
+++ b/gitlab/tests/test_base.py
@@ -128,6 +128,13 @@ class TestRESTObject:
assert {"foo": "foo", "bar": "bar"} == obj._attrs
assert {} == obj._updated_attrs
+ def test_update_attrs_deleted(self, fake_manager):
+ obj = FakeObject(fake_manager, {"foo": "foo", "bar": "bar"})
+ obj.bar = "baz"
+ obj._update_attrs({"foo": "foo"})
+ assert {"foo": "foo"} == obj._attrs
+ assert {} == obj._updated_attrs
+
def test_create_managers(self, fake_gitlab, fake_manager):
class ObjectWithManager(FakeObject):
_managers = (("fakes", "FakeManager"),)
diff --git a/gitlab/v4/cli.py b/gitlab/v4/cli.py
index 51416f1..6172f93 100644
--- a/gitlab/v4/cli.py
+++ b/gitlab/v4/cli.py
@@ -85,11 +85,7 @@ class GitlabCLI(object):
try:
project = self.gl.projects.get(int(self.args["project_id"]), lazy=True)
data = project.exports.get().download()
- if hasattr(sys.stdout, "buffer"):
- # python3
- sys.stdout.buffer.write(data)
- else:
- sys.stdout.write(data)
+ sys.stdout.buffer.write(data)
except Exception as e:
cli.die("Impossible to download the export", e)
@@ -440,5 +436,7 @@ def run(gl, what, action, args, verbose, output, fields):
printer.display(get_dict(data, fields), verbose=verbose, obj=data)
elif isinstance(data, str):
print(data)
+ elif isinstance(data, bytes):
+ sys.stdout.buffer.write(data)
elif hasattr(data, "decode"):
print(data.decode())
diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py
index 80b3c21..edeff04 100644
--- a/gitlab/v4/objects/__init__.py
+++ b/gitlab/v4/objects/__init__.py
@@ -3859,6 +3859,17 @@ class ProjectPipelineJobManager(ListMixin, RESTManager):
_list_filters = ("scope",)
+class ProjectPipelineBridge(RESTObject):
+ pass
+
+
+class ProjectPipelineBridgeManager(ListMixin, RESTManager):
+ _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/bridges"
+ _obj_cls = ProjectPipelineBridge
+ _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"}
+ _list_filters = ("scope",)
+
+
class ProjectPipelineVariable(RESTObject):
_id_attr = "key"
@@ -3872,6 +3883,7 @@ class ProjectPipelineVariableManager(ListMixin, RESTManager):
class ProjectPipeline(RESTObject, RefreshMixin, ObjectDeleteMixin):
_managers = (
("jobs", "ProjectPipelineJobManager"),
+ ("bridges", "ProjectPipelineBridgeManager"),
("variables", "ProjectPipelineVariableManager"),
)
@@ -5422,19 +5434,29 @@ class ProjectManager(CRUDMixin, RESTManager):
)
_types = {"avatar": types.ImageAttribute}
_list_filters = (
- "search",
- "owned",
- "starred",
"archived",
- "visibility",
+ "id_after",
+ "id_before",
+ "last_activity_after",
+ "last_activity_before",
+ "membership",
+ "min_access_level",
"order_by",
- "sort",
+ "owned",
+ "repository_checksum_failed",
+ "repository_storage",
+ "search_namespaces",
+ "search",
"simple",
- "membership",
+ "sort",
+ "starred",
"statistics",
+ "visibility",
+ "wiki_checksum_failed",
+ "with_custom_attributes",
"with_issues_enabled",
"with_merge_requests_enabled",
- "with_custom_attributes",
+ "with_programming_language",
)
def import_project(