Example #1
0
def check_cli(cmd):
    from azure.cli.core.file_util import (
        create_invoker_and_load_cmds_and_args, get_all_help)

    exceptions = {}

    print('Running CLI self-test.\n')

    print('Loading all commands and arguments...')
    try:
        create_invoker_and_load_cmds_and_args(cmd.cli_ctx)
        print('Commands loaded OK.\n')
    except Exception as ex:  # pylint: disable=broad-except
        exceptions['load_commands'] = ex
        logger.error('Error occurred loading commands!\n')

    print('Retrieving all help...')
    try:
        get_all_help(cmd.cli_ctx)
        print('Help loaded OK.\n')
    except Exception as ex:  # pylint: disable=broad-except
        exceptions['load_help'] = ex
        logger.error('Error occurred loading help!\n')

    if not exceptions:
        print('CLI self-test completed: OK')
    else:
        raise CLIError(exceptions)
Example #2
0
def check_cli(cmd):
    from azure.cli.core.file_util import (
        create_invoker_and_load_cmds_and_args, get_all_help)

    exceptions = {}

    print('Running CLI self-test.\n')

    print('Loading all commands and arguments...')
    try:
        create_invoker_and_load_cmds_and_args(cmd.cli_ctx)
        print('Commands loaded OK.\n')
    except Exception as ex:  # pylint: disable=broad-except
        exceptions['load_commands'] = ex
        logger.error('Error occurred loading commands!\n')

    print('Retrieving all help...')
    try:
        get_all_help(cmd.cli_ctx, skip=False)
        print('Help loaded OK.\n')
    except Exception as ex:  # pylint: disable=broad-except
        exceptions['load_help'] = ex
        logger.error('Error occurred loading help!\n')

    if not exceptions:
        print('CLI self-test completed: OK')
    else:
        raise CLIError(exceptions)
Example #3
0
    def test_load_from_help_yaml(self, mocked_load, mocked_pkg_util):
        # setup help.py and help.yaml help.
        self.set_help_py()
        yaml_path = self.set_help_yaml()
        create_invoker_and_load_cmds_and_args(self.test_cli)

        # mock logic in core._help_loaders for retrieving yaml file from loader path.
        expected_arg = self.test_cli.invocation.commands_loader.cmd_to_loader_map['test alpha'][0].__class__
        with mock.patch('inspect.getfile', side_effect=get_mocked_inspect_getfile(expected_arg, yaml_path)):
            group_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test"), None)
            command_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test alpha"), None)  # pylint: disable=line-too-long

            # Test that group and command help are successfully displayed.
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "-h"])
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "alpha", "-h"])

        # Test group help
        self.assertIsNotNone(group_help_obj)
        self.assertEqual(group_help_obj.short_summary, "Group yaml summary.")
        self.assertEqual(group_help_obj.long_summary, "Group yaml description. A.K.A long description.")
        self.assertEqual(group_help_obj.links[0], {"title": "Azure Test Docs", "url": "https://docs.microsoft.com/en-us/azure/test"})
        self.assertEqual(group_help_obj.links[1], {"url": "https://aka.ms/just-a-url"})

        # Test command help
        self.assertIsNotNone(command_help_obj)
        self.assertEqual(command_help_obj.short_summary, "Command yaml summary.")
        self.assertEqual(command_help_obj.long_summary, "Command yaml description. A.K.A long description.")
        self.assertEqual(command_help_obj.links[0], {"title": "Azure Test Alpha Docs",
                                                     "url": "https://docs.microsoft.com/en-us/azure/test/alpha"})
        self.assertEqual(command_help_obj.links[1], {"url": "https://aka.ms/just-a-long-url"})

        # test that parameters and help are loaded from command function docstring, argument registry help and help.yaml
        obj_param_dict = {param.name: param for param in command_help_obj.parameters}
        param_name_set = {"--arg1 -a", "--arg2 -b", "--arg3", "ARG4"}
        self.assertTrue(set(obj_param_dict.keys()).issuperset(param_name_set))

        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")
        self.assertEqual(obj_param_dict["--arg3"].short_summary, "Arg3's docstring help text.")
        self.assertEqual(obj_param_dict["ARG4"].short_summary, "Arg4's summary, yaml. Positional arg, not required.")

        self.assertEqual(obj_param_dict["--arg2 -b"].short_summary, "Arg 2's summary.")
        self.assertEqual(obj_param_dict["--arg2 -b"].long_summary, "A true description of this parameter.")
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[0], {"string": "Number range: -5.0 to 5.0"})
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[1]['link'], {"url": "https://www.foo.com",
                                                                                "title": "foo"})
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[2]['link'], {"command": "az test show",
                                                                                "title": "Show test details"})

        self.assertEqual(command_help_obj.examples[0].short_summary, "A simple example")
        self.assertEqual(command_help_obj.examples[0].long_summary, "More detail on the simple example.")
        self.assertEqual(command_help_obj.examples[0].command, "az test alpha --arg1 apple --arg2 ball --arg3 cat")
        self.assertEqual(command_help_obj.examples[0].supported_profiles, "2018-03-01-hybrid, latest")
        self.assertEqual(command_help_obj.examples[0].unsupported_profiles, None)

        self.assertEqual(command_help_obj.examples[1].supported_profiles, None)
        self.assertEqual(command_help_obj.examples[1].unsupported_profiles, "2017-03-09-profile")
Example #4
0
    def test_load_from_help_yaml(self, mocked_load, mocked_pkg_util):
        # setup help.py and help.yaml help.
        self.set_help_py()
        yaml_path = self.set_help_yaml()
        create_invoker_and_load_cmds_and_args(self.test_cli)

        # mock logic in core._help_loaders for retrieving yaml file from loader path.
        expected_arg = self.test_cli.invocation.commands_loader.cmd_to_loader_map['test alpha'][0].__class__
        with mock.patch('inspect.getfile', side_effect=get_mocked_inspect_getfile(expected_arg, yaml_path)):
            group_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test"), None)
            command_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test alpha"), None)  # pylint: disable=line-too-long

            # Test that group and command help are successfully displayed.
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "-h"])
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "alpha", "-h"])

        # Test group help
        self.assertIsNotNone(group_help_obj)
        self.assertEqual(group_help_obj.short_summary, "Group yaml summary.")
        self.assertEqual(group_help_obj.long_summary, "Group yaml description. A.K.A long description.")
        self.assertEqual(group_help_obj.links[0], {"title": "Azure Test Docs", "url": "https://docs.microsoft.com/en-us/azure/test"})
        self.assertEqual(group_help_obj.links[1], {"url": "https://aka.ms/just-a-url"})

        # Test command help
        self.assertIsNotNone(command_help_obj)
        self.assertEqual(command_help_obj.short_summary, "Command yaml summary.")
        self.assertEqual(command_help_obj.long_summary, "Command yaml description. A.K.A long description.")
        self.assertEqual(command_help_obj.links[0], {"title": "Azure Test Alpha Docs",
                                                     "url": "https://docs.microsoft.com/en-us/azure/test/alpha"})
        self.assertEqual(command_help_obj.links[1], {"url": "https://aka.ms/just-a-long-url"})

        # test that parameters and help are loaded from command function docstring, argument registry help and help.yaml
        obj_param_dict = {param.name: param for param in command_help_obj.parameters}
        param_name_set = {"--arg1 -a", "--arg2 -b", "--arg3", "ARG4"}
        self.assertTrue(set(obj_param_dict.keys()).issuperset(param_name_set))

        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")
        self.assertEqual(obj_param_dict["--arg3"].short_summary, "Arg3's docstring help text.")
        self.assertEqual(obj_param_dict["ARG4"].short_summary, "Arg4's summary, yaml. Positional arg, not required.")

        self.assertEqual(obj_param_dict["--arg2 -b"].short_summary, "Arg 2's summary.")
        self.assertEqual(obj_param_dict["--arg2 -b"].long_summary, "A true description of this parameter.")
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[0], {"string": "Number range: -5.0 to 5.0"})
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[1]['link'], {"url": "https://www.foo.com",
                                                                                "title": "foo"})
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[2]['link'], {"command": "az test show",
                                                                                "title": "Show test details"})

        self.assertEqual(command_help_obj.examples[0].short_summary, "A simple example")
        self.assertEqual(command_help_obj.examples[0].long_summary, "More detail on the simple example.")
        self.assertEqual(command_help_obj.examples[0].command, "az test alpha --arg1 apple --arg2 ball --arg3 cat")
        self.assertEqual(command_help_obj.examples[0].supported_profiles, "2018-03-01-hybrid, latest")
        self.assertEqual(command_help_obj.examples[0].unsupported_profiles, None)

        self.assertEqual(command_help_obj.examples[1].supported_profiles, None)
        self.assertEqual(command_help_obj.examples[1].unsupported_profiles, "2017-03-09-profile")
Example #5
0
    def test_load_from_help_py(self, mocked_load, mocked_pkg_util):
        self.set_help_py()
        create_invoker_and_load_cmds_and_args(self.test_cli)
        group_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test"), None)
        command_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test alpha"), None)

        # Test that group and command help are successfully displayed.
        with self.assertRaises(SystemExit):
            self.test_cli.invoke(["test", "-h"])
        with self.assertRaises(SystemExit):
            self.test_cli.invoke(["test", "alpha", "-h"])

        # Test group help
        self.assertIsNotNone(group_help_obj)
        self.assertEqual(group_help_obj.short_summary, "Foo Bar Group.")
        self.assertEqual(group_help_obj.long_summary, "Foo Bar Baz Group is a fun group.")

        # Test command help
        self.assertIsNotNone(command_help_obj)
        self.assertEqual(command_help_obj.short_summary, "Foo Bar Command.")
        self.assertEqual(command_help_obj.long_summary, "Foo Bar Baz Command is a fun command.")

        # test that parameters and help are loaded from command function docstring, argument registry help and help.py
        obj_param_dict = {param.name: param for param in command_help_obj.parameters}
        param_name_set = {"--arg1 -a", "--arg2 -b", "--arg3", "ARG4"}
        self.assertTrue(set(obj_param_dict.keys()).issuperset(param_name_set))

        self.assertEqual(obj_param_dict["--arg3"].short_summary, "Arg3's docstring help text.")
        self.assertEqual(obj_param_dict["ARG4"].short_summary, "Positional parameter. Not required.")
        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")

        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")
        self.assertEqual(obj_param_dict["--arg1 -a"].value_sources[0]['link']['command'], "az foo bar")
        self.assertEqual(obj_param_dict["--arg1 -a"].value_sources[1]['link']['command'], "az bar baz")

        if self.test_cli.cloud.profile in ['2018-03-01-hybrid', 'latest']:
            self.assertEqual(command_help_obj.examples[0].short_summary, "Alpha Example")
            self.assertEqual(command_help_obj.examples[0].command, "az test alpha --arg1 a --arg2 b --arg3 c")
            self.assertEqual(command_help_obj.examples[0].supported_profiles, "2018-03-01-hybrid, latest")
            self.assertEqual(command_help_obj.examples[0].unsupported_profiles, None)

            self.assertEqual(command_help_obj.examples[1].supported_profiles, None)
            self.assertEqual(command_help_obj.examples[1].unsupported_profiles, "2017-03-09-profile")

        if self.test_cli.cloud.profile == '2019-03-01-hybrid':
            self.assertEqual(len(command_help_obj.examples), 1)
            self.assertEqual(command_help_obj.examples[0].short_summary, "A simple example unsupported on latest")
            self.assertEqual(command_help_obj.examples[0].command, "az test alpha --arg1 a --arg2 b")
            self.assertEqual(command_help_obj.examples[0].unsupported_profiles, '2017-03-09-profile')

        if self.test_cli.cloud.profile == '2017-03-09-profile':
            self.assertEqual(len(command_help_obj.examples), 0)
Example #6
0
def main(args):
    from azure.cli.core import get_default_cli
    from azure.cli.core.file_util import get_all_help, create_invoker_and_load_cmds_and_args

    print('Initializing linter with command table and help files...')
    # setup CLI to enable command loader
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)
    command_table = az_cli.invocation.commands_loader.command_table

    # format loaded help
    loaded_help = {data.command: data for data in loaded_help if data.command}

    # load yaml help
    help_file_entries = {}
    for entry_name, help_yaml in helps.items():
        help_entry = yaml.load(help_yaml)
        help_file_entries[entry_name] = help_entry

    if not args.rule_types_to_run:
        args.rule_types_to_run = [
            'params', 'commands', 'command_groups', 'help_entries'
        ]

    # find rule exclusions and pass to linter manager
    from ..utilities.path import get_command_modules_paths
    exclusions = {}
    command_modules_paths = get_command_modules_paths()
    for _, path in command_modules_paths:
        exclusion_path = os.path.join(path, 'linter_exclusions.yml')
        if os.path.isfile(exclusion_path):
            mod_exclusions = yaml.load(open(exclusion_path))
            exclusions.update(mod_exclusions)

    # only run linter on modules specified
    if args.modules:
        from .util import include_mods
        command_table, help_file_entries = include_mods(
            command_table, help_file_entries, args.modules)

    # Instantiate and run Linter
    linter_manager = LinterManager(command_table=command_table,
                                   help_file_entries=help_file_entries,
                                   loaded_help=loaded_help,
                                   exclusions=exclusions,
                                   rule_inclusions=args.rules)
    exit_code = linter_manager.run(run_params='params'
                                   in args.rule_types_to_run,
                                   run_commands='commands'
                                   in args.rule_types_to_run,
                                   run_command_groups='command_groups'
                                   in args.rule_types_to_run,
                                   run_help_files_entries='help_entries'
                                   in args.rule_types_to_run,
                                   ci=args.ci)

    sys.exit(exit_code)
Example #7
0
def main(args):
    from azure.cli.core import get_default_cli
    from azure.cli.core.file_util import get_all_help, create_invoker_and_load_cmds_and_args

    print('Initializing linter with command table and help files...')
    # setup CLI to enable command loader
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)
    command_loader = az_cli.invocation.commands_loader

    # format loaded help
    loaded_help = {data.command: data for data in loaded_help if data.command}

    # load yaml help
    help_file_entries = {}
    for entry_name, help_yaml in helps.items():
        help_entry = yaml.load(help_yaml)
        help_file_entries[entry_name] = help_entry

    if not args.rule_types_to_run:
        args.rule_types_to_run = ['params', 'commands', 'command_groups', 'help_entries']

    # find rule exclusions and pass to linter manager
    from ..utilities.path import get_command_modules_paths, get_extensions_paths
    exclusions = {}
    command_modules_paths = get_command_modules_paths()
    extension_paths = get_extensions_paths()
    for gen in (command_modules_paths, extension_paths):
        for _, path in gen:
            exclusion_path = os.path.join(path, 'linter_exclusions.yml')
            if os.path.isfile(exclusion_path):
                mod_exclusions = yaml.load(open(exclusion_path))
                exclusions.update(mod_exclusions)

    # only run linter on modules and extensions specified
    if args.modules or args.extensions:
        from .util import include_commands
        command_loader, help_file_entries = include_commands(
            command_loader, help_file_entries, module_inclusions=args.modules, extensions=args.extensions)

    # Instantiate and run Linter
    linter_manager = LinterManager(command_loader=command_loader,
                                   help_file_entries=help_file_entries,
                                   loaded_help=loaded_help,
                                   exclusions=exclusions,
                                   rule_inclusions=args.rules)
    exit_code = linter_manager.run(run_params='params' in args.rule_types_to_run,
                                   run_commands='commands' in args.rule_types_to_run,
                                   run_command_groups='command_groups' in args.rule_types_to_run,
                                   run_help_files_entries='help_entries' in args.rule_types_to_run,
                                   ci=args.ci)

    sys.exit(exit_code)
Example #8
0
    def test_load_from_help_py(self, mocked_load, mocked_pkg_util):
        self.set_help_py()
        create_invoker_and_load_cmds_and_args(self.test_cli)
        group_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test"), None)
        command_help_obj = next((help for help in get_all_help(self.test_cli) if help.command == "test alpha"), None)

        # Test that group and command help are successfully displayed.
        with self.assertRaises(SystemExit):
            self.test_cli.invoke(["test", "-h"])
        with self.assertRaises(SystemExit):
            self.test_cli.invoke(["test", "alpha", "-h"])

        # Test group help
        self.assertIsNotNone(group_help_obj)
        self.assertEqual(group_help_obj.short_summary, "Foo Bar Group.")
        self.assertEqual(group_help_obj.long_summary, "Foo Bar Baz Group is a fun group.")

        # Test command help
        self.assertIsNotNone(command_help_obj)
        self.assertEqual(command_help_obj.short_summary, "Foo Bar Command.")
        self.assertEqual(command_help_obj.long_summary, "Foo Bar Baz Command is a fun command.")

        # test that parameters and help are loaded from command function docstring, argument registry help and help.py
        obj_param_dict = {param.name: param for param in command_help_obj.parameters}
        param_name_set = {"--arg1 -a", "--arg2 -b", "--arg3", "ARG4"}
        self.assertTrue(set(obj_param_dict.keys()).issuperset(param_name_set))

        self.assertEqual(obj_param_dict["--arg3"].short_summary, "Arg3's docstring help text.")
        self.assertEqual(obj_param_dict["ARG4"].short_summary, "Positional parameter. Not required.")
        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")

        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary, "A short summary.")
        self.assertEqual(obj_param_dict["--arg1 -a"].value_sources[0]['link']['command'], "az foo bar")
        self.assertEqual(obj_param_dict["--arg1 -a"].value_sources[1]['link']['command'], "az bar baz")

        self.assertEqual(command_help_obj.examples[0].short_summary, "Alpha Example")
        self.assertEqual(command_help_obj.examples[0].command, "az test alpha --arg1 a --arg2 b --arg3 c")
        self.assertEqual(command_help_obj.examples[0].supported_profiles, "2018-03-01-hybrid, latest")
        self.assertEqual(command_help_obj.examples[0].unsupported_profiles, None)

        self.assertEqual(command_help_obj.examples[1].supported_profiles, None)
        self.assertEqual(command_help_obj.examples[1].unsupported_profiles, "2017-03-09-profile")
def verify_load_all(_):
    from azure.cli.core import get_default_cli
    from azure.cli.core.file_util import get_all_help, create_invoker_and_load_cmds_and_args

    print('Loading all commands, arguments, and help...')
    # setup CLI to enable command loader
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)
    print('Everything loaded successfully.')
Example #10
0
def verify_load_all(_):
    from azure.cli.core import get_default_cli, EVENT_FAILED_EXTENSION_LOAD
    from azure.cli.core.file_util import get_all_help, create_invoker_and_load_cmds_and_args

    print('Loading all commands, arguments, and help...')
    # setup CLI to enable command loader and register event
    az_cli = get_default_cli()
    az_cli.register_event(EVENT_FAILED_EXTENSION_LOAD, extension_failed_load_handler)

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)

    # verify each installed extension is properly loaded
    if not FAILED_TO_LOAD or set(FAILED_TO_LOAD).issubset(set(EXTENSION_FAILURE_EXCLUSIONS)):
        print('Everything loaded successfully.')
    else:
        raise Exception('Exceptions failed to load: {}'.format(', '.join(FAILED_TO_LOAD)))
Example #11
0
def main():
    az_cli = AzCli(cli_name='az',
                   commands_loader_cls=MainCommandsLoader,
                   invocation_cls=AzCliCommandInvoker,
                   parser_cls=AzCliCommandParser,
                   help_cls=AzCliHelp)
    create_invoker_and_load_cmds_and_args(az_cli)
    help_files = get_all_help(az_cli)
    high_command_set = set()
    for help_file in help_files:
        if help_file.command:
            high_command_set.add(help_file.command.split()[0])
    print('high_command_set:')
    print(high_command_set)

    # Load and check service_name.json
    with open('src/azure-cli/service_name.json') as f:
        service_names = json.load(f)
    print('Verifying src/azure-cli/service_name.json')
    service_name_map = {}
    for service_name in service_names:
        command = service_name['Command']
        service = service_name['AzureServiceName']
        if not command.startswith('az '):
            raise Exception('{} does not start with az!'.format(command))
        if not service:
            raise Exception('AzureServiceName of {} is empty!'.format(command))
        service_name_map[command[3:]] = service
    print('service_name_map:')
    print(service_name_map)

    # Check existence in service_name.json
    for high_command in high_command_set:
        if high_command not in service_name_map:
            raise Exception(
                'No entry of {} in service_name.json. Please add one to the file.'
                .format(high_command))
Example #12
0
    def test_load_from_help_json(self, mocked_load, mocked_pkg_util,
                                 mocked_getmembers):
        # setup help.py, help.yaml and help.json
        self.set_help_py()
        path = self.set_help_yaml(
        )  # either (yaml or json) path should work. As both files are in the same temp dir.
        self.set_help_json()
        create_invoker_and_load_cmds_and_args(self.test_cli)

        # mock logic in core._help_loaders for retrieving yaml file from loader path.
        expected_arg = self.test_cli.invocation.commands_loader.cmd_to_loader_map[
            'test alpha'][0].__class__
        with mock.patch('inspect.getfile',
                        side_effect=get_mocked_inspect_getfile(
                            expected_arg, path)):
            group_help_obj = next((help for help in get_all_help(self.test_cli)
                                   if help.command == "test"), None)
            command_help_obj = next((help
                                     for help in get_all_help(self.test_cli)
                                     if help.command == "test alpha"), None)

            # Test that group and command help are successfully displayed.
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "-h"])
            with self.assertRaises(SystemExit):
                self.test_cli.invoke(["test", "alpha", "-h"])

        # Test group help
        self.assertIsNotNone(group_help_obj)
        self.assertEqual(group_help_obj.short_summary, "Group json summary.")
        self.assertEqual(group_help_obj.long_summary,
                         "Group json description. A.K.A long description.")
        self.assertEqual(
            group_help_obj.links[0], {
                "title": "Azure Json Test Docs",
                "url": "https://docs.microsoft.com/azure/test"
            })
        self.assertEqual(group_help_obj.links[1],
                         {"url": "https://aka.ms/just-a-url"})

        # Test command help
        self.assertIsNotNone(command_help_obj)
        self.assertEqual(command_help_obj.short_summary,
                         "Command json summary.")
        self.assertEqual(command_help_obj.long_summary,
                         "Command json description. A.K.A long description.")
        self.assertEqual(
            command_help_obj.links[0], {
                "title": "Azure Json Test Alpha Docs",
                "url": "https://docs.microsoft.com/azure/test/alpha"
            })
        self.assertEqual(command_help_obj.links[1],
                         {"url": "https://aka.ms/just-a-long-url"})

        # test that parameters and help are loaded from command function docstring, argument registry help and help.yaml
        obj_param_dict = {
            param.name: param
            for param in command_help_obj.parameters
        }
        param_name_set = {"--arg1 -a", "--arg2 -b", "--arg3", "ARG4"}
        self.assertTrue(set(obj_param_dict.keys()).issuperset(param_name_set))

        self.assertEqual(obj_param_dict["--arg3"].short_summary,
                         "Arg 3's json summary.")
        self.assertEqual(obj_param_dict["--arg3"].long_summary,
                         "A truly true description of this parameter.")
        self.assertEqual(obj_param_dict["--arg3"].value_sources[0],
                         {"string": "Number range: 0 to 10"})
        self.assertEqual(obj_param_dict["--arg3"].value_sources[1]['link'], {
            "url": "https://www.foo-json.com",
            "title": "foo-json"
        })
        self.assertEqual(obj_param_dict["--arg3"].value_sources[2]['link'], {
            "command": "az test show",
            "title": "Show test details. Json file"
        })

        if self.test_cli.cloud.profile in ['2018-03-01-hybrid', 'latest']:
            self.assertEqual(command_help_obj.examples[0].short_summary,
                             "A simple example from json")
            self.assertEqual(command_help_obj.examples[0].long_summary,
                             "More detail on the simple example.")
            self.assertEqual(
                command_help_obj.examples[0].command,
                "az test alpha --arg1 alpha --arg2 beta --arg3 chi")
            self.assertEqual(command_help_obj.examples[0].supported_profiles,
                             "2018-03-01-hybrid, latest")

        if self.test_cli.cloud.profile == '2019-03-01-hybrid':
            # only supported example here
            self.assertEqual(len(command_help_obj.examples), 0)

        if self.test_cli.cloud.profile == '2017-03-09-profile':
            self.assertEqual(len(command_help_obj.examples), 0)

        # validate other parameters, which have help from help.py and help.yamls
        self.assertEqual(obj_param_dict["--arg1 -a"].short_summary,
                         "A short summary.")
        self.assertEqual(obj_param_dict["--arg2 -b"].short_summary,
                         "Arg 2's summary.")
        self.assertEqual(
            obj_param_dict["ARG4"].short_summary,
            "Arg4's summary, yaml. Positional arg, not required.")
        # arg2's help from help.yaml still preserved.
        self.assertEqual(obj_param_dict["--arg2 -b"].long_summary,
                         "A true description of this parameter.")
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[0],
                         {"string": "Number range: -5.0 to 5.0"})
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[1]['link'],
                         {
                             "url": "https://www.foo.com",
                             "title": "foo"
                         })
        self.assertEqual(obj_param_dict["--arg2 -b"].value_sources[2]['link'],
                         {
                             "command": "az test show",
                             "title": "Show test details"
                         })
Example #13
0
    def make_rst(self):
        INDENT = '   '
        DOUBLEINDENT = INDENT * 2

        az_cli = AzCli(cli_name='az',
               commands_loader_cls=MainCommandsLoader,
               invocation_cls=AzCliCommandInvoker,
               parser_cls=AzCliCommandParser,
               help_cls=AzCliHelp)
        with patch('getpass.getuser', return_value='your_system_user_login_name'):
            create_invoker_and_load_cmds_and_args(az_cli)
        help_files = get_all_help(az_cli)

        doc_source_map = _load_doc_source_map()

        for help_file in help_files:
            is_command = isinstance(help_file, CliCommandHelpFile)
            yield '.. cli{}:: {}'.format('command' if is_command else 'group', help_file.command if help_file.command else 'az') #it is top level group az if command is empty
            yield ''
            yield '{}:summary: {}'.format(INDENT, help_file.short_summary)
            yield '{}:description: {}'.format(INDENT, help_file.long_summary)
            if help_file.deprecate_info:
                yield '{}:deprecated: {}'.format(INDENT, help_file.deprecate_info._get_message(help_file.deprecate_info))
            if not is_command:
                top_group_name = help_file.command.split()[0] if help_file.command else 'az' 
                yield '{}:docsource: {}'.format(INDENT, doc_source_map[top_group_name] if top_group_name in doc_source_map else '')
            else:
                top_command_name = help_file.command.split()[0] if help_file.command else ''
                if top_command_name in doc_source_map:
                    yield '{}:docsource: {}'.format(INDENT, doc_source_map[top_command_name])
            yield ''

            if is_command and help_file.parameters:
               group_registry = ArgumentGroupRegistry(
                  [p.group_name for p in help_file.parameters if p.group_name]) 

               for arg in sorted(help_file.parameters,
                                key=lambda p: group_registry.get_group_priority(p.group_name)
                                + str(not p.required) + p.name):
                    yield '{}.. cliarg:: {}'.format(INDENT, arg.name)
                    yield ''
                    yield '{}:required: {}'.format(DOUBLEINDENT, arg.required)
                    if arg.deprecate_info:
                        yield '{}:deprecated: {}'.format(DOUBLEINDENT, arg.deprecate_info._get_message(arg.deprecate_info))
                    short_summary = arg.short_summary or ''
                    possible_values_index = short_summary.find(' Possible values include')
                    short_summary = short_summary[0:possible_values_index
                                                    if possible_values_index >= 0 else len(short_summary)]
                    short_summary = short_summary.strip()
                    yield '{}:summary: {}'.format(DOUBLEINDENT, short_summary)
                    yield '{}:description: {}'.format(DOUBLEINDENT, arg.long_summary)
                    if arg.choices:
                        yield '{}:values: {}'.format(DOUBLEINDENT, ', '.join(sorted([str(x) for x in arg.choices])))
                    if arg.default and arg.default != argparse.SUPPRESS:
                        try:
                            if arg.default.startswith(USER_HOME):
                                arg.default = arg.default.replace(USER_HOME, '~').replace('\\', '/')
                        except Exception:
                            pass
                        try:
                            arg.default = arg.default.replace("\\", "\\\\")
                        except Exception:
                            pass
                        yield '{}:default: {}'.format(DOUBLEINDENT, arg.default)
                    if arg.value_sources:
                        yield '{}:source: {}'.format(DOUBLEINDENT, ', '.join(_get_populator_commands(arg)))
                    yield ''
            yield ''
            if len(help_file.examples) > 0:
               for e in help_file.examples:
                  yield '{}.. cliexample:: {}'.format(INDENT, e.short_summary)
                  yield ''
                  yield DOUBLEINDENT + e.command.replace("\\", "\\\\")
                  yield ''
def run_linter(modules=None, rule_types=None, rules=None):

    require_azure_cli()

    from azure.cli.core import get_default_cli  # pylint: disable=import-error
    from azure.cli.core.file_util import (  # pylint: disable=import-error
        get_all_help, create_invoker_and_load_cmds_and_args)

    heading('CLI Linter')

    # needed to remove helps from azdev
    azdev_helps = helps.copy()
    exclusions = {}
    selected_modules = get_path_table(include_only=modules)

    if not selected_modules:
        raise CLIError('No modules selected.')

    selected_mod_names = list(selected_modules['mod'].keys()) + list(selected_modules['core'].keys()) + \
        list(selected_modules['ext'].keys())
    selected_mod_paths = list(selected_modules['mod'].values()) + list(selected_modules['core'].values()) + \
        list(selected_modules['ext'].values())

    if selected_mod_names:
        display('Modules: {}\n'.format(', '.join(selected_mod_names)))

    # collect all rule exclusions
    for path in selected_mod_paths:
        exclusion_path = os.path.join(path, 'linter_exclusions.yml')
        if os.path.isfile(exclusion_path):
            mod_exclusions = yaml.load(open(exclusion_path))
            exclusions.update(mod_exclusions)

    start = time.time()
    display('Initializing linter with command table and help files...')
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)

    stop = time.time()
    logger.info('Commands and help loaded in %i sec', stop - start)
    command_loader = az_cli.invocation.commands_loader

    # format loaded help
    loaded_help = {data.command: data for data in loaded_help if data.command}

    # load yaml help
    help_file_entries = {}
    for entry_name, help_yaml in helps.items():
        # ignore help entries from azdev itself, unless it also coincides
        # with a CLI or extension command name.
        if entry_name in azdev_helps and entry_name not in command_loader.command_table:
            continue
        help_entry = yaml.load(help_yaml)
        help_file_entries[entry_name] = help_entry

    # trim command table and help to just selected_modules
    command_loader, help_file_entries = filter_modules(
        command_loader, help_file_entries, modules=selected_mod_names)

    if not command_loader.command_table:
        raise CLIError('No commands selected to check.')

    # Instantiate and run Linter
    linter_manager = LinterManager(command_loader=command_loader,
                                   help_file_entries=help_file_entries,
                                   loaded_help=loaded_help,
                                   exclusions=exclusions,
                                   rule_inclusions=rules)

    subheading('Results')
    logger.info('Running linter: %i commands, %i help entries',
                len(command_loader.command_table), len(help_file_entries))
    exit_code = linter_manager.run(
        run_params=not rule_types or 'params' in rule_types,
        run_commands=not rule_types or 'commands' in rule_types,
        run_command_groups=not rule_types or 'command_groups'in rule_types,
        run_help_files_entries=not rule_types or 'help_entries' in rule_types)
    sys.exit(exit_code)
Example #15
0
 def _get_help_files(self, az_cli):
     create_invoker_and_load_cmds_and_args(az_cli)
     return get_all_help(az_cli)
Example #16
0
def main(args):
    from azure.cli.core import get_default_cli
    from azure.cli.core.file_util import get_all_help, create_invoker_and_load_cmds_and_args

    print('Initializing linter with command table and help files...')
    # setup CLI to enable command loader
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)
    command_table = az_cli.invocation.commands_loader.command_table

    # format loaded help
    loaded_help = {data.command: data for data in loaded_help if data.command}

    # load yaml help
    help_file_entries = {}
    for entry_name, help_yaml in helps.items():
        help_entry = yaml.load(help_yaml)
        help_file_entries[entry_name] = help_entry

    if not args.rule_types_to_run:
        args.rule_types_to_run = ['params', 'commands', 'command_groups', 'help_entries']

    # find rule exclusions and pass to linter manager
    from ..utilities.path import get_command_modules_paths
    exclusions = {}
    command_modules_paths = get_command_modules_paths()
    for _, path in get_command_modules_paths():
        exclusion_path = os.path.join(path, 'linter_exclusions.yml')
        if os.path.isfile(exclusion_path):
            mod_exclusions = yaml.load(open(exclusion_path))
            exclusions.update(mod_exclusions)

    # only run linter on modules specified
    if args.modules:
        allowed_module_paths = tuple(path for mod, path in command_modules_paths if mod in args.modules)
        for command_name, command in list(command_table.items()):
            # brute force way to remove all traces from excluded modules
            loader_cls = command.loader.__class__
            loader_file_path = inspect.getfile(loader_cls)
            if not loader_file_path.startswith(allowed_module_paths):
                del command_table[command_name]
                help_file_entries.pop(command_name, None)
                for group_name in _get_command_groups(command_name):
                    help_file_entries.pop(group_name, None)


    # Instantiate and run Linter
    linter_manager = LinterManager(command_table=command_table,
                                   help_file_entries=help_file_entries,
                                   loaded_help=loaded_help,
                                   exclusions=exclusions)
    exit_code = linter_manager.run(run_params='params' in args.rule_types_to_run,
                                   run_commands='commands' in args.rule_types_to_run,
                                   run_command_groups='command_groups' in args.rule_types_to_run,
                                   run_help_files_entries='help_entries' in args.rule_types_to_run,
                                   ci=args.ci)

    sys.exit(exit_code)
Example #17
0
def run_linter(modules=None,
               rule_types=None,
               rules=None,
               ci_exclusions=None,
               git_source=None,
               git_target=None,
               git_repo=None,
               include_whl_extensions=False,
               min_severity=None,
               save_global_exclusion=False):

    require_azure_cli()

    from azure.cli.core import get_default_cli  # pylint: disable=import-error
    from azure.cli.core.file_util import (  # pylint: disable=import-error
        get_all_help, create_invoker_and_load_cmds_and_args)

    heading('CLI Linter')

    # allow user to run only on CLI or extensions
    cli_only = modules == ['CLI']
    ext_only = modules == ['EXT']
    if cli_only or ext_only:
        modules = None

    # process severity option
    if min_severity:
        try:
            min_severity = LinterSeverity.get_linter_severity(min_severity)
        except ValueError:
            valid_choices = linter_severity_choices()
            raise CLIError(
                "Please specify a valid linter severity. It should be one of: {}"
                .format(", ".join(valid_choices)))

    # needed to remove helps from azdev
    azdev_helps = helps.copy()
    exclusions = {}
    selected_modules = get_path_table(
        include_only=modules, include_whl_extensions=include_whl_extensions)

    if cli_only:
        selected_modules['ext'] = {}
    if ext_only:
        selected_modules['mod'] = {}
        selected_modules['core'] = {}

    # used to upsert global exclusion
    update_global_exclusion = None
    if save_global_exclusion and (cli_only or ext_only):
        if cli_only:
            update_global_exclusion = 'CLI'
            if os.path.exists(
                    os.path.join(get_cli_repo_path(),
                                 'linter_exclusions.yml')):
                os.remove(
                    os.path.join(get_cli_repo_path(), 'linter_exclusions.yml'))
        elif ext_only:
            update_global_exclusion = 'EXT'
            for ext_path in get_ext_repo_paths():
                if os.path.exists(
                        os.path.join(ext_path, 'linter_exclusions.yml')):
                    os.remove(os.path.join(ext_path, 'linter_exclusions.yml'))

    # filter down to only modules that have changed based on git diff
    selected_modules = filter_by_git_diff(selected_modules, git_source,
                                          git_target, git_repo)

    if not any((selected_modules[x] for x in selected_modules)):
        raise CLIError('No modules selected.')

    selected_mod_names = list(selected_modules['mod'].keys()) + list(selected_modules['core'].keys()) + \
        list(selected_modules['ext'].keys())
    selected_mod_paths = list(selected_modules['mod'].values()) + list(selected_modules['core'].values()) + \
        list(selected_modules['ext'].values())

    if selected_mod_names:
        display('Modules: {}\n'.format(', '.join(selected_mod_names)))

    # collect all rule exclusions
    for path in selected_mod_paths:
        exclusion_path = os.path.join(path, 'linter_exclusions.yml')
        if os.path.isfile(exclusion_path):
            mod_exclusions = yaml.safe_load(open(exclusion_path))
            merge_exclusion(exclusions, mod_exclusions or {})

    global_exclusion_paths = [
        os.path.join(get_cli_repo_path(), 'linter_exclusions.yml')
    ]
    try:
        global_exclusion_paths.extend([
            os.path.join(path, 'linter_exclusions.yml')
            for path in (get_ext_repo_paths() or [])
        ])
    except CLIError:
        pass
    for path in global_exclusion_paths:
        if os.path.isfile(path):
            mod_exclusions = yaml.safe_load(open(path))
            merge_exclusion(exclusions, mod_exclusions or {})

    start = time.time()
    display('Initializing linter with command table and help files...')
    az_cli = get_default_cli()

    # load commands, args, and help
    create_invoker_and_load_cmds_and_args(az_cli)
    loaded_help = get_all_help(az_cli)

    stop = time.time()
    logger.info('Commands and help loaded in %i sec', stop - start)
    command_loader = az_cli.invocation.commands_loader

    # format loaded help
    loaded_help = {data.command: data for data in loaded_help if data.command}

    # load yaml help
    help_file_entries = {}
    for entry_name, help_yaml in helps.items():
        # ignore help entries from azdev itself, unless it also coincides
        # with a CLI or extension command name.
        if entry_name in azdev_helps and entry_name not in command_loader.command_table:
            continue
        help_entry = yaml.safe_load(help_yaml)
        help_file_entries[entry_name] = help_entry

    # trim command table and help to just selected_modules
    command_loader, help_file_entries = filter_modules(
        command_loader,
        help_file_entries,
        modules=selected_mod_names,
        include_whl_extensions=include_whl_extensions)

    if not command_loader.command_table:
        raise CLIError('No commands selected to check.')

    # Instantiate and run Linter
    linter_manager = LinterManager(
        command_loader=command_loader,
        help_file_entries=help_file_entries,
        loaded_help=loaded_help,
        exclusions=exclusions,
        rule_inclusions=rules,
        use_ci_exclusions=ci_exclusions,
        min_severity=min_severity,
        update_global_exclusion=update_global_exclusion)

    subheading('Results')
    logger.info('Running linter: %i commands, %i help entries',
                len(command_loader.command_table), len(help_file_entries))
    exit_code = linter_manager.run(run_params=not rule_types
                                   or 'params' in rule_types,
                                   run_commands=not rule_types
                                   or 'commands' in rule_types,
                                   run_command_groups=not rule_types
                                   or 'command_groups' in rule_types,
                                   run_help_files_entries=not rule_types
                                   or 'help_entries' in rule_types)
    sys.exit(exit_code)