Use git push-url instead of a second remote

Having a gerrit remote means that we fetch changes twice. It's also
not necessary since the push-url can be set on the origin remote. As
a first step, add a config option that changes the default for defaultremote
to origin and then reworks the logic to add the remote url to origin as a
push-url instead of creating a gerrit remote.

Since this will cause people with an existing gerrit remote to have a
push url added and the gerrit remote orpahned, a follow on commit will
come that will look for a gerrit remote and, if it exists, use it as the
source of url for the push-url and then delete the old remote.

Change-Id: Ief5d092a796516de9605b7df64e7b902c3b47351
This commit is contained in:
Cedric Brandily 2015-05-28 12:22:58 +02:00
parent f5619a6f85
commit 44707a1e79
3 changed files with 147 additions and 78 deletions

View File

@ -57,7 +57,7 @@ GLOBAL_CONFIG = "/etc/git-review/git-review.conf"
USER_CONFIG = os.path.join(CONFIGDIR, "git-review.conf") USER_CONFIG = os.path.join(CONFIGDIR, "git-review.conf")
DEFAULTS = dict(scheme='ssh', hostname=False, port=None, project=False, DEFAULTS = dict(scheme='ssh', hostname=False, port=None, project=False,
branch='master', remote="gerrit", rebase="1", branch='master', remote="gerrit", rebase="1",
track="0") track="0", usepushurl="0")
_branch_name = None _branch_name = None
_has_color = None _has_color = None
@ -369,7 +369,7 @@ def make_remote_url(scheme, username, hostname, port, project):
return "%s://%s@%s/%s" % (scheme, username, hostport, project) return "%s://%s@%s/%s" % (scheme, username, hostport, project)
def add_remote(scheme, hostname, port, project, remote): def add_remote(scheme, hostname, port, project, remote, usepushurl):
"""Adds a gerrit remote.""" """Adds a gerrit remote."""
asked_for_username = False asked_for_username = False
@ -392,11 +392,15 @@ def add_remote(scheme, hostname, port, project, remote):
"%s" % remote_url) "%s" % remote_url)
asked_for_username = True asked_for_username = True
print("Creating a git remote called \"%s\" that maps to:" % remote) if usepushurl:
cmd = "git remote set-url --push %s %s" % (remote, remote_url)
print("Adding a git push url to '%s' that maps to:" % remote)
else:
cmd = "git remote add -f %s %s" % (remote, remote_url)
print("Creating a git remote called '%s' that maps to:" % remote)
print("\t%s" % remote_url) print("\t%s" % remote_url)
cmd = "git remote add -f %s %s" % (remote, remote_url)
(status, remote_output) = run_command_status(cmd)
(status, remote_output) = run_command_status(cmd)
if status != 0: if status != 0:
raise CommandFailed(status, remote_output, cmd, {}) raise CommandFailed(status, remote_output, cmd, {})
@ -678,6 +682,7 @@ def load_config_file(config_file):
'remote': 'defaultremote', 'remote': 'defaultremote',
'rebase': 'defaultrebase', 'rebase': 'defaultrebase',
'track': 'track', 'track': 'track',
'usepushurl': 'usepushurl',
} }
config = {} config = {}
for config_key, option_name in options.items(): for config_key, option_name in options.items():
@ -732,42 +737,58 @@ def resolve_tracking(remote, branch):
return remote, branch return remote, branch
def check_remote(branch, remote, scheme, hostname, port, project): def check_remote(branch, remote, scheme, hostname, port, project,
usepushurl=False):
"""Check that a Gerrit Git remote repo exists, if not, set one.""" """Check that a Gerrit Git remote repo exists, if not, set one."""
has_color = check_color_support() if usepushurl:
if has_color: push_url = git_config_get_value('remote.%s' % remote, 'pushurl', None)
color_never = "--color=never" if push_url:
return
else: else:
color_never = "" has_color = check_color_support()
if has_color:
color_never = "--color=never"
else:
color_never = ""
if remote in run_command("git remote").split("\n"): if remote in run_command("git remote").split("\n"):
remotes = run_command("git branch -a %s" % color_never).split("\n") remotes = run_command("git branch -a %s" % color_never).split("\n")
for current_remote in remotes: for current_remote in remotes:
if (current_remote.strip() == "remotes/%s/%s" % (remote, branch) remote_string = "remotes/%s/%s" % (remote, branch)
and not UPDATE): if (current_remote.strip() == remote_string and not UPDATE):
return return
# We have the remote, but aren't set up to fetch. Fix it # We have the remote, but aren't set up to fetch. Fix it
if VERBOSE: if VERBOSE:
print("Setting up gerrit branch tracking for better rebasing") print("Setting up gerrit branch tracking for better rebasing")
update_remote(remote) update_remote(remote)
return return
if hostname is False or project is False: if hostname is False or project is False:
# This means there was no .gitreview file # This means there was no .gitreview file
printwrap("No '.gitreview' file found in this repository. We don't " printwrap("No '.gitreview' file found in this repository. We don't "
"know where your gerrit is. Please manually create a remote " "know where your gerrit is.")
"named \"%s\" and try again." % remote) if usepushurl:
printwrap("Please set the push-url on your origin remote to the "
"location of your gerrit server and try again")
else:
printwrap("Please manually create a remote "
"named \"%s\" and try again." % remote)
sys.exit(1) sys.exit(1)
# Gerrit remote not present, try to add it # Gerrit remote not present, try to add it
try: try:
add_remote(scheme, hostname, port, project, remote) add_remote(scheme, hostname, port, project, remote, usepushurl)
except Exception: except Exception:
print(sys.exc_info()[2]) print(sys.exc_info()[2])
printwrap("We don't know where your gerrit is. Please manually create " if usepushurl:
"a remote named \"%s\" and try again." % remote) printwrap("We don't know where your gerrit is. Please manually"
" add a push-url to the '%s' remote and try again."
% remote)
else:
printwrap("We don't know where your gerrit is. Please manually"
" create a remote named '%s' and try again." % remote)
raise raise
@ -1294,6 +1315,10 @@ def _main():
help="Regenerate Change-id before submitting") help="Regenerate Change-id before submitting")
parser.add_argument("-r", "--remote", dest="remote", parser.add_argument("-r", "--remote", dest="remote",
help="git remote to use for gerrit") help="git remote to use for gerrit")
parser.add_argument("--use-pushurl", dest="usepushurl",
action="store_true",
help="Use remote push-url logic instead of separate"
" remotes")
rebase_group = parser.add_mutually_exclusive_group() rebase_group = parser.add_mutually_exclusive_group()
rebase_group.add_argument("-R", "--no-rebase", dest="rebase", rebase_group.add_argument("-R", "--no-rebase", dest="rebase",
@ -1400,7 +1425,8 @@ def _main():
config = Config(os.path.join(top_dir, ".gitreview")) config = Config(os.path.join(top_dir, ".gitreview"))
parser.set_defaults(rebase=convert_bool(config['rebase']), parser.set_defaults(rebase=convert_bool(config['rebase']),
track=convert_bool(config['track']), track=convert_bool(config['track']),
remote=config['remote']) remote=None,
usepushurl=convert_bool(config['usepushurl']))
options = parser.parse_args() options = parser.parse_args()
if no_git_dir: if no_git_dir:
raise no_git_dir raise no_git_dir
@ -1421,6 +1447,11 @@ def _main():
VERBOSE = options.verbose VERBOSE = options.verbose
UPDATE = options.update UPDATE = options.update
remote = options.remote remote = options.remote
if not remote:
if options.usepushurl:
remote = 'origin'
else:
remote = config['remote']
yes = options.yes yes = options.yes
status = 0 status = 0
@ -1428,7 +1459,8 @@ def _main():
remote, branch = resolve_tracking(remote, branch) remote, branch = resolve_tracking(remote, branch)
check_remote(branch, remote, config['scheme'], check_remote(branch, remote, config['scheme'],
config['hostname'], config['port'], config['project']) config['hostname'], config['port'], config['project'],
usepushurl=options.usepushurl)
if options.color: if options.color:
set_color_output(options.color) set_color_output(options.color)

View File

@ -131,6 +131,7 @@ class BaseGitReviewTestCase(testtools.TestCase, GerritHelpers):
"""Base class for the git-review tests.""" """Base class for the git-review tests."""
_test_counter = 0 _test_counter = 0
_remote = 'gerrit'
@property @property
def project_uri(self): def project_uri(self):
@ -201,12 +202,18 @@ class BaseGitReviewTestCase(testtools.TestCase, GerritHelpers):
# go to the just cloned test Git repository # go to the just cloned test Git repository
self._run_git('clone', self.project_uri) self._run_git('clone', self.project_uri)
self._run_git('remote', 'add', 'gerrit', self.project_uri) self.configure_gerrit_remote()
self.addCleanup(shutil.rmtree, self.test_dir) self.addCleanup(shutil.rmtree, self.test_dir)
# ensure user is configured for all tests # ensure user is configured for all tests
self._configure_gitreview_username() self._configure_gitreview_username()
def set_remote(self, uri):
self._run_git('remote', 'set-url', self._remote, uri)
def reset_remote(self):
self._run_git('remote', 'rm', self._remote)
def attach_on_exception(self, filename): def attach_on_exception(self, filename):
@self.addOnException @self.addOnException
def attach_file(exc_info): def attach_file(exc_info):
@ -290,6 +297,9 @@ class BaseGitReviewTestCase(testtools.TestCase, GerritHelpers):
os.environ['PATH'] = self.ssh_dir + os.pathsep + os.environ['PATH'] os.environ['PATH'] = self.ssh_dir + os.pathsep + os.environ['PATH']
os.environ['GIT_SSH'] = self._dir('ssh', 'ssh') os.environ['GIT_SSH'] = self._dir('ssh', 'ssh')
def configure_gerrit_remote(self):
self._run_git('remote', 'add', self._remote, self.project_uri)
def _configure_gitreview_username(self): def _configure_gitreview_username(self):
self._run_git('config', 'gitreview.username', 'test_user') self._run_git('config', 'gitreview.username', 'test_user')

View File

@ -23,6 +23,39 @@ from git_review import tests
from git_review.tests import utils from git_review.tests import utils
class ConfigTestCase(tests.BaseGitReviewTestCase):
"""Class for config tests."""
def test_get_config_from_cli(self):
self.reset_remote()
self._run_git('remote', 'rm', 'origin')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git('config', 'gitreview.remote', 'remote-gitconfig')
self._run_git_review('-s', '-r', 'remote-cli')
remote = self._run_git('remote').strip()
self.assertEqual('remote-cli', remote)
def test_get_config_from_gitconfig(self):
self.reset_remote()
self._run_git('remote', 'rm', 'origin')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git('config', 'gitreview.remote', 'remote-gitconfig')
self._run_git_review('-s')
remote = self._run_git('remote').strip()
self.assertEqual('remote-gitconfig', remote)
def test_get_config_from_file(self):
self.reset_remote()
self._run_git('remote', 'rm', 'origin')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git_review('-s')
remote = self._run_git('remote').strip()
self.assertEqual('remote-file', remote)
class GitReviewTestCase(tests.BaseGitReviewTestCase): class GitReviewTestCase(tests.BaseGitReviewTestCase):
"""Class for the git-review tests.""" """Class for the git-review tests."""
@ -35,14 +68,14 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
def test_git_review_s(self): def test_git_review_s(self):
"""Test git-review -s.""" """Test git-review -s."""
self._run_git('remote', 'rm', 'gerrit') self.reset_remote()
self._run_git_review('-s') self._run_git_review('-s')
self._simple_change('test file modified', 'test commit message') self._simple_change('test file modified', 'test commit message')
self.assertIn('Change-Id:', self._run_git('log', '-1')) self.assertIn('Change-Id:', self._run_git('log', '-1'))
def test_git_review_s_in_detached_head(self): def test_git_review_s_in_detached_head(self):
"""Test git-review -s in detached HEAD state.""" """Test git-review -s in detached HEAD state."""
self._run_git('remote', 'rm', 'gerrit') self.reset_remote()
master_sha1 = self._run_git('rev-parse', 'master') master_sha1 = self._run_git('rev-parse', 'master')
self._run_git('checkout', master_sha1) self._run_git('checkout', master_sha1)
self._run_git_review('-s') self._run_git_review('-s')
@ -56,14 +89,14 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
self._run_git('reset', '--hard', 'HEAD^') self._run_git('reset', '--hard', 'HEAD^')
# Review setup with an outdated repo # Review setup with an outdated repo
self._run_git('remote', 'rm', 'gerrit') self.reset_remote()
self._run_git_review('-s') self._run_git_review('-s')
self._simple_change('test file modified', 'test commit message 2') self._simple_change('test file modified', 'test commit message 2')
self.assertIn('Change-Id:', self._run_git('log', '-1')) self.assertIn('Change-Id:', self._run_git('log', '-1'))
def test_git_review_s_from_subdirectory(self): def test_git_review_s_from_subdirectory(self):
"""Test git-review -s from subdirectory.""" """Test git-review -s from subdirectory."""
self._run_git('remote', 'rm', 'gerrit') self.reset_remote()
utils.run_cmd('mkdir', 'subdirectory', chdir=self.test_dir) utils.run_cmd('mkdir', 'subdirectory', chdir=self.test_dir)
self._run_git_review( self._run_git_review(
'-s', chdir=os.path.join(self.test_dir, 'subdirectory')) '-s', chdir=os.path.join(self.test_dir, 'subdirectory'))
@ -81,7 +114,7 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
# download clean Git repository and fresh change from Gerrit to it # download clean Git repository and fresh change from Gerrit to it
self._run_git('clone', self.project_uri) self._run_git('clone', self.project_uri)
self._run_git('remote', 'add', 'gerrit', self.project_uri) self.configure_gerrit_remote()
self._run_git_review('-d', change_id) self._run_git_review('-d', change_id)
self.assertIn('test commit message', self._run_git('log', '-1')) self.assertIn('test commit message', self._run_git('log', '-1'))
@ -94,7 +127,7 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
# and branch is tracking # and branch is tracking
head = self._run_git('symbolic-ref', '-q', 'HEAD') head = self._run_git('symbolic-ref', '-q', 'HEAD')
self.assertIn( self.assertIn(
'refs/remotes/gerrit/master', 'refs/remotes/%s/master' % self._remote,
self._run_git("for-each-ref", "--format='%(upstream)'", head)) self._run_git("for-each-ref", "--format='%(upstream)'", head))
def test_multiple_changes(self): def test_multiple_changes(self):
@ -164,9 +197,11 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
"""Test message displayed where no remote branch exists.""" """Test message displayed where no remote branch exists."""
self._run_git_review('-s') self._run_git_review('-s')
self._run_git('checkout', '-b', 'new_branch') self._run_git('checkout', '-b', 'new_branch')
self._simple_change('simple message',
'need to avoid noop message')
exc = self.assertRaises(Exception, self._run_git_review, 'new_branch') exc = self.assertRaises(Exception, self._run_git_review, 'new_branch')
self.assertIn("The branch 'new_branch' does not exist on the given " self.assertIn("The branch 'new_branch' does not exist on the given "
"remote 'gerrit'", exc.args[0]) "remote '%s'" % self._remote, exc.args[0])
def test_need_rebase_no_upload(self): def test_need_rebase_no_upload(self):
"""Test change needing a rebase does not upload.""" """Test change needing a rebase does not upload."""
@ -179,8 +214,9 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
'create conflict with master') 'create conflict with master')
exc = self.assertRaises(Exception, self._run_git_review) exc = self.assertRaises(Exception, self._run_git_review)
self.assertIn("Errors running git rebase -p -i remotes/gerrit/master", self.assertIn(
exc.args[0]) "Errors running git rebase -p -i remotes/%s/master" % self._remote,
exc.args[0])
self.assertIn("It is likely that your change has a merge conflict.", self.assertIn("It is likely that your change has a merge conflict.",
exc.args[0]) exc.args[0])
@ -196,8 +232,9 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
self._dir('test', 'new_test_file.txt')) self._dir('test', 'new_test_file.txt'))
review_res = self._run_git_review('-v') review_res = self._run_git_review('-v')
self.assertIn("Running: git rebase -p -i remotes/gerrit/master", self.assertIn(
review_res) "Running: git rebase -p -i remotes/%s/master" % self._remote,
review_res)
self.assertEqual(self._run_git('rev-parse', 'HEAD^1'), head_1) self.assertEqual(self._run_git('rev-parse', 'HEAD^1'), head_1)
def test_uploads_with_nondefault_rebase(self): def test_uploads_with_nondefault_rebase(self):
@ -473,53 +510,43 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase):
def test_git_review_F_R(self): def test_git_review_F_R(self):
self.assertRaises(Exception, self._run_git_review, '-F', '-R') self.assertRaises(Exception, self._run_git_review, '-F', '-R')
def test_get_config_from_cli(self):
self._run_git('remote', 'rm', 'origin')
self._run_git('remote', 'rm', 'gerrit')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git('config', 'gitreview.remote', 'remote-gitconfig')
self._run_git_review('-s', '-r', 'remote-cli')
remote = self._run_git('remote').strip()
self.assertEqual('remote-cli', remote)
def test_get_config_from_gitconfig(self):
self._run_git('remote', 'rm', 'origin')
self._run_git('remote', 'rm', 'gerrit')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git('config', 'gitreview.remote', 'remote-gitconfig')
self._run_git_review('-s')
remote = self._run_git('remote').strip()
self.assertEqual('remote-gitconfig', remote)
def test_get_config_from_file(self):
self._run_git('remote', 'rm', 'origin')
self._run_git('remote', 'rm', 'gerrit')
self._create_gitreview_file(defaultremote='remote-file')
self._run_git_review('-s')
remote = self._run_git('remote').strip()
self.assertEqual('remote-file', remote)
def test_config_instead_of_honored(self): def test_config_instead_of_honored(self):
self._run_git('remote', 'add', 'alias', 'test_project_url') self.set_remote('test_project_url')
exc = self.assertRaises(Exception, self._run_git_review, self.assertRaises(Exception, self._run_git_review, '-l')
'-l', '-r', 'alias')
self.assertIn("'test_project_url' does not appear to be a git "
"repository", exc.args[0])
self._run_git('config', '--add', 'url.%s.insteadof' % self.project_uri, self._run_git('config', '--add', 'url.%s.insteadof' % self.project_uri,
'test_project_url') 'test_project_url')
self._run_git_review('-l', '-r', 'alias') self._run_git_review('-l')
def test_config_pushinsteadof_honored(self):
self.set_remote('test_project_url')
self.assertRaises(Exception, self._run_git_review, '-l')
self._run_git('config', '--unset',
'url.%s.insteadof' % self.project_uri)
self._run_git('config', '--add', self._run_git('config', '--add',
'url.%s.pushinsteadof' % self.project_uri, 'url.%s.pushinsteadof' % self.project_uri,
'test_project_url') 'test_project_url')
self._run_git_review('-l', '-r', 'alias') self._run_git_review('-l')
class PushUrlTestCase(GitReviewTestCase):
"""Class for the git-review tests using origin push-url."""
_remote = 'origin'
def set_remote(self, uri):
self._run_git('remote', 'set-url', '--push', self._remote, uri)
def reset_remote(self):
self._run_git('config', '--unset', 'remote.%s.pushurl' % self._remote)
def configure_gerrit_remote(self):
self.set_remote(self.project_uri)
self._run_git('config', 'gitreview.usepushurl', '1')
def test_config_pushinsteadof_honored(self):
self.skipTest("pushinsteadof doesn't rewrite pushurls")
class HttpGitReviewTestCase(tests.HttpMixin, GitReviewTestCase): class HttpGitReviewTestCase(tests.HttpMixin, GitReviewTestCase):