Prefer git-config over git-review config files
git-review gets its configuration from multiple sources (by priority): * command line options * git-config * options: username, rebase * with local/global/system config * git-review config files * options: scheme, host, port, project, defaultbranch/remote/rebase * locally using .gitreview * globally using ~/.config/gitreview/git-review.conf * system using /etc/git-review/git-review.conf .gitreview file is commonly provided versioned in the git repo, where other git-review config files and git-config is done by developers. It implies for developers multiple places to define local/global/system configuration options but some can only be changed by updating .gitreview (scheme/port...) which is under versioning. This change proposes to use as configuration sources (by priority): * command line options * git-config for developer local/global/system config * options: username, rebase and all .gitreview options * .gitreview local file for repo provided specific config and deprecates git-review global/system files in order to reduce configuration sources and allow to overload .gitreview configuration without updating it. Change-Id: I24aba0fa089de57d51a79049d9c192f76d576f69
This commit is contained in:
parent
abe76bfe28
commit
1bc87f26d6
22
git-review.1
22
git-review.1
@ -181,6 +181,24 @@ file:
|
|||||||
[gitreview]
|
[gitreview]
|
||||||
username=\fImygerrituser\fP
|
username=\fImygerrituser\fP
|
||||||
.Ed
|
.Ed
|
||||||
|
.It gitreview.scheme
|
||||||
|
This setting determines the default scheme (ssh/http/https) of gerrit remote
|
||||||
|
.Ed
|
||||||
|
.It gitreview.host
|
||||||
|
This setting determines the default hostname of gerrit remote
|
||||||
|
.Ed
|
||||||
|
.It gitreview.port
|
||||||
|
This setting determines the default port of gerrit remote
|
||||||
|
.Ed
|
||||||
|
.It gitreview.project
|
||||||
|
This setting determines the default name of gerrit git repo
|
||||||
|
.Ed
|
||||||
|
.It gitreview.remote
|
||||||
|
This setting determines the default name to use for gerrit remote
|
||||||
|
.Ed
|
||||||
|
.It gitreview.branch
|
||||||
|
This setting determines the default branch
|
||||||
|
.Ed
|
||||||
.It gitreview.rebase
|
.It gitreview.rebase
|
||||||
This setting determines whether changes submitted will
|
This setting determines whether changes submitted will
|
||||||
be rebased to the newest state of the branch.
|
be rebased to the newest state of the branch.
|
||||||
@ -232,6 +250,7 @@ not to rebase changes by default (same as the
|
|||||||
command line option)
|
command line option)
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
[gerrit]
|
[gerrit]
|
||||||
|
scheme=ssh
|
||||||
host=review.example.com
|
host=review.example.com
|
||||||
port=29418
|
port=29418
|
||||||
project=department/project.git
|
project=department/project.git
|
||||||
@ -240,6 +259,9 @@ defaultremote=review
|
|||||||
defaultrebase=0
|
defaultrebase=0
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
|
When the same option is provided through FILES and CONFIGURATION, the
|
||||||
|
CONFIGURATION value wins.
|
||||||
|
.Pp
|
||||||
.Sh DIAGNOSTICS
|
.Sh DIAGNOSTICS
|
||||||
.Pp
|
.Pp
|
||||||
Normally, exit status is 0 if executed successfully.
|
Normally, exit status is 0 if executed successfully.
|
||||||
|
@ -56,8 +56,7 @@ CONFIGDIR = os.path.expanduser("~/.config/git-review")
|
|||||||
GLOBAL_CONFIG = "/etc/git-review/git-review.conf"
|
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,
|
||||||
defaultbranch='master', defaultremote="gerrit",
|
branch='master', remote="gerrit", rebase="1")
|
||||||
defaultrebase="1")
|
|
||||||
|
|
||||||
_branch_name = None
|
_branch_name = None
|
||||||
_has_color = None
|
_has_color = None
|
||||||
@ -240,6 +239,29 @@ def git_config_get_value(section, option, default=None, as_bool=False):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
"""Expose as dictionary configuration options."""
|
||||||
|
|
||||||
|
def __init__(self, config_file=None):
|
||||||
|
self.config = DEFAULTS.copy()
|
||||||
|
filenames = [] if LOCAL_MODE else [GLOBAL_CONFIG, USER_CONFIG]
|
||||||
|
if config_file:
|
||||||
|
filenames.append(config_file)
|
||||||
|
for filename in filenames:
|
||||||
|
if os.path.exists(filename):
|
||||||
|
if filename != config_file:
|
||||||
|
msg = ("Using global/system git-review config files (%s) "
|
||||||
|
"is deprecated")
|
||||||
|
print(msg % filename)
|
||||||
|
self.config.update(load_config_file(filename))
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
value = git_config_get_value('gitreview', key)
|
||||||
|
if value is None:
|
||||||
|
value = self.config[key]
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class GitConfigException(CommandFailed):
|
class GitConfigException(CommandFailed):
|
||||||
"""Git config value retrieval failed."""
|
"""Git config value retrieval failed."""
|
||||||
EXIT_CODE = 128
|
EXIT_CODE = 128
|
||||||
@ -519,22 +541,6 @@ def check_color_support():
|
|||||||
return _has_color
|
return _has_color
|
||||||
|
|
||||||
|
|
||||||
def get_config(config_file=None):
|
|
||||||
"""Generate the configuration map by starting with some built-in defaults
|
|
||||||
and then loading GLOBAL_CONFIG, USER_CONFIG, and a repository-specific
|
|
||||||
.gitreview file, if they exist. In case of conflict, the configuration file
|
|
||||||
with the narrowest scope wins.
|
|
||||||
"""
|
|
||||||
config = DEFAULTS.copy()
|
|
||||||
filenames = [] if LOCAL_MODE else [GLOBAL_CONFIG, USER_CONFIG]
|
|
||||||
if config_file:
|
|
||||||
filenames.append(config_file)
|
|
||||||
for filename in filenames:
|
|
||||||
if os.path.exists(filename):
|
|
||||||
config.update(load_config_file(filename))
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def load_config_file(config_file):
|
def load_config_file(config_file):
|
||||||
"""Load configuration options from a file."""
|
"""Load configuration options from a file."""
|
||||||
configParser = ConfigParser.ConfigParser()
|
configParser = ConfigParser.ConfigParser()
|
||||||
@ -544,9 +550,9 @@ def load_config_file(config_file):
|
|||||||
'hostname': 'host',
|
'hostname': 'host',
|
||||||
'port': 'port',
|
'port': 'port',
|
||||||
'project': 'project',
|
'project': 'project',
|
||||||
'defaultbranch': 'defaultbranch',
|
'branch': 'defaultbranch',
|
||||||
'defaultremote': 'defaultremote',
|
'remote': 'defaultremote',
|
||||||
'defaultrebase': 'defaultrebase',
|
'rebase': 'defaultrebase',
|
||||||
}
|
}
|
||||||
config = {}
|
config = {}
|
||||||
for config_key, option_name in options.items():
|
for config_key, option_name in options.items():
|
||||||
@ -1047,7 +1053,7 @@ def finish_branch(target_branch):
|
|||||||
|
|
||||||
def convert_bool(one_or_zero):
|
def convert_bool(one_or_zero):
|
||||||
"Return a bool on a one or zero string."
|
"Return a bool on a one or zero string."
|
||||||
return one_or_zero in ["1", "true", "True"]
|
return str(one_or_zero) in ["1", "true", "True"]
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
@ -1167,13 +1173,10 @@ def _main():
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
no_git_dir = False
|
no_git_dir = False
|
||||||
config = get_config(os.path.join(top_dir, ".gitreview"))
|
config = Config(os.path.join(top_dir, ".gitreview"))
|
||||||
defaultrebase = convert_bool(
|
parser.set_defaults(branch=config['branch'],
|
||||||
git_config_get_value("gitreview", "rebase",
|
rebase=convert_bool(config['rebase']),
|
||||||
default=str(config['defaultrebase'])))
|
remote=config['remote'])
|
||||||
parser.set_defaults(rebase=defaultrebase,
|
|
||||||
branch=config['defaultbranch'],
|
|
||||||
remote=config['defaultremote'])
|
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
if no_git_dir:
|
if no_git_dir:
|
||||||
raise no_git_dir
|
raise no_git_dir
|
||||||
|
@ -274,16 +274,18 @@ class BaseGitReviewTestCase(testtools.TestCase, GerritHelpers):
|
|||||||
host = '127.%s.%s.%s' % (self._test_counter, pid >> 8, pid & 255)
|
host = '127.%s.%s.%s' % (self._test_counter, pid >> 8, pid & 255)
|
||||||
return host, 29418, host, 8080, self._dir('gerrit', 'site-' + host)
|
return host, 29418, host, 8080, self._dir('gerrit', 'site-' + host)
|
||||||
|
|
||||||
def _create_gitreview_file(self):
|
def _create_gitreview_file(self, **kwargs):
|
||||||
cfg = ('[gerrit]\n'
|
cfg = ('[gerrit]\n'
|
||||||
'scheme=%s\n'
|
'scheme=%s\n'
|
||||||
'host=%s\n'
|
'host=%s\n'
|
||||||
'port=%s\n'
|
'port=%s\n'
|
||||||
'project=test/test_project.git')
|
'project=test/test_project.git\n'
|
||||||
|
'%s')
|
||||||
parsed = urlparse(self.project_uri)
|
parsed = urlparse(self.project_uri)
|
||||||
host_port = parsed.netloc.rpartition('@')[-1]
|
host_port = parsed.netloc.rpartition('@')[-1]
|
||||||
host, __, port = host_port.partition(':')
|
host, __, port = host_port.partition(':')
|
||||||
cfg %= parsed.scheme, host, port
|
extra = '\n'.join('%s=%s' % kv for kv in kwargs.items())
|
||||||
|
cfg %= parsed.scheme, host, port, extra
|
||||||
utils.write_to_file(self._dir('test', '.gitreview'), cfg.encode())
|
utils.write_to_file(self._dir('test', '.gitreview'), cfg.encode())
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,6 +302,35 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
class HttpGitReviewTestCase(tests.HttpMixin, GitReviewTestCase):
|
class HttpGitReviewTestCase(tests.HttpMixin, GitReviewTestCase):
|
||||||
"""Class for the git-review tests over HTTP(S)."""
|
"""Class for the git-review tests over HTTP(S)."""
|
||||||
|
@ -46,7 +46,7 @@ class ConfigTestCase(testtools.TestCase):
|
|||||||
mock.PropertyMock(return_value=True))
|
mock.PropertyMock(return_value=True))
|
||||||
@mock.patch('os.path.exists', return_value=False)
|
@mock.patch('os.path.exists', return_value=False)
|
||||||
def test_gitreview_local_mode(self, exists_mock):
|
def test_gitreview_local_mode(self, exists_mock):
|
||||||
cmd.get_config()
|
cmd.Config()
|
||||||
self.assertFalse(exists_mock.called)
|
self.assertFalse(exists_mock.called)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user