summaryrefslogtreecommitdiff
path: root/buildscripts/resmokelib
diff options
context:
space:
mode:
authorMikhail Shchatko <mikhail.shchatko@mongodb.com>2021-07-22 10:36:16 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-07-22 14:25:55 +0000
commit73b4bcdabaddc1e2b5b59a19e0d7bae969a85669 (patch)
treead9be2cc61d7fb1990f3d3b58caba2a94571af69 /buildscripts/resmokelib
parentadecbaa346c6e8d8dbf292a3c08aa22b0350b62e (diff)
downloadmongo-73b4bcdabaddc1e2b5b59a19e0d7bae969a85669.tar.gz
SERVER-58613 Add list-tags subcommand to resmoke
Diffstat (limited to 'buildscripts/resmokelib')
-rw-r--r--buildscripts/resmokelib/run/__init__.py45
-rw-r--r--buildscripts/resmokelib/run/list_tags.py66
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