Merge "Set remote url on every getRepo in merger"
diff --git a/tests/base.py b/tests/base.py
index 0f2df35..ec94c48 100755
--- a/tests/base.py
+++ b/tests/base.py
@@ -941,7 +941,7 @@
log = logging.getLogger("zuul.test.FakeGithubConnection")
def __init__(self, driver, connection_name, connection_config, rpcclient,
- changes_db=None, upstream_root=None):
+ changes_db=None, upstream_root=None, git_url_with_auth=False):
super(FakeGithubConnection, self).__init__(driver, connection_name,
connection_config)
self.connection_name = connection_name
@@ -953,6 +953,7 @@
self.merge_not_allowed_count = 0
self.reports = []
self.github_client = tests.fakegithub.FakeGithub(changes_db)
+ self.git_url_with_auth = git_url_with_auth
self.rpcclient = rpcclient
def getGithubClient(self,
@@ -1045,7 +1046,13 @@
return 'read'
def getGitUrl(self, project):
- return os.path.join(self.upstream_root, str(project))
+ if self.git_url_with_auth:
+ auth_token = ''.join(
+ random.choice(string.ascii_lowercase) for x in range(8))
+ prefix = 'file://x-access-token:%s@' % auth_token
+ else:
+ prefix = ''
+ return prefix + os.path.join(self.upstream_root, str(project))
def real_getGitUrl(self, project):
return super(FakeGithubConnection, self).getGitUrl(project)
@@ -1907,6 +1914,7 @@
run_ansible = False
create_project_keys = False
use_ssl = False
+ git_url_with_auth = False
def _startMerger(self):
self.merge_server = zuul.merger.server.MergeServer(self.config,
@@ -2076,10 +2084,12 @@
def getGithubConnection(driver, name, config):
server = config.get('server', 'github.com')
db = self.github_changes_dbs.setdefault(server, {})
- con = FakeGithubConnection(driver, name, config,
- self.rpcclient,
- changes_db=db,
- upstream_root=self.upstream_root)
+ con = FakeGithubConnection(
+ driver, name, config,
+ self.rpcclient,
+ changes_db=db,
+ upstream_root=self.upstream_root,
+ git_url_with_auth=self.git_url_with_auth)
self.event_queues.append(con.event_queue)
setattr(self, 'fake_' + name, con)
return con
diff --git a/tests/unit/test_merger_repo.py b/tests/unit/test_merger_repo.py
index fb2f199..984644f 100644
--- a/tests/unit/test_merger_repo.py
+++ b/tests/unit/test_merger_repo.py
@@ -22,7 +22,7 @@
import testtools
from zuul.merger.merger import Repo
-from tests.base import ZuulTestCase, FIXTURE_DIR
+from tests.base import ZuulTestCase, FIXTURE_DIR, simple_layout
class TestMergerRepo(ZuulTestCase):
@@ -116,3 +116,63 @@
# This is created on the second fetch
self.assertTrue(os.path.exists(os.path.join(
self.workspace_root, 'stamp2')))
+
+
+class TestMergerWithAuthUrl(ZuulTestCase):
+ config_file = 'zuul-github-driver.conf'
+
+ git_url_with_auth = True
+
+ @simple_layout('layouts/merging-github.yaml', driver='github')
+ def test_changing_url(self):
+ """
+ This test checks that if getGitUrl returns different urls for the same
+ repo (which happens if an access token is part of the url) then the
+ remote urls are changed in the merger accordingly. This tests directly
+ the merger.
+ """
+
+ merger = self.executor_server.merger
+ repo = merger.getRepo('github', 'org/project')
+ first_url = repo.remote_url
+
+ repo = merger.getRepo('github', 'org/project')
+ second_url = repo.remote_url
+
+ # the urls should differ
+ self.assertNotEqual(first_url, second_url)
+
+ @simple_layout('layouts/merging-github.yaml', driver='github')
+ def test_changing_url_end_to_end(self):
+ """
+ This test checks that if getGitUrl returns different urls for the same
+ repo (which happens if an access token is part of the url) then the
+ remote urls are changed in the merger accordingly. This is an end to
+ end test.
+ """
+
+ A = self.fake_github.openFakePullRequest('org/project', 'master',
+ 'PR title')
+ self.fake_github.emitEvent(A.getCommentAddedEvent('merge me'))
+ self.waitUntilSettled()
+ self.assertTrue(A.is_merged)
+
+ # get remote url of org/project in merger
+ repo = self.executor_server.merger.repos.get('github.com/org/project')
+ self.assertIsNotNone(repo)
+ git_repo = git.Repo(repo.local_path)
+ first_url = list(git_repo.remotes[0].urls)[0]
+
+ B = self.fake_github.openFakePullRequest('org/project', 'master',
+ 'PR title')
+ self.fake_github.emitEvent(B.getCommentAddedEvent('merge me again'))
+ self.waitUntilSettled()
+ self.assertTrue(B.is_merged)
+
+ repo = self.executor_server.merger.repos.get('github.com/org/project')
+ self.assertIsNotNone(repo)
+ git_repo = git.Repo(repo.local_path)
+ second_url = list(git_repo.remotes[0].urls)[0]
+
+ # the urls should differ
+ self.assertNotEqual(first_url, second_url)
diff --git a/zuul/merger/merger.py b/zuul/merger/merger.py
index 5e102b4..aba8645 100644
--- a/zuul/merger/merger.py
+++ b/zuul/merger/merger.py
@@ -79,6 +79,8 @@
self.retry_interval = retry_interval
try:
self._ensure_cloned()
+ self._git_set_remote_url(
+ git.Repo(self.local_path), self.remote_url)
except Exception:
self.log.exception("Unable to initialize repo for %s" % remote)
@@ -112,8 +114,7 @@
config_writer.set_value('user', 'name', self.username)
config_writer.write()
if rewrite_url:
- with repo.remotes.origin.config_writer as config_writer:
- config_writer.set('url', self.remote_url)
+ self._git_set_remote_url(repo, self.remote_url)
self._initialized = True
def isInitialized(self):
@@ -154,6 +155,10 @@
else:
raise
+ def _git_set_remote_url(self, repo, url):
+ with repo.remotes.origin.config_writer as config_writer:
+ config_writer.set('url', url)
+
def createRepoObject(self):
self._ensure_cloned()
repo = git.Repo(self.local_path)
@@ -350,6 +355,13 @@
repo = self.createRepoObject()
repo.delete_remote(repo.remotes[remote])
+ def setRemoteUrl(self, url):
+ if self.remote_url == url:
+ return
+ self.log.debug("Set remote url to %s" % url)
+ self.remote_url = url
+ self._git_set_remote_url(self.createRepoObject(), self.remote_url)
+
class Merger(object):
def __init__(self, working_root, connections, email, username,
@@ -397,7 +409,9 @@
url = source.getGitUrl(project)
key = '/'.join([hostname, project_name])
if key in self.repos:
- return self.repos[key]
+ repo = self.repos[key]
+ repo.setRemoteUrl(url)
+ return repo
sshkey = self.connections.connections.get(connection_name).\
connection_config.get('sshkey')
if not url: