diff options
author | Mikhail Shchatko <mikhail.shchatko@mongodb.com> | 2021-07-22 10:36:16 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-07-22 14:25:55 +0000 |
commit | 73b4bcdabaddc1e2b5b59a19e0d7bae969a85669 (patch) | |
tree | ad9be2cc61d7fb1990f3d3b58caba2a94571af69 /buildscripts/resmokelib | |
parent | adecbaa346c6e8d8dbf292a3c08aa22b0350b62e (diff) | |
download | mongo-73b4bcdabaddc1e2b5b59a19e0d7bae969a85669.tar.gz |
SERVER-58613 Add list-tags subcommand to resmoke
Diffstat (limited to 'buildscripts/resmokelib')
-rw-r--r-- | buildscripts/resmokelib/run/__init__.py | 45 | ||||
-rw-r--r-- | buildscripts/resmokelib/run/list_tags.py | 66 |
2 files changed, 110 insertions, 1 deletions
diff --git a/buildscripts/resmokelib/run/__init__.py b/buildscripts/resmokelib/run/__init__.py index ab624e9027b..ede083f8454 100644 --- a/buildscripts/resmokelib/run/__init__.py +++ b/buildscripts/resmokelib/run/__init__.py @@ -37,6 +37,7 @@ from buildscripts.resmokelib.core import process from buildscripts.resmokelib.core import jasper_process from buildscripts.resmokelib.plugin import PluginInterface, Subcommand from buildscripts.resmokelib.run import runtime_recorder +from buildscripts.resmokelib.run import list_tags from buildscripts.resmokelib.run.runtime_recorder import compare_start_time _INTERNAL_OPTIONS_TITLE = "Internal Options" @@ -121,6 +122,8 @@ class TestRunner(Subcommand): # pylint: disable=too-many-instance-attributes self.list_suites() elif self.__command == "find-suites": self.find_suites() + elif self.__command == "list-tags": + self.list_tags() elif config.DRY_RUN == "tests": self.dry_run() else: @@ -146,6 +149,34 @@ class TestRunner(Subcommand): # pylint: disable=too-many-instance-attributes self._resmoke_logger.info("%s will be run by the following suite(s): %s", test, suite_names) + def list_tags(self): + """List the tags and its documentation available in the suites.""" + tag_docs = {} + out_tag_names = [] + for suite_name in suitesconfig.get_named_suites(): + suite_file = config.NAMED_SUITES.get(suite_name, "") + tags_blocks = list_tags.get_tags_blocks(suite_file) + + for tags_block in tags_blocks: + splitted_tags_block = list_tags.split_into_tags(tags_block) + + for single_tag_block in splitted_tags_block: + tag_name, doc = list_tags.get_tag_doc(single_tag_block) + + if tag_name and (tag_name not in tag_docs + or len(doc) > len(tag_docs[tag_name])): + tag_docs[tag_name] = doc + + if suite_name in config.SUITE_FILES: # pylint: disable=unsupported-membership-test + out_tag_names.append(tag_name) + + if config.SUITE_FILES == [config.DEFAULTS["suite_files"]]: + out_tag_docs = tag_docs + else: + out_tag_docs = {tag: doc for tag, doc in tag_docs.items() if tag in out_tag_names} + + self._resmoke_logger.info("Found tags in suites:%s", list_tags.make_output(out_tag_docs)) + @staticmethod def _find_suites_by_test(suites): """ @@ -562,6 +593,7 @@ class RunPlugin(PluginInterface): RunPlugin._add_run(subparsers) RunPlugin._add_list_suites(subparsers) RunPlugin._add_find_suites(subparsers) + RunPlugin._add_list_tags(subparsers) def parse(self, subcommand, parser, parsed_args, **kwargs): """ @@ -573,7 +605,7 @@ class RunPlugin(PluginInterface): :param kwargs: additional args :return: None or a Subcommand """ - if subcommand in ('find-suites', 'list-suites', 'run'): + if subcommand in ('find-suites', 'list-suites', 'list-tags', 'run'): configure_resmoke.validate_and_update_config(parser, parsed_args) if config.EVERGREEN_TASK_ID is not None: return TestRunnerEvg(subcommand, **kwargs) @@ -1101,6 +1133,17 @@ class RunPlugin(PluginInterface): parser.add_argument("test_files", metavar="TEST_FILES", nargs="*", help="Explicit test files to run") + @classmethod + def _add_list_tags(cls, subparsers): + """Create and add the parser for the list-tags subcommand.""" + parser = subparsers.add_parser( + "list-tags", help="Lists the tags and their documentation available in the suites.") + parser.set_defaults(logger_file="console") + parser.add_argument( + "--suites", dest="suite_files", metavar="SUITE1,SUITE2", + help=("Comma separated list of suite names to get tags from." + " All suites are used if unspecified.")) + def to_local_args(input_args=None): # pylint: disable=too-many-branches,too-many-locals """ diff --git a/buildscripts/resmokelib/run/list_tags.py b/buildscripts/resmokelib/run/list_tags.py new file mode 100644 index 00000000000..05ea6725b83 --- /dev/null +++ b/buildscripts/resmokelib/run/list_tags.py @@ -0,0 +1,66 @@ +"""Functions to parse suite yaml files to get tags and comments around them.""" + +import textwrap +import re + + +def parse_tags_blocks(suite): + """Get substrings from the suite string where tags are defined.""" + yaml_tag_keys = ["include_with_any_tags", "exclude_with_any_tags"] + yaml_tag_keys_regex = "|".join(yaml_tag_keys) + all_tags_regex = re.compile(rf"(({yaml_tag_keys_regex}):\n(\s*(-|#)\s*.*)*)") + return [tag_block[0] for tag_block in all_tags_regex.findall(suite)] + + +def get_tags_blocks(suite_file): + """Get substrings from the suite file where tags are defined.""" + tags_blocks = [] + try: + with open(suite_file, "r") as fh: + tags_blocks = parse_tags_blocks(fh.read()) + except FileNotFoundError: + pass + return tags_blocks + + +def split_into_tags(tags_block): + """Split tag block into lines representing each tag.""" + tags_block_lines = tags_block.split("\n")[1:] + splitted_tags_block = [] + i = 0 + for line in tags_block_lines: + if len(splitted_tags_block) <= i: + splitted_tags_block.append([]) + line = line.strip() + splitted_tags_block[i].append(line) + if line.startswith("-"): + i += 1 + return splitted_tags_block + + +def get_tag_doc(single_tag_block): + """Get tag name with its documentation string.""" + tag_name = "" + doc = "" + for line in single_tag_block: + if line.startswith("#"): + doc += re.sub(r"^#+\s*", "", line).strip() + "\n" + elif line.startswith("-"): + if "#" in line: + tag_name, comment = line.split("#", 1) + tag_name = tag_name.replace("- ", "").strip() + doc += comment.strip() + else: + tag_name = line.replace("- ", "").strip() + doc = doc.strip() + return tag_name, doc + + +def make_output(tag_docs): + """Make output string.""" + output = "" + for tag, doc in sorted(tag_docs.items()): + newline = "\n" + wrapped_doc = textwrap.indent(doc, '\t') + output = f"{output}{newline}{tag}:{newline}{wrapped_doc}" + return output |