Skip to content

Commit 3ccf7c3

Browse files
authored
Merge pull request #6066 from saadmk11/gitlab-integration
PR Builder GitLab Integration
2 parents 4d8828e + 4c89847 commit 3ccf7c3

File tree

9 files changed

+481
-14
lines changed

9 files changed

+481
-14
lines changed

readthedocs/api/v2/views/integrations.py

+54-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
GITHUB_PULL_REQUEST_SYNC = 'synchronize'
4343
GITHUB_CREATE = 'create'
4444
GITHUB_DELETE = 'delete'
45+
GITLAB_MERGE_REQUEST = 'merge_request'
46+
GITLAB_MERGE_REQUEST_CLOSE = 'close'
47+
GITLAB_MERGE_REQUEST_MERGE = 'merge'
48+
GITLAB_MERGE_REQUEST_OPEN = 'open'
49+
GITLAB_MERGE_REQUEST_REOPEN = 'reopen'
50+
GITLAB_MERGE_REQUEST_UPDATE = 'update'
4551
GITLAB_TOKEN_HEADER = 'HTTP_X_GITLAB_TOKEN'
4652
GITLAB_PUSH = 'push'
4753
GITLAB_NULL_HASH = '0' * 40
@@ -401,7 +407,7 @@ class GitLabWebhookView(WebhookMixin, APIView):
401407
"""
402408
Webhook consumer for GitLab.
403409
404-
Accepts webhook events from GitLab, 'push' events trigger builds.
410+
Accepts webhook events from GitLab, 'push' and 'merge_request' events trigger builds.
405411
406412
Expects the following JSON::
407413
@@ -413,10 +419,26 @@ class GitLabWebhookView(WebhookMixin, APIView):
413419
...
414420
}
415421
422+
For merge_request events:
423+
424+
{
425+
"object_kind": "merge_request",
426+
"object_attributes": {
427+
"iid": 2,
428+
"last_commit": {
429+
"id": "717abb9a6a0f3111dbd601ef6f58c70bdd165aef",
430+
},
431+
"action": "open"
432+
...
433+
},
434+
...
435+
}
436+
416437
See full payload here:
417438
418439
- https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#push-events
419440
- https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#tag-events
441+
- https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#merge-request-events
420442
"""
421443

422444
integration_type = Integration.GITLAB_WEBHOOK
@@ -441,6 +463,17 @@ def is_payload_valid(self):
441463
return False
442464
return token == secret
443465

466+
def get_external_version_data(self):
467+
"""Get commit SHA and merge request number from payload."""
468+
try:
469+
identifier = self.data['object_attributes']['last_commit']['id']
470+
verbose_name = str(self.data['object_attributes']['iid'])
471+
472+
return identifier, verbose_name
473+
474+
except KeyError:
475+
raise ParseError('Parameters "id" and "iid" are required')
476+
444477
def handle_webhook(self):
445478
"""
446479
Handle GitLab events for push and tag_push.
@@ -450,6 +483,7 @@ def handle_webhook(self):
450483
0000000000000000000000000000000000000000 ('0' * 40)
451484
"""
452485
event = self.request.data.get('object_kind', GITLAB_PUSH)
486+
action = self.data.get('object_attributes', {}).get('action', None)
453487
webhook_gitlab.send(
454488
Project,
455489
project=self.project,
@@ -470,6 +504,25 @@ def handle_webhook(self):
470504
return self.get_response_push(self.project, branches)
471505
except KeyError:
472506
raise ParseError('Parameter "ref" is required')
507+
508+
if (
509+
self.project.has_feature(Feature.EXTERNAL_VERSION_BUILD) and
510+
event == GITLAB_MERGE_REQUEST and action
511+
):
512+
if (
513+
action in
514+
[
515+
GITLAB_MERGE_REQUEST_OPEN,
516+
GITLAB_MERGE_REQUEST_REOPEN,
517+
GITLAB_MERGE_REQUEST_UPDATE
518+
]
519+
):
520+
# Handle open, update, reopen merge_request event.
521+
return self.get_external_version_response(self.project)
522+
523+
if action in [GITLAB_MERGE_REQUEST_CLOSE, GITLAB_MERGE_REQUEST_MERGE]:
524+
# Handle merge and close merge_request event.
525+
return self.get_delete_external_version_response(self.project)
473526
return None
474527

475528
def _normalize_ref(self, ref):

readthedocs/builds/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,5 @@
9191
RTD_BUILD_STATUS_API_NAME = 'continuous-documentation/read-the-docs'
9292

9393
GITHUB_EXTERNAL_VERSION_NAME = 'Pull Request'
94+
GITLAB_EXTERNAL_VERSION_NAME = 'Merge Request'
9495
GENERIC_EXTERNAL_VERSION_NAME = 'External Version'

readthedocs/builds/models.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727
GITHUB_URL,
2828
GITHUB_PULL_REQUEST_URL,
2929
GITHUB_PULL_REQUEST_COMMIT_URL,
30+
GITLAB_BRAND,
3031
GITLAB_COMMIT_URL,
32+
GITLAB_MERGE_REQUEST_URL,
33+
GITLAB_MERGE_REQUEST_COMMIT_URL,
3134
GITLAB_URL,
3235
PRIVACY_CHOICES,
3336
PRIVATE,
@@ -44,6 +47,7 @@
4447
BUILD_TYPES,
4548
GENERIC_EXTERNAL_VERSION_NAME,
4649
GITHUB_EXTERNAL_VERSION_NAME,
50+
GITLAB_EXTERNAL_VERSION_NAME,
4751
INTERNAL,
4852
LATEST,
4953
NON_REPOSITORY_VERSIONS,
@@ -178,7 +182,14 @@ def vcs_url(self):
178182
repo=repo,
179183
number=self.verbose_name,
180184
)
181-
# TODO: Add VCS URL for other Git Providers
185+
if 'gitlab' in self.project.repo:
186+
user, repo = get_gitlab_username_repo(self.project.repo)
187+
return GITLAB_MERGE_REQUEST_URL.format(
188+
user=user,
189+
repo=repo,
190+
number=self.verbose_name,
191+
)
192+
# TODO: Add VCS URL for BitBucket.
182193
return ''
183194

184195
url = ''
@@ -787,7 +798,19 @@ def get_commit_url(self):
787798
number=self.version.verbose_name,
788799
commit=self.commit
789800
)
790-
# TODO: Add External Version Commit URL for other Git Providers
801+
if 'gitlab' in repo_url:
802+
user, repo = get_gitlab_username_repo(repo_url)
803+
if not user and not repo:
804+
return ''
805+
806+
repo = repo.rstrip('/')
807+
return GITLAB_MERGE_REQUEST_COMMIT_URL.format(
808+
user=user,
809+
repo=repo,
810+
number=self.version.verbose_name,
811+
commit=self.commit
812+
)
813+
# TODO: Add External Version Commit URL for BitBucket.
791814
else:
792815
if 'github' in repo_url:
793816
user, repo = get_github_username_repo(repo_url)
@@ -845,8 +868,11 @@ def external_version_name(self):
845868
if self.is_external:
846869
if self.project.git_provider_name == GITHUB_BRAND:
847870
return GITHUB_EXTERNAL_VERSION_NAME
848-
# TODO: Add External Version Name for other Git Providers
849871

872+
if self.project.git_provider_name == GITLAB_BRAND:
873+
return GITLAB_EXTERNAL_VERSION_NAME
874+
875+
# TODO: Add External Version Name for BitBucket.
850876
return GENERIC_EXTERNAL_VERSION_NAME
851877
return None
852878

readthedocs/projects/constants.py

+11
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,19 @@
353353
'https://gitlab.com/{user}/{repo}/'
354354
'commit/{commit}'
355355
)
356+
GITLAB_MERGE_REQUEST_COMMIT_URL = (
357+
'https://gitlab.com/{user}/{repo}/'
358+
'commit/{commit}?merge_request_iid={number}'
359+
)
360+
GITLAB_MERGE_REQUEST_URL = (
361+
'https://gitlab.com/{user}/{repo}/'
362+
'merge_requests/{number}'
363+
)
356364

365+
# Patterns to pull merge/pull request from providers
357366
GITHUB_PR_PULL_PATTERN = 'pull/{id}/head:external-{id}'
367+
GITLAB_MR_PULL_PATTERN = 'merge-requests/{id}/head:external-{id}'
358368

359369
# Git provider names
360370
GITHUB_BRAND = 'GitHub'
371+
GITLAB_BRAND = 'GitLab'

0 commit comments

Comments
 (0)