diff options
author | David Bradford <david.bradford@mongodb.com> | 2019-03-01 09:33:31 -0500 |
---|---|---|
committer | David Bradford <david.bradford@mongodb.com> | 2019-03-01 10:23:48 -0500 |
commit | 6b601f1005a683fb5fd6050b8ecb618c49fd6e59 (patch) | |
tree | ad50633a4355104c046edc35db50a98f5fbb1e5c /buildscripts | |
parent | 31de5655f1ea195748484a65c067beedf773c883 (diff) | |
download | mongo-6b601f1005a683fb5fd6050b8ecb618c49fd6e59.tar.gz |
SERVER-39413: Add script to analyze evergreen task tag usage
Diffstat (limited to 'buildscripts')
-rw-r--r-- | buildscripts/ciconfig/evergreen.py | 5 | ||||
-rwxr-xr-x | buildscripts/evergreen_task_tags.py | 91 | ||||
-rw-r--r-- | buildscripts/tests/ciconfig/test_evergreen.py | 74 | ||||
-rw-r--r-- | buildscripts/tests/test_evergreen_task_tags.py | 63 |
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) |