Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only run Travis tests for plugins either added or modified by PR #36

Merged
merged 49 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
efd5223
add option to specify more than one test file
Jun 21, 2023
700a8bd
run tests of plugins changed by pr
Jun 22, 2023
d415099
Merge branch 'main' of https://github.com/brain-score/core into kvf/r…
Jun 22, 2023
2f3931c
run all test files in plugin dir
Jun 22, 2023
3f448f6
cleanup
Jun 22, 2023
337d30b
add notification that tests are running
Jun 22, 2023
503c52e
get_scoring_info -> get_plugin_info
Jun 22, 2023
146da61
Documentation
kvfairchild Jun 27, 2023
b066cbe
Documentation
kvfairchild Jun 27, 2023
e5f5162
cleanup
Jun 27, 2023
4b684c6
Documentation
kvfairchild Jun 27, 2023
48cee74
Documentation
kvfairchild Jun 27, 2023
e65915b
Refactor
kvfairchild Jun 27, 2023
18f9a49
Refactor
kvfairchild Jun 27, 2023
d22aa18
cleanup
Jun 27, 2023
ef97d2d
specify path for git cmd
Jun 27, 2023
98c0965
add plugin change parsing tests
Jun 29, 2023
f3bc366
travis TEST
Jun 29, 2023
7303912
change test SHAs
Jun 29, 2023
38d0e6a
change test SHAs
Jun 29, 2023
78ddb63
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
21be65d
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
ddf5c65
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
4d44070
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
19a04f8
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
477209b
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
bb0b1ab
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
8920368
Update brainscore_core/plugin_management/parse_plugin_changes.py
kvfairchild Jul 3, 2023
dd15a43
Update tests/test_plugin_management/test_parse_plugin_changes.py
kvfairchild Jul 3, 2023
0d7a68b
Update tests/test_plugin_management/test_parse_plugin_changes.py
kvfairchild Jul 3, 2023
f63de37
Update tests/test_plugin_management/test_parse_plugin_changes.py
kvfairchild Jul 3, 2023
ce47a12
Update tests/test_plugin_management/test_parse_plugin_changes__brains…
kvfairchild Jul 3, 2023
abdfe12
Update tests/test_plugin_management/test_parse_plugin_changes__brains…
kvfairchild Jul 3, 2023
3e64802
Update tests/test_plugin_management/test_parse_plugin_changes__brains…
kvfairchild Jul 3, 2023
fefec4d
Update brainscore_core/plugin_management/test_plugins.py
kvfairchild Jul 3, 2023
f601d0e
add comment re: printing output
Jul 6, 2023
31c9ee5
var naming
Jul 6, 2023
bb1a64f
test git access
Jul 6, 2023
986017f
test git access
Jul 6, 2023
13b4635
exclude pr_only tests
Jul 19, 2023
2495b3a
change conditional to type
Aug 4, 2023
dfcbbe3
split jobs
Aug 6, 2023
1bf2229
format
Aug 6, 2023
18af27c
format
Aug 6, 2023
f8c13f4
stage jobs
Aug 6, 2023
95942a7
YAML Additions (#38)
qasim-at-tci Aug 9, 2023
6b0e5e9
mark test_get_all_changed_files pr_only
Aug 10, 2023
d6a20b5
Merge branch 'kvf/reduce-language-test-time' of https://github.com/br…
Aug 10, 2023
1fbc3a5
add pr_only to markers
Aug 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions brainscore_core/plugin_management/parse_plugin_changes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import re
import subprocess
import sys
from pathlib import Path
from typing import List, Tuple

from .test_plugins import run_args

PLUGIN_DIRS = ['models', 'benchmarks', 'data', 'metrics']


def get_all_changed_files(commit_SHA: str) -> List[str]:
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
cmd = f'git diff --name-only main {commit_SHA}'
files_changed_bytes = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE).stdout.splitlines()
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
files_changed = [f.decode() for f in files_changed_bytes]

return files_changed


def get_changed_plugin_files(changed_files: str) -> Tuple[List[str], List[str]]:
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
changed_files_list = changed_files.split() if type(changed_files) == str else changed_files

changed_plugin_files = []
changed_non_plugin_files = []

for f in changed_files_list:
subdir = f.split('/')[1] if len(f.split('/')) > 1 else None
if not any(plugin_dir == subdir for plugin_dir in PLUGIN_DIRS):
changed_non_plugin_files.append(f)
else:
changed_plugin_files.append(f)

return changed_plugin_files, changed_non_plugin_files
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved


def is_automergeable(plugin_info_dict: dict, num_changed_non_plugin_files: int):
"""
Stores `plugin_info_dict['is_plugin_only']` `"True"` or `"False"`
depending on whether there are any changed non-plugin files.
"""
plugin_info_dict["is_plugin_only"] = "False" if num_changed_non_plugin_files > 0 else "True"
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved


def _plugin_name_from_path(path_relative_to_library: str) -> str:
"""
Returns the name of the plugin from the given path.
E.g. `_plugin_name_from_path("brainscore_vision/models/mymodel")` will return `"mymodel"`.
"""
return path_relative_to_library.split('/')[2]


def get_changed_plugin_paths(plugin_info_dict: dict, changed_plugin_files: List[str], domain_root: str):
"""
Adds full path (rel. to library) of all changed plugin directories for each plugin_type to plugin_info_dict
"""
plugin_info_dict["changed_plugins"] = {}
for plugin_type in PLUGIN_DIRS:
plugin_type_path = f'{domain_root}/{plugin_type}/'
changed_plugin_paths = [fpath for fpath in changed_plugin_files if fpath.startswith(plugin_type_path)]
plugin_info_dict["changed_plugins"][plugin_type] = list(set([_plugin_name_from_path(fname)
for fname in changed_plugin_paths if f'/{plugin_type}/' in fname]))
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved


def _get_plugin_ids(plugin_type: str, new_plugin_dirs: List[str], domain_root: str) -> List[str]:
"""
Searches all __init.py__ files in `new_plugin_dirs` of `plugin_type` for registered plugins.
Returns list of identifiers for each registered plugin.
"""
plugin_ids = []

for plugin_dirname in new_plugin_dirs:
init_file = Path(f'{domain_root}/{plugin_type}/{plugin_dirname}/__init__.py')
with open(init_file) as f:
registry_name = plugin_type.strip(
's') + '_registry' # remove plural and determine variable name, e.g. "models" -> "model_registry"
plugin_registrations = [line for line in f if f"{registry_name}["
in line.replace('\"', '\'')]
for line in plugin_registrations:
result = re.search(f'{registry_name}\[.*\]', line)
identifier = result.group(0)[len(registry_name) + 2:-2] # remove brackets and quotes
plugin_ids.append(identifier)

return plugin_ids


def parse_plugin_changes(commit_SHA: str, domain_root: str) -> dict:
"""
Return information about which files changed by the invoking PR (compared against main) belong to plugins

:param commit_SHA: SHA of the invoking PR
:param domain_root: the root package directory of the repo where the PR originates, either 'brainscore' (vision) or 'brainscore_language' (language)
"""
plugin_info_dict = {}
changed_files = get_all_changed_files(commit_SHA)
changed_plugin_files, changed_non_plugin_files = get_changed_plugin_files(changed_files)
is_automergeable(plugin_info_dict, len(changed_non_plugin_files))
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
get_changed_plugin_paths(plugin_info_dict, changed_plugin_files, domain_root)
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved

return plugin_info_dict


def get_plugin_info(commit_SHA: str, domain_root: str):
"""
If any model or benchmark files changed, get plugin ids and set run_score to "True"
Otherwise set else "False"
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
"""
plugin_info_dict = parse_plugin_changes(commit_SHA, domain_root)

scoring_plugin_types = ("models", "benchmarks")
plugins_to_score = [plugin_info_dict["changed_plugins"][plugin_type] for plugin_type in scoring_plugin_types]

if len(plugins_to_score) > 0:
plugin_info_dict["run_score"] = "True"
for plugin_type in scoring_plugin_types:
scoring_plugin_ids = _get_plugin_ids(plugin_type, plugin_info_dict["changed_plugins"][plugin_type], domain_root)
plugin_info_dict[f'new_{plugin_type}'] = ' '.join(scoring_plugin_ids)
else:
plugin_info_dict["run_score"] = "False"

print(plugin_info_dict)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
print(plugin_info_dict)
_logger.debug(f"plugin_info_dict: {plugin_info_dict}")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or delete if not worth debugging, along with the suggested import logging

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be printed, not logged to debug, as that's how the calling functions access the output.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see -- can you add a comment to the code to explain? I'm worried I'll come across this in a year and again think this should be logged 😄



def run_changed_plugin_tests(commit_SHA: str, domain_root: str):
"""
Initiates run of all tests in each changed plugin directory
"""
plugin_info_dict = parse_plugin_changes(commit_SHA, domain_root)

tests_to_run = []
for plugin_type in plugin_info_dict["changed_plugins"]:
changed_plugins = plugin_info_dict["changed_plugins"][plugin_type]
for plugin_dirname in changed_plugins:
root = Path(f'{domain_root}/{plugin_type}/{plugin_dirname}')
for filepath in root.rglob(r'test*.py'):
tests_to_run.append(str(filepath))

print("Running tests for new or modified plugins...")
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
run_args('brainscore_language', tests_to_run)
16 changes: 9 additions & 7 deletions brainscore_core/plugin_management/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import warnings
import yaml
from pathlib import Path
from typing import Dict, Union
from typing import Dict, Union, List

from .environment_manager import EnvironmentManager

Expand Down Expand Up @@ -108,21 +108,23 @@ def run_all_tests(root_directory: Path, results: Dict):
plugin_test_runner()


def run_args(root_directory: Union[Path, str], test_file: Union[None, str] = None, test: Union[None, str] = None):
def run_args(root_directory: Union[Path, str], test_files: Union[None, List[str]] = None, test: Union[None, str] = None):
"""
Run single specified test or all tests for each plugin.

:param root_directory: the directory containing all plugin types, e.g. `/local/brain-score_language/`
:param test_file: path of target test file (optional)
:param test_files: List of paths of target test files (optional)
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved
:param test: name of test to run (optional)
"""
results = {}
if not test_file:
if not test_files:
run_all_tests(root_directory=Path(root_directory), results=results)
elif test_file and Path(test_file).exists():
run_specified_tests(root_directory=Path(root_directory), test_file=test_file, results=results, test=test)
else:
warnings.warn("Test file not found.")
for test_file in test_files:
if Path(test_file).exists():
run_specified_tests(root_directory=Path(root_directory), test_file=test_file, results=results, test=test)
else:
warnings.warn(f"Test file {test_file} not found.")
kvfairchild marked this conversation as resolved.
Show resolved Hide resolved

plugins_with_errors = {k: v for k, v in results.items() if (v != 0) and (v != 5)}
num_plugins_failed = len(plugins_with_errors)
Expand Down