Set remote url on every getRepo in merger

In case we run on github with apps we have an access token in the git
url. This access token is only valid for a specific period of
time. Currently the merger caches its repos and never changes the git
url on subsequent merge or cat requests. After timeout the merger then
faces an exception [1].

The fix is to update the remote url on every getRepo call in the
merger. This makes sure that we have a recent access token on every
merge or cat call.

Further the executor has the same problems and gets fixed by this too
as it also uses getRepo from the merger.

[1] Exception:
 2017-12-20 07:00:00,874 ERROR zuul.Merger: Unable to update github/sandbox/sandbox
 Traceback (most recent call last):
   File "/usr/lib/python3.6/site-packages/zuul/merger/merger.py", line 382, in updateRepo
     repo.reset()
   File "/usr/lib/python3.6/site-packages/zuul/merger/merger.py", line 143, in reset
     self.update()
   File "/usr/lib/python3.6/site-packages/zuul/merger/merger.py", line 293, in update
     self._git_fetch(repo, 'origin', tags=True)
   File "/usr/lib/python3.6/site-packages/zuul/merger/merger.py", line 133, in _git_fetch
     **kwargs)
   File "/usr/lib/python3.6/site-packages/git/cmd.py", line 551, in <lambda>
     return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
   File "/usr/lib/python3.6/site-packages/git/cmd.py", line 1010, in _call_process
     return self.execute(call, **exec_kwargs)
   File "/usr/lib/python3.6/site-packages/git/cmd.py", line 821, in execute
     raise GitCommandError(command, status, stderr_value, stdout_value)
 git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
   cmdline: git fetch --tags origin
   stderr: 'remote: Invalid username or password.
 fatal: Authentication failed for 'https://x-access-token:v1.c8ec09e233b16871b64843adeec5fb048a383fba@github.example.com/sandbox/sandbox/''

Change-Id: If990dc48e6c10c24b6b32db5f5711fc3608bdfe4
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)