Skip to content

Commit 4461139

Browse files
author
Gauvain Pocentek
committed
Add support for the discussions API
Fixes #501
1 parent 660f0cf commit 4461139

File tree

3 files changed

+175
-2
lines changed

3 files changed

+175
-2
lines changed

docs/api-objects.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ API examples
1414
gl_objects/commits
1515
gl_objects/deploy_keys
1616
gl_objects/deployments
17+
gl_objects/discussions
1718
gl_objects/environments
1819
gl_objects/events
1920
gl_objects/features

gitlab/v4/objects.py

+119-2
Original file line numberDiff line numberDiff line change
@@ -1159,10 +1159,39 @@ class ProjectCommitCommentManager(ListMixin, CreateMixin, RESTManager):
11591159
_create_attrs = (('note', ), ('path', 'line', 'line_type'))
11601160

11611161

1162+
class ProjectCommitDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject):
1163+
pass
1164+
1165+
1166+
class ProjectCommitDiscussionNoteManager(GetMixin, CreateMixin, UpdateMixin,
1167+
DeleteMixin, RESTManager):
1168+
_path = ('/projects/%(project_id)s/repository/commits/%(commit_id)s/'
1169+
'discussions/%(discussion_id)s/notes')
1170+
_obj_cls = ProjectCommitDiscussionNote
1171+
_from_parent_attrs = {'project_id': 'project_id',
1172+
'commit_id': 'commit_id',
1173+
'discussion_id': 'id'}
1174+
_create_attrs = (('body',), ('created_at', 'position'))
1175+
_update_attrs = (('body',), tuple())
1176+
1177+
1178+
class ProjectCommitDiscussion(RESTObject):
1179+
_managers = (('notes', 'ProjectCommitDiscussionNoteManager'),)
1180+
1181+
1182+
class ProjectCommitDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
1183+
_path = ('/projects/%(project_id)s/repository/commits/%(commit_id)s/'
1184+
'discussions')
1185+
_obj_cls = ProjectCommitDiscussion
1186+
_from_parent_attrs = {'project_id': 'project_id', 'commit_id': 'id'}
1187+
_create_attrs = (('body',), ('created_at',))
1188+
1189+
11621190
class ProjectCommit(RESTObject):
11631191
_short_print_attr = 'title'
11641192
_managers = (
11651193
('comments', 'ProjectCommitCommentManager'),
1194+
('discussions', 'ProjectCommitDiscussionManager'),
11661195
('statuses', 'ProjectCommitStatusManager'),
11671196
)
11681197

@@ -1330,13 +1359,41 @@ class ProjectIssueNoteManager(CRUDMixin, RESTManager):
13301359
_update_attrs = (('body', ), tuple())
13311360

13321361

1362+
class ProjectIssueDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject):
1363+
pass
1364+
1365+
1366+
class ProjectIssueDiscussionNoteManager(GetMixin, CreateMixin, UpdateMixin,
1367+
DeleteMixin, RESTManager):
1368+
_path = ('/projects/%(project_id)s/issues/%(issue_iid)s/'
1369+
'discussions/%(discussion_id)s/notes')
1370+
_obj_cls = ProjectIssueDiscussionNote
1371+
_from_parent_attrs = {'project_id': 'project_id',
1372+
'issue_iid': 'issue_iid',
1373+
'discussion_id': 'id'}
1374+
_create_attrs = (('body',), ('created_at',))
1375+
_update_attrs = (('body',), tuple())
1376+
1377+
1378+
class ProjectIssueDiscussion(RESTObject):
1379+
_managers = (('notes', 'ProjectIssueDiscussionNoteManager'),)
1380+
1381+
1382+
class ProjectIssueDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
1383+
_path = '/projects/%(project_id)s/issues/%(issue_iid)s/discussions'
1384+
_obj_cls = ProjectIssueDiscussion
1385+
_from_parent_attrs = {'project_id': 'project_id', 'issue_iid': 'iid'}
1386+
_create_attrs = (('body',), ('created_at',))
1387+
1388+
13331389
class ProjectIssue(SubscribableMixin, TodoMixin, TimeTrackingMixin, SaveMixin,
13341390
ObjectDeleteMixin, RESTObject):
13351391
_short_print_attr = 'title'
13361392
_id_attr = 'iid'
13371393
_managers = (
1338-
('notes', 'ProjectIssueNoteManager'),
13391394
('awardemojis', 'ProjectIssueAwardEmojiManager'),
1395+
('discussions', 'ProjectIssueDiscussionManager'),
1396+
('notes', 'ProjectIssueNoteManager'),
13401397
)
13411398

13421399
@cli.register_custom_action('ProjectIssue')
@@ -1510,7 +1567,7 @@ class ProjectMergeRequestNoteAwardEmojiManager(NoUpdateMixin, RESTManager):
15101567
'/notes/%(note_id)s/award_emoji')
15111568
_obj_cls = ProjectMergeRequestNoteAwardEmoji
15121569
_from_parent_attrs = {'project_id': 'project_id',
1513-
'mr_iid': 'issue_iid',
1570+
'mr_iid': 'mr_iid',
15141571
'note_id': 'id'}
15151572
_create_attrs = (('name', ), tuple())
15161573

@@ -1527,13 +1584,45 @@ class ProjectMergeRequestNoteManager(CRUDMixin, RESTManager):
15271584
_update_attrs = (('body', ), tuple())
15281585

15291586

1587+
class ProjectMergeRequestDiscussionNote(SaveMixin, ObjectDeleteMixin,
1588+
RESTObject):
1589+
pass
1590+
1591+
1592+
class ProjectMergeRequestDiscussionNoteManager(GetMixin, CreateMixin,
1593+
UpdateMixin, DeleteMixin,
1594+
RESTManager):
1595+
_path = ('/projects/%(project_id)s/merge_requests/%(mr_iid)s/'
1596+
'discussions/%(discussion_id)s/notes')
1597+
_obj_cls = ProjectMergeRequestDiscussionNote
1598+
_from_parent_attrs = {'project_id': 'project_id',
1599+
'mr_iid': 'mr_iid',
1600+
'discussion_id': 'id'}
1601+
_create_attrs = (('body',), ('created_at',))
1602+
_update_attrs = (('body',), tuple())
1603+
1604+
1605+
class ProjectMergeRequestDiscussion(SaveMixin, RESTObject):
1606+
_managers = (('notes', 'ProjectMergeRequestDiscussionNoteManager'),)
1607+
1608+
1609+
class ProjectMergeRequestDiscussionManager(RetrieveMixin, CreateMixin,
1610+
UpdateMixin, RESTManager):
1611+
_path = '/projects/%(project_id)s/merge_requests/%(mr_iid)s/discussions'
1612+
_obj_cls = ProjectMergeRequestDiscussion
1613+
_from_parent_attrs = {'project_id': 'project_id', 'mr_iid': 'iid'}
1614+
_create_attrs = (('body',), ('created_at', 'position'))
1615+
_update_attrs = (('resolved',), tuple())
1616+
1617+
15301618
class ProjectMergeRequest(SubscribableMixin, TodoMixin, TimeTrackingMixin,
15311619
SaveMixin, ObjectDeleteMixin, RESTObject):
15321620
_id_attr = 'iid'
15331621

15341622
_managers = (
15351623
('awardemojis', 'ProjectMergeRequestAwardEmojiManager'),
15361624
('diffs', 'ProjectMergeRequestDiffManager'),
1625+
('discussions', 'ProjectMergeRequestDiscussionManager'),
15371626
('notes', 'ProjectMergeRequestNoteManager'),
15381627
)
15391628

@@ -2175,11 +2264,39 @@ class ProjectSnippetAwardEmojiManager(NoUpdateMixin, RESTManager):
21752264
_create_attrs = (('name', ), tuple())
21762265

21772266

2267+
class ProjectSnippetDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject):
2268+
pass
2269+
2270+
2271+
class ProjectSnippetDiscussionNoteManager(GetMixin, CreateMixin, UpdateMixin,
2272+
DeleteMixin, RESTManager):
2273+
_path = ('/projects/%(project_id)s/snippets/%(snippet_id)s/'
2274+
'discussions/%(discussion_id)s/notes')
2275+
_obj_cls = ProjectSnippetDiscussionNote
2276+
_from_parent_attrs = {'project_id': 'project_id',
2277+
'snippet_id': 'snippet_id',
2278+
'discussion_id': 'id'}
2279+
_create_attrs = (('body',), ('created_at',))
2280+
_update_attrs = (('body',), tuple())
2281+
2282+
2283+
class ProjectSnippetDiscussion(RESTObject):
2284+
_managers = (('notes', 'ProjectSnippetDiscussionNoteManager'),)
2285+
2286+
2287+
class ProjectSnippetDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
2288+
_path = '/projects/%(project_id)s/snippets/%(snippet_id)s/discussions'
2289+
_obj_cls = ProjectSnippetDiscussion
2290+
_from_parent_attrs = {'project_id': 'project_id', 'snippet_id': 'id'}
2291+
_create_attrs = (('body',), ('created_at',))
2292+
2293+
21782294
class ProjectSnippet(SaveMixin, ObjectDeleteMixin, RESTObject):
21792295
_url = '/projects/%(project_id)s/snippets'
21802296
_short_print_attr = 'title'
21812297
_managers = (
21822298
('awardemojis', 'ProjectSnippetAwardEmojiManager'),
2299+
('discussions', 'ProjectSnippetDiscussionManager'),
21832300
('notes', 'ProjectSnippetNoteManager'),
21842301
)
21852302

tools/python_test_v4.py

+55
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,20 @@
379379
commit.comments.create({'note': 'This is a commit comment'})
380380
assert(len(commit.comments.list()) == 1)
381381

382+
# commit discussion
383+
count = len(commit.discussions.list())
384+
discussion = commit.discussions.create({'body': 'Discussion body'})
385+
assert(len(commit.discussions.list()) == (count + 1))
386+
d_note = discussion.notes.create({'body': 'first note'})
387+
d_note_from_get = discussion.notes.get(d_note.id)
388+
d_note_from_get.body = 'updated body'
389+
d_note_from_get.save()
390+
discussion = commit.discussions.get(discussion.id)
391+
assert(discussion.attributes['notes'][-1]['body'] == 'updated body')
392+
d_note_from_get.delete()
393+
discussion = commit.discussions.get(discussion.id)
394+
assert(len(discussion.attributes['notes']) == 1)
395+
382396
# housekeeping
383397
admin_project.housekeeping()
384398

@@ -492,6 +506,18 @@
492506
assert(len(issue1.notes.list()) == 0)
493507
assert(isinstance(issue1.user_agent_detail(), dict))
494508

509+
discussion = issue1.discussions.create({'body': 'Discussion body'})
510+
assert(len(issue1.discussions.list()) == 1)
511+
d_note = discussion.notes.create({'body': 'first note'})
512+
d_note_from_get = discussion.notes.get(d_note.id)
513+
d_note_from_get.body = 'updated body'
514+
d_note_from_get.save()
515+
discussion = issue1.discussions.get(discussion.id)
516+
assert(discussion.attributes['notes'][-1]['body'] == 'updated body')
517+
d_note_from_get.delete()
518+
discussion = issue1.discussions.get(discussion.id)
519+
assert(len(discussion.attributes['notes']) == 1)
520+
495521
# tags
496522
tag1 = admin_project.tags.create({'tag_name': 'v1.0', 'ref': 'master'})
497523
assert(len(admin_project.tags.list()) == 1)
@@ -507,6 +533,19 @@
507533
{'title': 'snip1', 'file_name': 'foo.py', 'code': 'initial content',
508534
'visibility': gitlab.v4.objects.VISIBILITY_PRIVATE}
509535
)
536+
537+
discussion = snippet.discussions.create({'body': 'Discussion body'})
538+
assert(len(snippet.discussions.list()) == 1)
539+
d_note = discussion.notes.create({'body': 'first note'})
540+
d_note_from_get = discussion.notes.get(d_note.id)
541+
d_note_from_get.body = 'updated body'
542+
d_note_from_get.save()
543+
discussion = snippet.discussions.get(discussion.id)
544+
assert(discussion.attributes['notes'][-1]['body'] == 'updated body')
545+
d_note_from_get.delete()
546+
discussion = snippet.discussions.get(discussion.id)
547+
assert(len(discussion.attributes['notes']) == 1)
548+
510549
snippet.file_name = 'bar.py'
511550
snippet.save()
512551
snippet = admin_project.snippets.get(snippet.id)
@@ -541,6 +580,19 @@
541580
'target_branch': 'master',
542581
'title': 'MR readme2'})
543582

583+
# discussion
584+
discussion = mr.discussions.create({'body': 'Discussion body'})
585+
assert(len(mr.discussions.list()) == 1)
586+
d_note = discussion.notes.create({'body': 'first note'})
587+
d_note_from_get = discussion.notes.get(d_note.id)
588+
d_note_from_get.body = 'updated body'
589+
d_note_from_get.save()
590+
discussion = mr.discussions.get(discussion.id)
591+
assert(discussion.attributes['notes'][-1]['body'] == 'updated body')
592+
d_note_from_get.delete()
593+
discussion = mr.discussions.get(discussion.id)
594+
assert(len(discussion.attributes['notes']) == 1)
595+
544596
# basic testing: only make sure that the methods exist
545597
mr.commits()
546598
mr.changes()
@@ -646,7 +698,10 @@
646698
assert(snippet.title == 'updated_title')
647699
content = snippet.content()
648700
assert(content == 'import gitlab')
701+
649702
snippet.delete()
703+
snippets = gl.snippets.list(all=True)
704+
assert(len(snippets) == 0)
650705

651706
# user activities
652707
gl.user_activities.list()

0 commit comments

Comments
 (0)