summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/gl_objects/geo_nodes.rst2
-rw-r--r--docs/gl_objects/issues.rst38
-rw-r--r--gitlab/v4/objects.py38
-rwxr-xr-xtools/ee-test.py31
4 files changed, 102 insertions, 7 deletions
diff --git a/docs/gl_objects/geo_nodes.rst b/docs/gl_objects/geo_nodes.rst
index 44ed391..181ec91 100644
--- a/docs/gl_objects/geo_nodes.rst
+++ b/docs/gl_objects/geo_nodes.rst
@@ -11,7 +11,7 @@ Reference
+ :class:`gitlab.v4.objects.GeoNodeManager`
+ :attr:`gitlab.Gitlab.geonodes`
-* GitLab API: https://docs.gitlab.com/ee/api/geo_nodes.html
+* GitLab API: https://docs.gitlab.com/ee/api/geo_nodes.html (EE feature)
Examples
--------
diff --git a/docs/gl_objects/issues.rst b/docs/gl_objects/issues.rst
index 0a6b254..7abaa78 100644
--- a/docs/gl_objects/issues.rst
+++ b/docs/gl_objects/issues.rst
@@ -159,3 +159,41 @@ Get the list of merge requests that will close an issue when merged::
Get the list of participants::
users = issue.participants()
+
+Issue links
+===========
+
+Reference
+---------
+
+* v4 API:
+
+ + :class:`gitlab.v4.objects.ProjectIssueLink`
+ + :class:`gitlab.v4.objects.ProjectIssueLinkManager`
+ + :attr:`gitlab.v4.objects.ProjectIssue.links`
+
+* GitLab API: https://docs.gitlab.com/ee/api/issue_links.html (EE feature)
+
+Examples
+--------
+
+List the issues linked to ``i1``::
+
+ links = i1.links.list()
+
+Link issue ``i1`` to issue ``i2``::
+
+ data = {
+ 'target_project_id': i2.project_id,
+ 'target_issue_iid': i2.iid
+ }
+ src_issue, dest_issue = i1.links.create(data)
+
+.. note::
+
+ The ``create()`` method returns the source and destination ``ProjectIssue``
+ objects, not a ``ProjectIssueLink`` object.
+
+Delete a link::
+
+ i1.links.delete(issue_link_id)
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
index 8feb09b..f5160e5 100644
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -1539,6 +1539,43 @@ class ProjectIssueDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
_create_attrs = (('body',), ('created_at',))
+class ProjectIssueLink(ObjectDeleteMixin, RESTObject):
+ _id_attr = 'issue_link_id'
+
+
+class ProjectIssueLinkManager(ListMixin, CreateMixin, DeleteMixin,
+ RESTManager):
+ _path = '/projects/%(project_id)s/issues/%(issue_iid)s/links'
+ _obj_cls = ProjectIssueLink
+ _from_parent_attrs = {'project_id': 'project_id', 'issue_iid': 'iid'}
+ _create_attrs = (('target_project_id', 'target_issue_iid'), tuple())
+
+ @exc.on_http_error(exc.GitlabCreateError)
+ def create(self, data, **kwargs):
+ """Create a new object.
+
+ Args:
+ data (dict): parameters to send to the server to create the
+ resource
+ **kwargs: Extra options to send to the Gitlab server (e.g. sudo)
+
+ Returns:
+ RESTObject, RESTObject: The source and target issues
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabCreateError: If the server cannot perform the request
+ """
+ self._check_missing_create_attrs(data)
+ server_data = self.gitlab.http_post(self.path, post_data=data,
+ **kwargs)
+ source_issue = ProjectIssue(self._parent.manager,
+ server_data['source_issue'])
+ target_issue = ProjectIssue(self._parent.manager,
+ server_data['target_issue'])
+ return source_issue, target_issue
+
+
class ProjectIssue(UserAgentDetailMixin, SubscribableMixin, TodoMixin,
TimeTrackingMixin, ParticipantsMixin, SaveMixin,
ObjectDeleteMixin, RESTObject):
@@ -1547,6 +1584,7 @@ class ProjectIssue(UserAgentDetailMixin, SubscribableMixin, TodoMixin,
_managers = (
('awardemojis', 'ProjectIssueAwardEmojiManager'),
('discussions', 'ProjectIssueDiscussionManager'),
+ ('links', 'ProjectIssueLinkManager'),
('notes', 'ProjectIssueNoteManager'),
)
diff --git a/tools/ee-test.py b/tools/ee-test.py
index 792c28e..77ccd2e 100755
--- a/tools/ee-test.py
+++ b/tools/ee-test.py
@@ -3,7 +3,11 @@
import gitlab
-PROJECT_NAME = 'root/project1'
+P1 = 'root/project1'
+P2 = 'root/project2'
+I_P1 = 1
+I_P2 = 1
+
def start_log(message):
print('Testing %s... ' % message, end='')
@@ -14,17 +18,20 @@ def end_log():
gl = gitlab.Gitlab.from_config('ee')
-project = gl.projects.get(PROJECT_NAME)
+project1 = gl.projects.get(P1)
+project2 = gl.projects.get(P2)
+issue_p1 = project1.issues.get(I_P1)
+issue_p2 = project2.issues.get(I_P2)
start_log('MR approvals')
-approval = project.approvals.get()
+approval = project1.approvals.get()
v = approval.reset_approvals_on_push
approval.reset_approvals_on_push = not v
approval.save()
-approval = project.approvals.get()
+approval = project1.approvals.get()
assert(v != approval.reset_approvals_on_push)
-project.approvals.set_approvers([1], [])
-approval = project.approvals.get()
+project1.approvals.set_approvers([1], [])
+approval = project1.approvals.get()
assert(approval.approvers[0]['user']['id'] == 1)
end_log()
@@ -33,3 +40,15 @@ start_log('geo nodes')
nodes = gl.geonodes.list()
status = gl.geonodes.status()
end_log()
+
+start_log('issue links')
+# bit of cleanup just in case
+for link in issue_p1.links.list():
+ issue_p1.links.delete(link.issue_link_id)
+
+src, dst = issue_p1.links.create({'target_project_id': P2,
+ 'target_issue_iid': I_P2})
+links = issue_p1.links.list()
+link_id = links[0].issue_link_id
+issue_p1.links.delete(link_id)
+end_log()