gitlab: Add access token name, Update docs, Fix webhook
Highlight that Access Token: - can be created at project level and user level - can be used to authenticate when cloning repositories To clone internal or private projects, authentication is required. It can be achieved using the Access Token. Currently, any names can be used but [1] shows that it's likely going to be restricted to username and token-name. As token-name is directly related to an Access Token, use this value. webhook can be created foreach project but also at group level, so at the topmost group. Therefor only one webhook at the upper group can be used to send events to Zuul: remove "project" from webhook_token description [1] https://gitlab.com/gitlab-org/gitlab/-/issues/212953 Change-Id: I57adb5e03658d31bd3900d2d9037101cf491466e
This commit is contained in:
parent
dddbb3dbfe
commit
c4d120551a
|
@ -17,20 +17,35 @@ Zuul needs to interact with projects by:
|
||||||
- receiving events via web-hooks
|
- receiving events via web-hooks
|
||||||
- performing actions via the API
|
- performing actions via the API
|
||||||
|
|
||||||
The Zuul user's API token configured in zuul.conf must have the
|
web-hooks
|
||||||
following ACL rights: "api". The API token must be created in user Settings,
|
^^^^^^^^^
|
||||||
Access tokens.
|
|
||||||
|
|
||||||
Each project to be integrated with Zuul needs in "Settings/Webhooks":
|
Projects to be integrated with Zuul needs to send events using webhooks.
|
||||||
|
This can be enabled at Group level or Project level in "Settings/Webhooks"
|
||||||
|
|
||||||
- "URL" set to
|
- "URL" set to
|
||||||
``http://<zuul-web>/zuul/api/connection/<conn-name>/payload``
|
``http://<zuul-web>/api/connection/<conn-name>/payload``
|
||||||
- "Merge request events" set to "on"
|
- "Merge request events" set to "on"
|
||||||
- "Push events" set to "on"
|
- "Push events" set to "on"
|
||||||
- "Tag push events" set to "on"
|
- "Tag push events" set to "on"
|
||||||
- "Comments" set to "on"
|
- "Comments" set to "on"
|
||||||
- Define a "Secret Token"
|
- Define a "Secret Token"
|
||||||
|
|
||||||
|
|
||||||
|
API
|
||||||
|
^^^
|
||||||
|
|
||||||
|
| Even though bot users exist: https://docs.gitlab.com/ce/user/project/settings/project_access_tokens.html#project-bot-users
|
||||||
|
| They are only available at project level.
|
||||||
|
|
||||||
|
In order to manage multiple projects using a single connection, Zuul needs a
|
||||||
|
global access to projects, which can only be achieved by creating a specific
|
||||||
|
Zuul user. This user counts as a licensed seat.
|
||||||
|
|
||||||
|
The API token must be created in user Settings, Access tokens. The Zuul user's
|
||||||
|
API token configured in zuul.conf must have the following ACL rights: "api".
|
||||||
|
|
||||||
|
|
||||||
Connection Configuration
|
Connection Configuration
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -45,13 +60,18 @@ The supported options in ``zuul.conf`` connections are:
|
||||||
|
|
||||||
The connection must set ``driver=gitlab`` for GitLab connections.
|
The connection must set ``driver=gitlab`` for GitLab connections.
|
||||||
|
|
||||||
|
.. attr:: api_token_name
|
||||||
|
|
||||||
|
The user's personal access token name (Used if **cloneurl** is http(s))
|
||||||
|
Set this parameter if authentication to clone projects is required
|
||||||
|
|
||||||
.. attr:: api_token
|
.. attr:: api_token
|
||||||
|
|
||||||
The user's API token.
|
The user's personal access token
|
||||||
|
|
||||||
.. attr:: webhook_token
|
.. attr:: webhook_token
|
||||||
|
|
||||||
The project's webhook secret token.
|
The webhook secret token.
|
||||||
|
|
||||||
.. attr:: server
|
.. attr:: server
|
||||||
:default: gitlab.com
|
:default: gitlab.com
|
||||||
|
@ -75,10 +95,19 @@ The supported options in ``zuul.conf`` connections are:
|
||||||
|
|
||||||
Path to the GitLab web and API interface.
|
Path to the GitLab web and API interface.
|
||||||
|
|
||||||
|
.. attr:: sshkey
|
||||||
|
|
||||||
|
Path to SSH key to use (Used if **cloneurl** is ssh)
|
||||||
|
|
||||||
.. attr:: cloneurl
|
.. attr:: cloneurl
|
||||||
:default: {baseurl}
|
:default: {baseurl}
|
||||||
|
|
||||||
Path to the GitLab Git repositories. Used to clone.
|
Omit to clone using http(s) or set to ``ssh://git@{server}``.
|
||||||
|
If **api_token_name** is set and **cloneurl** is either omitted or is
|
||||||
|
set without credentials, **cloneurl** will be modified to use credentials
|
||||||
|
as this: ``http(s)://<api_token_name>:<api_token>@<server>``.
|
||||||
|
If **cloneurl** is defined with credentials, it will be used as is,
|
||||||
|
without modification from the driver.
|
||||||
|
|
||||||
|
|
||||||
Trigger Configuration
|
Trigger Configuration
|
||||||
|
|
|
@ -1817,6 +1817,9 @@ class FakeGitlabConnection(gitlabconnection.GitlabConnection):
|
||||||
def getGitUrl(self, project):
|
def getGitUrl(self, project):
|
||||||
return 'file://' + os.path.join(self.upstream_root, project.name)
|
return 'file://' + os.path.join(self.upstream_root, project.name)
|
||||||
|
|
||||||
|
def real_getGitUrl(self, project):
|
||||||
|
return super(FakeGitlabConnection, self).getGitUrl(project)
|
||||||
|
|
||||||
def openFakeMergeRequest(self, project,
|
def openFakeMergeRequest(self, project,
|
||||||
branch, title, description='', files=[]):
|
branch, title, description='', files=[]):
|
||||||
self.mr_number += 1
|
self.mr_number += 1
|
||||||
|
|
|
@ -20,3 +20,28 @@ api_token=0000000000000000000000000000000000000000
|
||||||
[database]
|
[database]
|
||||||
dburi=$MYSQL_FIXTURE_DBURI$
|
dburi=$MYSQL_FIXTURE_DBURI$
|
||||||
|
|
||||||
|
[connection gitlab2]
|
||||||
|
driver=gitlab
|
||||||
|
server=gitlabtwo
|
||||||
|
api_token=2222
|
||||||
|
cloneurl=http://myusername:2222@gitlab
|
||||||
|
|
||||||
|
[connection gitlab3]
|
||||||
|
driver=gitlab
|
||||||
|
server=gitlabthree
|
||||||
|
api_token_name=tokenname3
|
||||||
|
api_token=3333
|
||||||
|
cloneurl=http://myusername:2222@gitlabthree
|
||||||
|
|
||||||
|
[connection gitlab4]
|
||||||
|
driver=gitlab
|
||||||
|
server=gitlabfour
|
||||||
|
api_token_name=tokenname4
|
||||||
|
api_token=444
|
||||||
|
|
||||||
|
[connection gitlab5]
|
||||||
|
driver=gitlab
|
||||||
|
server=gitlabfive
|
||||||
|
api_token_name=tokenname5
|
||||||
|
api_token=555
|
||||||
|
cloneurl=http://gitlabfivvve
|
||||||
|
|
|
@ -699,6 +699,61 @@ class TestGitlabDriver(ZuulTestCase):
|
||||||
self.assertTrue(A.is_merged)
|
self.assertTrue(A.is_merged)
|
||||||
self.assertTrue(B.is_merged)
|
self.assertTrue(B.is_merged)
|
||||||
|
|
||||||
|
@simple_layout('layouts/crd-gitlab.yaml', driver='gitlab')
|
||||||
|
def test_api_token(self):
|
||||||
|
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||||
|
_, project = tenant.getProject('org/project1')
|
||||||
|
|
||||||
|
project_git_url = self.fake_gitlab.real_getGitUrl(project)
|
||||||
|
# cloneurl created from config 'server' should be used
|
||||||
|
# without credentials
|
||||||
|
self.assertEqual("https://gitlab/org/project1.git", project_git_url)
|
||||||
|
|
||||||
|
@simple_layout('layouts/crd-gitlab.yaml', driver='gitlab2')
|
||||||
|
def test_api_token_cloneurl(self):
|
||||||
|
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||||
|
_, project = tenant.getProject('org/project1')
|
||||||
|
|
||||||
|
project_git_url = self.fake_gitlab2.real_getGitUrl(project)
|
||||||
|
# cloneurl from config file should be used as it defines token name and
|
||||||
|
# secret
|
||||||
|
self.assertEqual("http://myusername:2222@gitlab/org/project1.git",
|
||||||
|
project_git_url)
|
||||||
|
|
||||||
|
@simple_layout('layouts/crd-gitlab.yaml', driver='gitlab3')
|
||||||
|
def test_api_token_name_cloneurl(self):
|
||||||
|
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||||
|
_, project = tenant.getProject('org/project1')
|
||||||
|
|
||||||
|
project_git_url = self.fake_gitlab3.real_getGitUrl(project)
|
||||||
|
# cloneurl from config file should be used as it defines token name and
|
||||||
|
# secret, even if token name and token secret are defined
|
||||||
|
self.assertEqual("http://myusername:2222@gitlabthree/org/project1.git",
|
||||||
|
project_git_url)
|
||||||
|
|
||||||
|
@simple_layout('layouts/crd-gitlab.yaml', driver='gitlab4')
|
||||||
|
def test_api_token_name(self):
|
||||||
|
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||||
|
_, project = tenant.getProject('org/project1')
|
||||||
|
|
||||||
|
project_git_url = self.fake_gitlab4.real_getGitUrl(project)
|
||||||
|
# cloneurl is not set, generate one from token name, token secret and
|
||||||
|
# server
|
||||||
|
self.assertEqual("https://tokenname4:444@gitlabfour/org/project1.git",
|
||||||
|
project_git_url)
|
||||||
|
|
||||||
|
@simple_layout('layouts/crd-gitlab.yaml', driver='gitlab5')
|
||||||
|
def test_api_token_name_cloneurl_server(self):
|
||||||
|
tenant = self.scheds.first.sched.abide.tenants.get('tenant-one')
|
||||||
|
_, project = tenant.getProject('org/project1')
|
||||||
|
|
||||||
|
project_git_url = self.fake_gitlab5.real_getGitUrl(project)
|
||||||
|
# cloneurl defines a url, without credentials. As token name is
|
||||||
|
# set, include token name and secret in cloneurl, 'server' is
|
||||||
|
# overwritten
|
||||||
|
self.assertEqual("http://tokenname5:555@gitlabfivvve/org/project1.git",
|
||||||
|
project_git_url)
|
||||||
|
|
||||||
|
|
||||||
class TestGitlabUnprotectedBranches(ZuulTestCase):
|
class TestGitlabUnprotectedBranches(ZuulTestCase):
|
||||||
config_file = 'zuul-gitlab-driver.conf'
|
config_file = 'zuul-gitlab-driver.conf'
|
||||||
|
|
|
@ -20,6 +20,7 @@ import cherrypy
|
||||||
import voluptuous as v
|
import voluptuous as v
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
|
@ -410,6 +411,8 @@ class GitlabConnection(CachedBranchConnection):
|
||||||
'canonical_hostname', self.server)
|
'canonical_hostname', self.server)
|
||||||
self.webhook_token = self.connection_config.get(
|
self.webhook_token = self.connection_config.get(
|
||||||
'webhook_token', '')
|
'webhook_token', '')
|
||||||
|
self.api_token_name = self.connection_config.get(
|
||||||
|
'api_token_name', '')
|
||||||
self.api_token = self.connection_config.get(
|
self.api_token = self.connection_config.get(
|
||||||
'api_token', '')
|
'api_token', '')
|
||||||
self.gl_client = GitlabAPIClient(self.baseurl, self.api_token)
|
self.gl_client = GitlabAPIClient(self.baseurl, self.api_token)
|
||||||
|
@ -479,7 +482,19 @@ class GitlabConnection(CachedBranchConnection):
|
||||||
return '%s/%s/merge_requests/%s' % (self.baseurl, project, number)
|
return '%s/%s/merge_requests/%s' % (self.baseurl, project, number)
|
||||||
|
|
||||||
def getGitUrl(self, project):
|
def getGitUrl(self, project):
|
||||||
return '%s/%s.git' % (self.cloneurl, project.name)
|
cloneurl = '%s/%s.git' % (self.cloneurl, project.name)
|
||||||
|
# https://gitlab.com/gitlab-org/gitlab/-/issues/212953
|
||||||
|
# any login name can be used, but it's likely going to be reduce to
|
||||||
|
# username/token-name
|
||||||
|
if (cloneurl.startswith('http') and self.api_token_name != '' and
|
||||||
|
not re.match("http?://.+:.+@.+", cloneurl)):
|
||||||
|
cloneurl = '%s://%s:%s@%s/%s.git' % (
|
||||||
|
self.cloneurl.split('://')[0],
|
||||||
|
self.api_token_name,
|
||||||
|
self.api_token,
|
||||||
|
self.cloneurl.split('://')[1],
|
||||||
|
project.name)
|
||||||
|
return cloneurl
|
||||||
|
|
||||||
def getChange(self, event, refresh=False):
|
def getChange(self, event, refresh=False):
|
||||||
project = self.source.getProject(event.project_name)
|
project = self.source.getProject(event.project_name)
|
||||||
|
|
Loading…
Reference in New Issue