Exemple #1
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)
Exemple #2
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)
Exemple #3
0
def load_help_files(data):
    """ loads all the extra information from help files """
    for command_name, help_yaml in helps.items():

        help_entry = yaml.load(help_yaml)
        try:
            help_type = help_entry['type']
        except KeyError:
            continue

        # if there is extra help for this command but it's not reflected in the command table
        if command_name not in data and help_type == 'command':
            logger.debug('Command: %s not found in command table',
                         command_name)
            continue

        short_summary = help_entry.get('short-summary')
        short_summary = short_summary() if callable(
            short_summary) else short_summary
        if short_summary and help_type == 'command':
            data[command_name]['help'] = short_summary
        else:
            # must be a command group or sub-group
            data[command_name] = {'help': short_summary}
            continue

        if 'parameters' in help_entry:
            for param in help_entry['parameters']:
                # this could fail if the help file and options list are not in the same order
                param_name = param['name'].split()[0]

                if param_name not in data[command_name]['parameters']:
                    logger.debug('Command %s does not have parameter: %s',
                                 command_name, param_name)
                    continue

                if 'short-summary' in param:
                    data[command_name]['parameters'][param_name][
                        'help'] = param["short-summary"]

        if 'examples' in help_entry:
            data[command_name]['examples'] = [[
                example['name'], example['text']
            ] for example in help_entry['examples']]
def load_help_files(data):
    """ loads all the extra information from help files """
    for command_name, help_yaml in helps.items():

        help_entry = yaml.safe_load(help_yaml)
        try:
            help_type = help_entry['type']
        except KeyError:
            continue

        # if there is extra help for this command but it's not reflected in the command table
        if command_name not in data and help_type == 'command':
            logger.debug('Command: %s not found in command table', command_name)
            continue

        short_summary = help_entry.get('short-summary')
        if short_summary and help_type == 'command':
            data[command_name]['help'] = short_summary
        else:
            # must be a command group or sub-group
            data[command_name] = {'help': short_summary}
            continue

        if 'parameters' in help_entry:
            for param in help_entry['parameters']:
                # this could fail if the help file and options list are not in the same order
                param_name = param['name'].split()[0]

                if param_name not in data[command_name]['parameters']:
                    logger.debug('Command %s does not have parameter: %s', command_name, param_name)
                    continue

                if 'short-summary' in param:
                    data[command_name]['parameters'][param_name]['help'] = param["short-summary"]

        if 'examples' in help_entry:
            data[command_name]['examples'] = [[example['name'], example['text']]
                                              for example in help_entry['examples']]
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)
Exemple #6
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)
Exemple #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_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)