Restore ansible --version output (#55728)
* Add custom action class for version info * Use args from CLI as prog for ArgumentParser object * Make prog a required parameter of create_base_parser() and update all uses to pass in the newly required parameter. * Add unit test for checking ansible --version * Update other related unit testspull/4420/head
parent
c195645575
commit
b3ce3fc5eb
|
@ -116,7 +116,7 @@ def opts_docs(cli_class_name, cli_module_name):
|
||||||
# instantiate each cli and ask its options
|
# instantiate each cli and ask its options
|
||||||
cli_klass = getattr(__import__("ansible.cli.%s" % cli_module_name,
|
cli_klass = getattr(__import__("ansible.cli.%s" % cli_module_name,
|
||||||
fromlist=[cli_class_name]), cli_class_name)
|
fromlist=[cli_class_name]), cli_class_name)
|
||||||
cli = cli_klass([])
|
cli = cli_klass([cli_name])
|
||||||
|
|
||||||
# parse the common options
|
# parse the common options
|
||||||
try:
|
try:
|
||||||
|
@ -124,8 +124,6 @@ def opts_docs(cli_class_name, cli_module_name):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
cli.parser.prog = cli_name
|
|
||||||
|
|
||||||
# base/common cli info
|
# base/common cli info
|
||||||
docs = {
|
docs = {
|
||||||
'cli': cli_module_name,
|
'cli': cli_module_name,
|
||||||
|
|
|
@ -61,6 +61,9 @@ class CLI(with_metaclass(ABCMeta, object)):
|
||||||
Base init method for all command line programs
|
Base init method for all command line programs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
raise ValueError('A non-empty list for args is required')
|
||||||
|
|
||||||
self.args = args
|
self.args = args
|
||||||
self.parser = None
|
self.parser = None
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
@ -275,7 +278,7 @@ class CLI(with_metaclass(ABCMeta, object)):
|
||||||
ansible.arguments.option_helpers.add_runas_options(self.parser)
|
ansible.arguments.option_helpers.add_runas_options(self.parser)
|
||||||
self.parser.add_option('--my-option', dest='my_option', action='store')
|
self.parser.add_option('--my-option', dest='my_option', action='store')
|
||||||
"""
|
"""
|
||||||
self.parser = opt_help.create_base_parser(usage=usage, desc=desc, epilog=epilog)
|
self.parser = opt_help.create_base_parser(os.path.basename(self.args[0]), usage=usage, desc=desc, epilog=epilog, )
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def post_process_args(self, options):
|
def post_process_args(self, options):
|
||||||
|
|
|
@ -29,6 +29,13 @@ class SortingHelpFormatter(argparse.HelpFormatter):
|
||||||
super(SortingHelpFormatter, self).add_arguments(actions)
|
super(SortingHelpFormatter, self).add_arguments(actions)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleVersion(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
ansible_version = to_native(version(getattr(parser, 'prog')))
|
||||||
|
print(ansible_version)
|
||||||
|
parser.exit()
|
||||||
|
|
||||||
|
|
||||||
class PrependListAction(argparse.Action):
|
class PrependListAction(argparse.Action):
|
||||||
"""A near clone of ``argparse._AppendAction``, but designed to prepend list values
|
"""A near clone of ``argparse._AppendAction``, but designed to prepend list values
|
||||||
instead of appending.
|
instead of appending.
|
||||||
|
@ -171,12 +178,13 @@ def version(prog=None):
|
||||||
# Functions to add pre-canned options to an OptionParser
|
# Functions to add pre-canned options to an OptionParser
|
||||||
#
|
#
|
||||||
|
|
||||||
def create_base_parser(usage="", desc=None, epilog=None):
|
def create_base_parser(prog, usage="", desc=None, epilog=None):
|
||||||
"""
|
"""
|
||||||
Create an options parser for all ansible scripts
|
Create an options parser for all ansible scripts
|
||||||
"""
|
"""
|
||||||
# base opts
|
# base opts
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
prog=prog,
|
||||||
formatter_class=SortingHelpFormatter,
|
formatter_class=SortingHelpFormatter,
|
||||||
epilog=epilog,
|
epilog=epilog,
|
||||||
description=desc,
|
description=desc,
|
||||||
|
@ -184,7 +192,8 @@ def create_base_parser(usage="", desc=None, epilog=None):
|
||||||
)
|
)
|
||||||
version_help = "show program's version number, config file location, configured module search path," \
|
version_help = "show program's version number, config file location, configured module search path," \
|
||||||
" module location, executable location and exit"
|
" module location, executable location and exit"
|
||||||
parser.add_argument('--version', action='version', version=to_native(version("%(prog)s")), help=version_help)
|
|
||||||
|
parser.add_argument('--version', action=AnsibleVersion, nargs=0, help=version_help)
|
||||||
add_verbosity_options(parser)
|
add_verbosity_options(parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import re
|
||||||
|
|
||||||
from ansible import context
|
from ansible import context
|
||||||
from ansible.cli.adhoc import AdHocCLI, display
|
from ansible.cli.adhoc import AdHocCLI, display
|
||||||
|
@ -13,8 +14,11 @@ from ansible.errors import AnsibleOptionsError
|
||||||
|
|
||||||
def test_parse():
|
def test_parse():
|
||||||
""" Test adhoc parse"""
|
""" Test adhoc parse"""
|
||||||
adhoc_cli = AdHocCLI([])
|
with pytest.raises(ValueError, match='A non-empty list for args is required'):
|
||||||
with pytest.raises(SystemExit) as exec_info:
|
adhoc_cli = AdHocCLI([])
|
||||||
|
|
||||||
|
adhoc_cli = AdHocCLI(['ansibletest'])
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
adhoc_cli.parse()
|
adhoc_cli.parse()
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,3 +91,23 @@ def test_run_no_extra_vars():
|
||||||
with pytest.raises(SystemExit) as exec_info:
|
with pytest.raises(SystemExit) as exec_info:
|
||||||
adhoc_cli.parse()
|
adhoc_cli.parse()
|
||||||
assert exec_info.value.code == 2
|
assert exec_info.value.code == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_ansible_version(capsys, mocker):
|
||||||
|
adhoc_cli = AdHocCLI(args=['/bin/ansible', '--version'])
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
adhoc_cli.run()
|
||||||
|
version = capsys.readouterr()
|
||||||
|
try:
|
||||||
|
version_lines = version.out.splitlines()
|
||||||
|
except AttributeError:
|
||||||
|
# Python 2.6 does return a named tuple, so get the first item
|
||||||
|
version_lines = version[0].splitlines()
|
||||||
|
|
||||||
|
assert len(version_lines) == 6, 'Incorrect number of lines in "ansible --version" output'
|
||||||
|
assert re.match('ansible [0-9.a-z]+$', version_lines[0]), 'Incorrect ansible version line in "ansible --version" output'
|
||||||
|
assert re.match(' config file = .*$', version_lines[1]), 'Incorrect config file line in "ansible --version" output'
|
||||||
|
assert re.match(' configured module search path = .*$', version_lines[2]), 'Incorrect module search path in "ansible --version" output'
|
||||||
|
assert re.match(' ansible python module location = .*$', version_lines[3]), 'Incorrect python module location in "ansible --version" output'
|
||||||
|
assert re.match(' executable location = .*$', version_lines[4]), 'Incorrect executable locaction in "ansible --version" output'
|
||||||
|
assert re.match(' python version = .*$', version_lines[5]), 'Incorrect python version in "ansible --version" output'
|
||||||
|
|
|
@ -27,12 +27,12 @@ from ansible.cli.console import ConsoleCLI
|
||||||
|
|
||||||
class TestConsoleCLI(unittest.TestCase):
|
class TestConsoleCLI(unittest.TestCase):
|
||||||
def test_parse(self):
|
def test_parse(self):
|
||||||
cli = ConsoleCLI([])
|
cli = ConsoleCLI(['ansible test'])
|
||||||
cli.parse()
|
cli.parse()
|
||||||
self.assertTrue(cli.parser is not None)
|
self.assertTrue(cli.parser is not None)
|
||||||
|
|
||||||
def test_module_args(self):
|
def test_module_args(self):
|
||||||
cli = ConsoleCLI([])
|
cli = ConsoleCLI(['ansible test'])
|
||||||
cli.parse()
|
cli.parse()
|
||||||
res = cli.module_args('copy')
|
res = cli.module_args('copy')
|
||||||
self.assertTrue(cli.parser is not None)
|
self.assertTrue(cli.parser is not None)
|
||||||
|
@ -42,7 +42,7 @@ class TestConsoleCLI(unittest.TestCase):
|
||||||
|
|
||||||
@patch('ansible.utils.display.Display.display')
|
@patch('ansible.utils.display.Display.display')
|
||||||
def test_helpdefault(self, mock_display):
|
def test_helpdefault(self, mock_display):
|
||||||
cli = ConsoleCLI([])
|
cli = ConsoleCLI(['ansible test'])
|
||||||
cli.parse()
|
cli.parse()
|
||||||
cli.modules = set(['copy'])
|
cli.modules = set(['copy'])
|
||||||
cli.helpdefault('copy')
|
cli.helpdefault('copy')
|
||||||
|
|
|
@ -40,7 +40,7 @@ class TestVaultCli(unittest.TestCase):
|
||||||
self.tty_patcher.stop()
|
self.tty_patcher.stop()
|
||||||
|
|
||||||
def test_parse_empty(self):
|
def test_parse_empty(self):
|
||||||
cli = VaultCLI([])
|
cli = VaultCLI(['vaultcli'])
|
||||||
self.assertRaises(SystemExit,
|
self.assertRaises(SystemExit,
|
||||||
cli.parse)
|
cli.parse)
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ from ansible.utils import context_objects as co
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def parser():
|
def parser():
|
||||||
parser = opt_help.create_base_parser()
|
parser = opt_help.create_base_parser('testparser')
|
||||||
|
|
||||||
opt_help.add_runas_options(parser)
|
opt_help.add_runas_options(parser)
|
||||||
opt_help.add_meta_options(parser)
|
opt_help.add_meta_options(parser)
|
||||||
|
|
Loading…
Reference in New Issue