summaryrefslogtreecommitdiff
path: root/buildscripts
diff options
context:
space:
mode:
authorDavid Bradford <david.bradford@mongodb.com>2019-03-01 09:33:31 -0500
committerDavid Bradford <david.bradford@mongodb.com>2019-03-01 10:23:48 -0500
commit6b601f1005a683fb5fd6050b8ecb618c49fd6e59 (patch)
treead50633a4355104c046edc35db50a98f5fbb1e5c /buildscripts
parent31de5655f1ea195748484a65c067beedf773c883 (diff)
downloadmongo-6b601f1005a683fb5fd6050b8ecb618c49fd6e59.tar.gz
SERVER-39413: Add script to analyze evergreen task tag usage
Diffstat (limited to 'buildscripts')
-rw-r--r--buildscripts/ciconfig/evergreen.py5
-rwxr-xr-xbuildscripts/evergreen_task_tags.py91
-rw-r--r--buildscripts/tests/ciconfig/test_evergreen.py74
-rw-r--r--buildscripts/tests/test_evergreen_task_tags.py63
4 files changed, 210 insertions, 23 deletions
diff --git a/buildscripts/ciconfig/evergreen.py b/buildscripts/ciconfig/evergreen.py
index 1cbe11fd320..55818b73322 100644
--- a/buildscripts/ciconfig/evergreen.py
+++ b/buildscripts/ciconfig/evergreen.py
@@ -140,6 +140,11 @@ class Task(object):
return ResmokeArgs.get_arg(args, "suites")
return None
+ @property
+ def tags(self):
+ """Get a set of tags this task has been marked with."""
+ return set(self.raw.get("tags", []))
+
def __str__(self):
return self.name
diff --git a/buildscripts/evergreen_task_tags.py b/buildscripts/evergreen_task_tags.py
new file mode 100755
index 00000000000..8144f048e51
--- /dev/null
+++ b/buildscripts/evergreen_task_tags.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+"""Script to gather information about how tags are used in evergreen tasks."""
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import argparse
+import os
+import sys
+
+# Get relative imports to work when the package is not installed on the PYTHONPATH.
+if __name__ == "__main__" and __package__ is None:
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from buildscripts.ciconfig import evergreen # pylint: disable=wrong-import-position
+
+DEFAULT_EVERGREEN_FILE = "etc/evergreen.yml"
+
+
+def parse_command_line():
+ """Parse command line options."""
+ parser = argparse.ArgumentParser(description=main.__doc__)
+
+ parser.add_argument("--list-tags", action="store_true", default=False,
+ help="List all tags used by tasks in evergreen yml.")
+ parser.add_argument("--tasks-for-tag", type=str, default=None,
+ help="List all tasks that use the given tag.")
+ parser.add_argument("--evergreen-file", type=str, default=DEFAULT_EVERGREEN_FILE,
+ help="Location of evergreen file.")
+
+ options = parser.parse_args()
+
+ return options
+
+
+def get_all_task_tags(evg_config):
+ """Get all task tags used in the evergreen configuration."""
+ if evg_config.tasks:
+ return sorted(set.union(*[task.tags for task in evg_config.tasks]))
+ return set()
+
+
+def list_all_tags(evg_config):
+ """
+ Print all task tags found in the evergreen configuration.
+
+ :param evg_config: evergreen configuration.
+ """
+ all_tags = get_all_task_tags(evg_config)
+ for tag in all_tags:
+ print(tag)
+
+
+def get_tasks_with_tag(evg_config, tag):
+ """
+ Get all tasks marked with the given tag in the evergreen configuration.
+
+ :param evg_config: evergreen configuration.
+ :param tag: tag to search for.
+ :return: list of tasks marked with the given tag.
+ """
+ return sorted([task.name for task in evg_config.tasks if tag in task.tags])
+
+
+def list_tasks_with_tag(evg_config, tag):
+ """
+ Print all tasks that are marked with the given tag.
+
+ :param evg_config: evergreen configuration.
+ :param tag: tag to search for.
+ """
+ task_list = get_tasks_with_tag(evg_config, tag)
+ for task in task_list:
+ print(task)
+
+
+def main():
+ """Gather information about how tags are used in evergreen tasks."""
+ options = parse_command_line()
+
+ evg_config = evergreen.parse_evergreen_file(options.evergreen_file)
+
+ if options.list_tags:
+ list_all_tags(evg_config)
+
+ if options.tasks_for_tag:
+ list_tasks_with_tag(evg_config, options.tasks_for_tag)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/buildscripts/tests/ciconfig/test_evergreen.py b/buildscripts/tests/ciconfig/test_evergreen.py
index 8fd3d25ed9a..3fb06c7a67c 100644
--- a/buildscripts/tests/ciconfig/test_evergreen.py
+++ b/buildscripts/tests/ciconfig/test_evergreen.py
@@ -76,12 +76,12 @@ class TestTask(unittest.TestCase):
def test_from_dict(self):
task_dict = {
- "name":
- "compile", "depends_on": [],
+ "name": "compile",
+ "depends_on": [],
"commands": [{"func": "fetch source"}, {"func": "run a task that passes"},
{"func": "run a function with an arg", "vars": {"foobar": "TESTING: ONE"}},
{"func": "run a function with an arg", "vars": {"foobar": "TESTING: TWO"}}]
- }
+ } # yapf: disable
task = _evergreen.Task(task_dict)
self.assertEqual("compile", task.name)
@@ -90,12 +90,12 @@ class TestTask(unittest.TestCase):
def test_resmoke_args(self):
task_dict = {
- "name":
- "jsCore", "commands": [{
- "func": "run tests",
- "vars": {"resmoke_args": "--suites=core --shellWriteMode=commands"}
- }]
- }
+ "name": "jsCore",
+ "commands": [{
+ "func": "run tests",
+ "vars": {"resmoke_args": "--suites=core --shellWriteMode=commands"}
+ }]
+ } # yapf: disable
task = _evergreen.Task(task_dict)
self.assertEqual("--suites=core --shellWriteMode=commands", task.resmoke_args)
@@ -103,12 +103,12 @@ class TestTask(unittest.TestCase):
def test_resmoke_args_gen(self):
task_dict = {
- "name":
- "jsCore", "commands": [{
- "func": "generate resmoke tasks",
- "vars": {"task": "core", "resmoke_args": "--shellWriteMode=commands"}
- }]
- }
+ "name": "jsCore",
+ "commands": [{
+ "func": "generate resmoke tasks",
+ "vars": {"task": "core", "resmoke_args": "--shellWriteMode=commands"}
+ }]
+ } # yapf: disable
task = _evergreen.Task(task_dict)
self.assertEqual("--suites=core --shellWriteMode=commands", task.resmoke_args)
@@ -116,19 +116,47 @@ class TestTask(unittest.TestCase):
def test_resmoke_args_gen_with_suite(self):
task_dict = {
- "name":
- "jsCore", "commands": [{
- "func": "generate resmoke tasks", "vars": {
- "task": "jsCore", "suite": "core",
- "resmoke_args": "--shellWriteMode=commands"
- }
- }]
- }
+ "name": "jsCore",
+ "commands": [{
+ "func": "generate resmoke tasks", "vars": {
+ "task": "jsCore", "suite": "core",
+ "resmoke_args": "--shellWriteMode=commands"
+ }
+ }]
+ } # yapf: disable
task = _evergreen.Task(task_dict)
self.assertEqual("--suites=core --shellWriteMode=commands", task.resmoke_args)
self.assertEqual("core", task.resmoke_suite)
+ def test_tags_with_no_tags(self):
+ task_dict = {
+ "name": "jsCore",
+ "commands": [{
+ "func": "run tests",
+ "vars": {"resmoke_args": "--suites=core --shellWriteMode=commands"}
+ }]
+ } # yapf: disable
+ task = _evergreen.Task(task_dict)
+
+ self.assertEqual(0, len(task.tags))
+
+ def test_tags_with_tags(self):
+ task_dict = {
+ "name": "jsCore",
+ "tags": ["tag 0", "tag 1", "tag 2"],
+ "commands": [{
+ "func": "run tests",
+ "vars": {"resmoke_args": "--suites=core --shellWriteMode=commands"}
+ }]
+ } # yapf: disable
+ task = _evergreen.Task(task_dict)
+
+ tag_set = task.tags
+ for tag in task_dict["tags"]:
+ self.assertIn(tag, tag_set)
+ self.assertEqual(len(task_dict["tags"]), len(tag_set))
+
class TestTaskGroup(unittest.TestCase):
"""Unit tests for the TaskGroup class."""
diff --git a/buildscripts/tests/test_evergreen_task_tags.py b/buildscripts/tests/test_evergreen_task_tags.py
new file mode 100644
index 00000000000..582bd93c87b
--- /dev/null
+++ b/buildscripts/tests/test_evergreen_task_tags.py
@@ -0,0 +1,63 @@
+"""Unit tests for the evergreen_task_tags script."""
+
+from __future__ import absolute_import
+
+import unittest
+
+from mock import MagicMock
+
+from buildscripts import evergreen_task_tags as ett
+
+# pylint: disable=missing-docstring,no-self-use
+
+
+def gen_tag_set(prefix, size):
+ return set([prefix + " " + str(index) for index in range(size)])
+
+
+class TestGetAllTaskTags(unittest.TestCase):
+ def test_with_no_tasks(self):
+ evg_config_mock = MagicMock(tasks=[])
+ self.assertEqual(0, len(ett.get_all_task_tags(evg_config_mock)))
+
+ def test_with_no_tags(self):
+ n_tasks = 5
+ task_list_mock = [MagicMock(tags=set()) for _ in range(n_tasks)]
+ evg_config_mock = MagicMock(tasks=task_list_mock)
+ self.assertEqual(0, len(ett.get_all_task_tags(evg_config_mock)))
+
+ def test_with_some_tags(self):
+ task_prefixes = ["b", "a", "q", "v"]
+ n_tags = 3
+ task_list_mock = [MagicMock(tags=gen_tag_set(prefix, n_tags)) for prefix in task_prefixes]
+ evg_config_mock = MagicMock(tasks=task_list_mock)
+
+ tag_list = ett.get_all_task_tags(evg_config_mock)
+ self.assertEqual(n_tags * len(task_prefixes), len(tag_list))
+ self.assertEqual(sorted(tag_list), tag_list)
+
+
+class TestGetTasksWithTag(unittest.TestCase):
+ def test_with_no_tasks(self):
+ evg_config_mock = MagicMock(tasks=[])
+ self.assertEqual(0, len(ett.get_tasks_with_tag(evg_config_mock, 'tag')))
+
+ def test_with_no_tags(self):
+ n_tasks = 5
+ task_list_mock = [MagicMock(tags=set()) for _ in range(n_tasks)]
+ evg_config_mock = MagicMock(tasks=task_list_mock)
+ self.assertEqual(0, len(ett.get_tasks_with_tag(evg_config_mock, 'tag')))
+
+ def test_with_one_tag_each(self):
+ task_prefixes = ["b", "a", "b", "v"]
+ n_tags = 3
+ task_list_mock = [MagicMock(tags=gen_tag_set(prefix, n_tags)) for prefix in task_prefixes]
+ for index, task in enumerate(task_list_mock):
+ task.name = "task " + str(index)
+ evg_config_mock = MagicMock(tasks=task_list_mock)
+
+ task_list = ett.get_tasks_with_tag(evg_config_mock, "b 0")
+ self.assertIn("task 0", task_list)
+ self.assertIn("task 2", task_list)
+ self.assertEqual(2, len(task_list))
+ self.assertEqual(sorted(task_list), task_list)