Merge "Add multi-branch support for project-templates" into feature/zuulv3
diff --git a/doc/source/admin/drivers/gerrit.rst b/doc/source/admin/drivers/gerrit.rst
index ac42bd3..935cb32 100644
--- a/doc/source/admin/drivers/gerrit.rst
+++ b/doc/source/admin/drivers/gerrit.rst
@@ -61,6 +61,17 @@
Path to Gerrit web interface.
+ .. attr:: gitweb_url_template
+ :default: {baseurl}/gitweb?p={project.name}.git;a=commitdiff;h={sha}
+
+ Url template for links to specific git shas. By default this will
+ point at Gerrit's built in gitweb but you can customize this value
+ to point elsewhere (like cgit or github).
+
+ The three values available for string interpolation are baseurl
+ which points back to Gerrit, project and all of its safe attributes,
+ and sha which is the git sha1.
+
.. attr:: user
:default: zuul
diff --git a/tests/fixtures/zuul-connections-cgit.conf b/tests/fixtures/zuul-connections-cgit.conf
new file mode 100644
index 0000000..39dc0bb
--- /dev/null
+++ b/tests/fixtures/zuul-connections-cgit.conf
@@ -0,0 +1,27 @@
+[gearman]
+server=127.0.0.1
+
+[scheduler]
+tenant_config=main.yaml
+
+[merger]
+git_dir=/tmp/zuul-test/merger-git
+git_user_email=zuul@example.com
+git_user_name=zuul
+
+[executor]
+git_dir=/tmp/zuul-test/executor-git
+
+[connection gerrit]
+driver=gerrit
+server=review.example.com
+user=jenkins
+sshkey=none
+gitweb_url_template=https://cgit.example.com/cgit/{project.name}/commit/?id={sha}
+
+[connection outgoing_smtp]
+driver=smtp
+server=localhost
+port=25
+default_from=zuul@example.com
+default_to=you@example.com
diff --git a/tests/fixtures/zuul-connections-gitweb.conf b/tests/fixtures/zuul-connections-gitweb.conf
new file mode 100644
index 0000000..172208e
--- /dev/null
+++ b/tests/fixtures/zuul-connections-gitweb.conf
@@ -0,0 +1,26 @@
+[gearman]
+server=127.0.0.1
+
+[scheduler]
+tenant_config=main.yaml
+
+[merger]
+git_dir=/tmp/zuul-test/merger-git
+git_user_email=zuul@example.com
+git_user_name=zuul
+
+[executor]
+git_dir=/tmp/zuul-test/executor-git
+
+[connection gerrit]
+driver=gerrit
+server=review.example.com
+user=jenkins
+sshkey=none
+
+[connection outgoing_smtp]
+driver=smtp
+server=localhost
+port=25
+default_from=zuul@example.com
+default_to=you@example.com
diff --git a/tests/unit/test_connection.py b/tests/unit/test_connection.py
index 719f307..c882d3a 100644
--- a/tests/unit/test_connection.py
+++ b/tests/unit/test_connection.py
@@ -338,3 +338,32 @@
self.assertNotIn("sql", self.connections.connections)
self.assertNotIn("timer", self.connections.connections)
self.assertNotIn("zuul", self.connections.connections)
+
+
+class TestConnectionsCgit(ZuulTestCase):
+ config_file = 'zuul-connections-cgit.conf'
+ tenant_config_file = 'config/single-tenant/main.yaml'
+
+ def test_cgit_web_url(self):
+ self.assertIn("gerrit", self.connections.connections)
+ conn = self.connections.connections['gerrit']
+ source = conn.source
+ proj = source.getProject('foo/bar')
+ url = conn._getWebUrl(proj, '1')
+ self.assertEqual(url,
+ 'https://cgit.example.com/cgit/foo/bar/commit/?id=1')
+
+
+class TestConnectionsGitweb(ZuulTestCase):
+ config_file = 'zuul-connections-gitweb.conf'
+ tenant_config_file = 'config/single-tenant/main.yaml'
+
+ def test_gitweb_url(self):
+ self.assertIn("gerrit", self.connections.connections)
+ conn = self.connections.connections['gerrit']
+ source = conn.source
+ proj = source.getProject('foo/bar')
+ url = conn._getWebUrl(proj, '1')
+ url_should_be = 'https://review.example.com/' \
+ 'gitweb?p=foo/bar.git;a=commitdiff;h=1'
+ self.assertEqual(url, url_should_be)
diff --git a/zuul/driver/gerrit/gerritconnection.py b/zuul/driver/gerrit/gerritconnection.py
index c3f9ee2..59051bb 100644
--- a/zuul/driver/gerrit/gerritconnection.py
+++ b/zuul/driver/gerrit/gerritconnection.py
@@ -299,6 +299,12 @@
self.baseurl = self.connection_config.get('baseurl',
'https://%s' % self.server)
+ default_gitweb_url_template = '{baseurl}/gitweb?' \
+ 'p={project.name}.git;' \
+ 'a=commitdiff;h={sha}'
+ url_template = self.connection_config.get('gitweb_url_template',
+ default_gitweb_url_template)
+ self.gitweb_url_template = url_template
self._change_cache = {}
self.projects = {}
@@ -338,7 +344,7 @@
change.ref = event.ref
change.oldrev = event.oldrev
change.newrev = event.newrev
- change.url = self._getGitwebUrl(project, sha=event.newrev)
+ change.url = self._getWebUrl(project, sha=event.newrev)
elif event.ref and not event.ref.startswith('refs/'):
# Pre 2.13 Gerrit ref-updated events don't have branch prefixes.
project = self.source.getProject(event.project_name)
@@ -347,7 +353,7 @@
change.ref = 'refs/heads/' + event.ref
change.oldrev = event.oldrev
change.newrev = event.newrev
- change.url = self._getGitwebUrl(project, sha=event.newrev)
+ change.url = self._getWebUrl(project, sha=event.newrev)
elif event.ref and event.ref.startswith('refs/heads/'):
# From the timer trigger or Post 2.13 Gerrit
project = self.source.getProject(event.project_name)
@@ -356,7 +362,7 @@
change.branch = event.ref[len('refs/heads/'):]
change.oldrev = event.oldrev
change.newrev = event.newrev
- change.url = self._getGitwebUrl(project, sha=event.newrev)
+ change.url = self._getWebUrl(project, sha=event.newrev)
elif event.ref:
# catch-all ref (ie, not a branch or head)
project = self.source.getProject(event.project_name)
@@ -364,7 +370,7 @@
change.ref = event.ref
change.oldrev = event.oldrev
change.newrev = event.newrev
- change.url = self._getGitwebUrl(project, sha=event.newrev)
+ change.url = self._getWebUrl(project, sha=event.newrev)
else:
self.log.warning("Unable to get change for %s" % (event,))
change = None
@@ -848,11 +854,11 @@
project.name)
return url
- def _getGitwebUrl(self, project: Project, sha: str=None) -> str:
- url = '%s/gitweb?p=%s.git' % (self.baseurl, project.name)
- if sha:
- url += ';a=commitdiff;h=' + sha
- return url
+ def _getWebUrl(self, project: Project, sha: str=None) -> str:
+ return self.gitweb_url_template.format(
+ baseurl=self.baseurl,
+ project=project.getSafeAttributes(),
+ sha=sha)
def onLoad(self):
self.log.debug("Starting Gerrit Connection/Watchers")
diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py
index 55d3031..1186aca 100644
--- a/zuul/driver/github/githubconnection.py
+++ b/zuul/driver/github/githubconnection.py
@@ -135,6 +135,7 @@
"""Move events from GitHub into the scheduler"""
log = logging.getLogger("zuul.GithubEventConnector")
+ delay = 3.0
def __init__(self, connection):
super(GithubEventConnector, self).__init__()
@@ -147,9 +148,17 @@
self.connection.addEvent(None)
def _handleEvent(self):
- json_body, event_type = self.connection.getEvent()
+ ts, json_body, event_type = self.connection.getEvent()
if self._stopped:
return
+ # Github can produce inconsistent data immediately after an
+ # event, So ensure that we do not deliver the event to Zuul
+ # until at least a certain amount of time has passed. Note
+ # that if we receive several events in succession, we will
+ # only need to delay for the first event. In essence, Zuul
+ # should always be a constant number of seconds behind Github.
+ now = time.time()
+ time.sleep(max((ts + self.delay) - now, 0.0))
# If there's any installation mapping information in the body then
# update the project mapping before any requests are made.
@@ -543,7 +552,7 @@
return token
def addEvent(self, data, event=None):
- return self.event_queue.put((data, event))
+ return self.event_queue.put((time.time(), data, event))
def getEvent(self):
return self.event_queue.get()
diff --git a/zuul/driver/sql/sqlreporter.py b/zuul/driver/sql/sqlreporter.py
index 7785c48..f9537ac 100644
--- a/zuul/driver/sql/sqlreporter.py
+++ b/zuul/driver/sql/sqlreporter.py
@@ -33,8 +33,8 @@
return
with self.connection.engine.begin() as conn:
- change = getattr(item.change, 'number', '')
- patchset = getattr(item.change, 'patchset', '')
+ change = getattr(item.change, 'number', None)
+ patchset = getattr(item.change, 'patchset', None)
ref = getattr(item.change, 'ref', '')
oldrev = getattr(item.change, 'oldrev', '')
newrev = getattr(item.change, 'newrev', '')
diff --git a/zuul/model.py b/zuul/model.py
index 68df7fc..cf63f64 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -358,6 +358,9 @@
def __repr__(self):
return '<Project %s>' % (self.name)
+ def getSafeAttributes(self):
+ return Attributes(name=self.name)
+
class Node(object):
"""A single node for use by a job.