From cfa71f3776a1e07b151a7ba9ae2afecef663f268 Mon Sep 17 00:00:00 2001 From: Mikhail Shchatko Date: Wed, 14 Aug 2024 17:49:24 +0300 Subject: [PATCH] SERVER-93515 Apply new VP and Overall quotas for the code lockdown (#26106) GitOrigin-RevId: 56309603a6e1d87c9caa8b78b3208104d9e76866 --- .../monitor_build_status/bfs_report.py | 54 ++- buildscripts/monitor_build_status/cli.py | 249 ++++--------- .../code_lockdown_config.py | 5 +- .../monitor_build_status/jira_service.py | 12 +- .../monitor_build_status/test_bfs_report.py | 48 +-- .../tests/monitor_build_status/test_cli.py | 348 ++---------------- .../monitor_build_status/test_jira_service.py | 29 +- etc/code_lockdown.yml | 47 ++- .../tasks/misc_tasks.yml | 55 --- evergreen/monitor_build_status_exit.sh | 16 - evergreen/monitor_build_status_run.sh | 8 +- 11 files changed, 211 insertions(+), 660 deletions(-) delete mode 100644 evergreen/monitor_build_status_exit.sh diff --git a/buildscripts/monitor_build_status/bfs_report.py b/buildscripts/monitor_build_status/bfs_report.py index 24e5772b0e3..b6348d2f3b4 100644 --- a/buildscripts/monitor_build_status/bfs_report.py +++ b/buildscripts/monitor_build_status/bfs_report.py @@ -1,5 +1,6 @@ from __future__ import annotations +from datetime import datetime, timezone from enum import Enum from typing import Dict, List, NamedTuple, Optional, Set @@ -14,9 +15,9 @@ class BfCategory(str, Enum): class CategorizedBFs(NamedTuple): - hot_bfs: Set[str] - cold_bfs: Set[str] - perf_bfs: Set[str] + hot_bfs: Set[BfIssue] + cold_bfs: Set[BfIssue] + perf_bfs: Set[BfIssue] @classmethod def empty(cls) -> CategorizedBFs: @@ -36,13 +37,13 @@ class CategorizedBFs(NamedTuple): test_type = TestType.from_evg_project_name(evg_project) if test_type == TestType.PERFORMANCE: - self.perf_bfs.add(bf.key) + self.perf_bfs.add(bf) if test_type == TestType.CORRECTNESS: if bf.temperature == BfTemperature.HOT: - self.hot_bfs.add(bf.key) + self.hot_bfs.add(bf) if bf.temperature in [BfTemperature.COLD, BfTemperature.NONE]: - self.cold_bfs.add(bf.key) + self.cold_bfs.add(bf) def add(self, more_bfs: CategorizedBFs) -> None: """ @@ -76,43 +77,38 @@ class BFsReport(NamedTuple): def get_bf_count( self, bf_category: BfCategory, - assigned_team: Optional[str] = None, + include_bfs_older_than_time: Optional[datetime] = None, + assigned_teams: Optional[List[str]] = None, ) -> int: """ Calculate BFs count for a given criteria. :param bf_category: BF category (hot, cold, perf). - :param assigned_team: Assigned team criterion, all teams if None. + :param include_bfs_older_than_time: Count BFs that have created date older than provided time. + :param assigned_teams: List of Assigned teams criterion, all teams if None. :return: BFs count. """ total_bf_count = 0 + if include_bfs_older_than_time is None: + include_bfs_older_than_time = datetime.utcnow().replace(tzinfo=timezone.utc) + team_reports = self.team_reports.values() - if assigned_team is not None: - team_reports = [self.team_reports[assigned_team]] + if assigned_teams is not None: + team_reports = [ + self.team_reports.get(team, CategorizedBFs.empty()) for team in assigned_teams + ] for team_report in team_reports: + bfs = set() if bf_category == BfCategory.HOT: - total_bf_count += len(team_report.hot_bfs) + bfs = team_report.hot_bfs if bf_category == BfCategory.COLD: - total_bf_count += len(team_report.cold_bfs) + bfs = team_report.cold_bfs if bf_category == BfCategory.PERF: - total_bf_count += len(team_report.perf_bfs) + bfs = team_report.perf_bfs + total_bf_count += len( + [bf for bf in bfs if bf.created_time < include_bfs_older_than_time] + ) return total_bf_count - - def combine_teams(self, team_names: List[str], group_name: str) -> None: - """ - Mutate `self.team_reports` by removing `team_names` entries and combining their BFs under `group_name`. - - :param team_names: Names of teams to combine BFs. - :param group_name: Group name to combine BFs under. - """ - group_bfs = CategorizedBFs.empty() - - for team in team_names: - team_bfs = self.team_reports.pop(team, None) - if team_bfs is not None: - group_bfs.add(team_bfs) - - self.team_reports[group_name] = group_bfs diff --git a/buildscripts/monitor_build_status/cli.py b/buildscripts/monitor_build_status/cli.py index 310cc1d1b31..58fda5bc479 100644 --- a/buildscripts/monitor_build_status/cli.py +++ b/buildscripts/monitor_build_status/cli.py @@ -43,12 +43,8 @@ JIRA_SERVER = "https://jira.mongodb.org" DEFAULT_REPO = "10gen/mongo" DEFAULT_BRANCH = "master" SLACK_CHANNEL = "#10gen-mongo-code-lockdown" -FRIDAY_INDEX = 4 # datetime.weekday() returns Monday as 0 and Sunday as 6 EVERGREEN_LOOKBACK_DAYS = 14 -GREEN_THRESHOLD_PERCENTS = 100 -RED_THRESHOLD_PERCENTS = 200 - def iterable_to_jql(entries: Iterable[str]) -> str: return ", ".join(f'"{entry}"' for entry in entries) @@ -66,57 +62,25 @@ ACTIVE_BFS_QUERY = ( ) -class ExitCode(Enum): - SUCCESS = 0 - PREVIOUS_BUILD_STATUS_UNKNOWN = 1 - - -class BuildStatus(Enum): +class CodeMergeStatus(Enum): RED = "RED" - YELLOW = "YELLOW" GREEN = "GREEN" - UNKNOWN = "UNKNOWN" @classmethod - def from_str(cls, status: Optional[str]) -> BuildStatus: - try: - return cls[status] - except KeyError: - return cls.UNKNOWN - - @classmethod - def from_threshold_percentages(cls, threshold_percentages: List[float]) -> BuildStatus: - if any(percentage > RED_THRESHOLD_PERCENTS for percentage in threshold_percentages): + def from_threshold_percentages(cls, threshold_percentages: List[float]) -> CodeMergeStatus: + if any(percentage > 100 for percentage in threshold_percentages): return cls.RED - if all(percentage < GREEN_THRESHOLD_PERCENTS for percentage in threshold_percentages): - return cls.GREEN - return cls.YELLOW + return cls.GREEN class SummaryMsg(Enum): - TITLE = "`[SUMMARY]`" + PREFIX = "`[SUMMARY]`" - BELOW_THRESHOLDS = f"All metrics are within {GREEN_THRESHOLD_PERCENTS}% of their thresholds." + BELOW_THRESHOLDS = "All metrics are within 100% of their thresholds.\nAll merges are allowed." THRESHOLD_EXCEEDED = ( - f"At least one metric exceeds {GREEN_THRESHOLD_PERCENTS}% of its threshold." + "At least one metric exceeds 100% of its threshold.\n" + "Approve only changes that fix BFs, Bugs, and Performance Regressions in the following scopes:" ) - THRESHOLD_EXCEEDED_X2 = ( - f"At least one metric exceeds {RED_THRESHOLD_PERCENTS}% of its threshold." - ) - - STATUS_CHANGED = " Build status has changed to `{status}`." - STATUS_IS = "Build status is `{status}`." - - ENTER_RED = "We are entering the code block state." - STILL_RED = "We are still in the code block state." - EXIT_RED = "We are exiting the code block state." - - ACTION_ON_RED = "Approve only changes that fix BFs, Bugs, and Performance Regressions." - ACTION_ON_YELLOW = ( - "Warning: all merges are still allowed, but now is a good time to get BFs, Bugs, and" - " Performance Regressions under control to avoid a blocking state." - ) - ACTION_ON_GREEN = "All merges are allowed." PLAYBOOK_REFERENCE = f"Refer to our playbook at <{BLOCK_ON_RED_PLAYBOOK_URL}> for details." @@ -132,13 +96,9 @@ class MonitorBuildStatusOrchestrator: self.evg_service = evg_service self.code_lockdown_config = code_lockdown_config - def evaluate_build_redness( - self, repo: str, branch: str, notify: bool, input_status_file: str, output_status_file: str - ) -> ExitCode: - exit_code = ExitCode.SUCCESS - + def evaluate_build_redness(self, repo: str, branch: str, notify: bool) -> None: status_message = f"\n`[STATUS]` '{repo}' repo '{branch}' branch" - threshold_percentages = [] + scope_percentages: Dict[str, List[float]] = {} LOGGER.info("Getting Evergreen projects data") evg_projects_info = self.evg_service.get_evg_project_info(repo, branch) @@ -150,7 +110,7 @@ class MonitorBuildStatusOrchestrator: bfs_report, self.code_lockdown_config ) status_message = f"{status_message}\n{bf_count_status_msg}\n" - threshold_percentages.extend(bf_count_percentages) + scope_percentages.update(bf_count_percentages) # We are looking for Evergreen versions that started before the beginning of yesterday # to give them time to complete @@ -167,48 +127,7 @@ class MonitorBuildStatusOrchestrator: ) status_message = f"{status_message}\n{waterfall_failure_rate_status_msg}\n" - previous_build_status = BuildStatus.UNKNOWN - if os.path.exists(input_status_file): - with open(input_status_file, "r") as input_file: - input_file_content = input_file.read().strip() - LOGGER.info( - "Input status file content", - file=input_status_file, - content=input_file_content, - ) - previous_build_status = BuildStatus.from_str(input_file_content) - if previous_build_status == BuildStatus.UNKNOWN: - LOGGER.error( - "Could not parse previous build status from the input build status file," - " the file was corrupted or contained unexpected string" - ) - else: - LOGGER.warning("Input status file is absent", file=input_status_file) - LOGGER.warning( - "The absence of input build status file is expected if the task is running for" - " the first time or for the first time after the file storage location is changed" - ) - - if previous_build_status == BuildStatus.UNKNOWN: - LOGGER.warning( - "We were not able to get the previous build status, which could lead to build status" - " being changed from RED to YELLOW, which should not happen, and/or summary messages" - " could be somewhat off" - ) - LOGGER.warning( - "If we are in a YELLOW condition, there's different behavior to communicate if that" - " was previously GREEN (things are worse, but not RED yet), YELLOW (no change), or" - " RED (still RED but improving)" - ) - LOGGER.warning( - "The state will still be reported, but may lose accuracy on specific actions to take" - ) - exit_code = ExitCode.PREVIOUS_BUILD_STATUS_UNKNOWN - - current_build_status = BuildStatus.from_threshold_percentages(threshold_percentages) - resulting_build_status, summary = self._summarize( - previous_build_status, current_build_status, self._today_is_friday() - ) + summary = self._summarize(scope_percentages) status_message = f"{status_message}\n{summary}" for line in status_message.split("\n"): @@ -221,11 +140,6 @@ class MonitorBuildStatusOrchestrator: msg=status_message.strip(), ) - with open(output_status_file, "w") as output_file: - output_file.write(resulting_build_status.value) - - return exit_code - def _make_bfs_report(self, evg_projects_info: EvgProjectsInfo) -> BFsReport: query = ( f'{ACTIVE_BFS_QUERY} AND "{JiraCustomFieldNames.EVERGREEN_PROJECT}" in' @@ -245,17 +159,16 @@ class MonitorBuildStatusOrchestrator: @staticmethod def _get_bf_counts_status( bfs_report: BFsReport, code_lockdown_config: CodeLockdownConfig - ) -> Tuple[str, List[float]]: - for group in code_lockdown_config.team_groups or []: - bfs_report.combine_teams(group.teams, group.name) + ) -> Tuple[str, Dict[str, List[float]]]: + now = datetime.utcnow().replace(tzinfo=timezone.utc) + scope_percentages: Dict[str, List[float]] = {} - percentages = [] status_message = "`[STATUS]` The current BF count" - headers = ["Assigned Team/Group", "Hot BFs", "Cold BFs", "Perf BFs"] + headers = ["Scope", "Hot BFs", "Cold BFs", "Perf BFs"] table_data = [] def _process_thresholds( - label: str, + scope: str, hot_bf_count: int, cold_bf_count: int, perf_bf_count: int, @@ -268,40 +181,60 @@ class MonitorBuildStatusOrchestrator: cold_bf_percentage = cold_bf_count / thresholds.cold_bf_count * 100 perf_bf_percentage = perf_bf_count / thresholds.perf_bf_count * 100 - percentages.extend([hot_bf_percentage, cold_bf_percentage, perf_bf_percentage]) + scope_percentages[scope] = [hot_bf_percentage, cold_bf_percentage, perf_bf_percentage] table_data.append( [ - label, + scope, f"{hot_bf_percentage:.0f}% ({hot_bf_count} / {thresholds.hot_bf_count})", f"{cold_bf_percentage:.0f}% ({cold_bf_count} / {thresholds.cold_bf_count})", f"{perf_bf_percentage:.0f}% ({perf_bf_count} / {thresholds.perf_bf_count})", ] ) - for assigned_team in sorted(list(bfs_report.team_reports.keys())): - _process_thresholds( - assigned_team, - bfs_report.get_bf_count(BfCategory.HOT, assigned_team), - bfs_report.get_bf_count(BfCategory.COLD, assigned_team), - bfs_report.get_bf_count(BfCategory.PERF, assigned_team), - code_lockdown_config.get_thresholds(assigned_team), - ) - + overall_older_than_time = now - timedelta( + hours=code_lockdown_config.overall_thresholds.include_bfs_older_than_hours + ) _process_thresholds( - "Overall", - bfs_report.get_bf_count(BfCategory.HOT), - bfs_report.get_bf_count(BfCategory.COLD), - bfs_report.get_bf_count(BfCategory.PERF), + "[Org] Overall", + bfs_report.get_bf_count(BfCategory.HOT, overall_older_than_time), + bfs_report.get_bf_count(BfCategory.COLD, overall_older_than_time), + bfs_report.get_bf_count(BfCategory.PERF, overall_older_than_time), code_lockdown_config.overall_thresholds, ) + for group in code_lockdown_config.team_groups or []: + group_thresholds = code_lockdown_config.get_thresholds(group.name) + group_older_than_time = now - timedelta( + hours=group_thresholds.include_bfs_older_than_hours + ) + _process_thresholds( + f"[Group] {group.name}", + bfs_report.get_bf_count(BfCategory.HOT, group_older_than_time, group.teams), + bfs_report.get_bf_count(BfCategory.COLD, group_older_than_time, group.teams), + bfs_report.get_bf_count(BfCategory.PERF, group_older_than_time, group.teams), + group_thresholds, + ) + + for assigned_team in sorted(list(bfs_report.team_reports.keys())): + team_thresholds = code_lockdown_config.get_thresholds(assigned_team) + team_older_than_time = now - timedelta( + hours=team_thresholds.include_bfs_older_than_hours + ) + _process_thresholds( + f"[Team] {assigned_team}", + bfs_report.get_bf_count(BfCategory.HOT, team_older_than_time, [assigned_team]), + bfs_report.get_bf_count(BfCategory.COLD, team_older_than_time, [assigned_team]), + bfs_report.get_bf_count(BfCategory.PERF, team_older_than_time, [assigned_team]), + team_thresholds, + ) + table_str = tabulate( table_data, headers, tablefmt="outline", colalign=("left", "right", "right", "right") ) status_message = f"{status_message}\n```\n{table_str}\n```" - return status_message, percentages + return status_message, scope_percentages def _make_waterfall_report( self, evg_project_names: List[str], window_end: datetime @@ -376,64 +309,25 @@ class MonitorBuildStatusOrchestrator: return status_message @staticmethod - def _summarize( - previous_status: BuildStatus, current_status: BuildStatus, today_is_friday: bool - ) -> Tuple[BuildStatus, str]: - resulting_status = previous_status - if current_status == BuildStatus.RED and previous_status != BuildStatus.RED: - if today_is_friday: - resulting_status = BuildStatus.RED - else: - resulting_status = BuildStatus.YELLOW - if current_status == BuildStatus.YELLOW and previous_status != BuildStatus.RED: - resulting_status = BuildStatus.YELLOW - if current_status == BuildStatus.GREEN: - resulting_status = BuildStatus.GREEN + def _summarize(scope_percentages: Dict[str, List[float]]) -> str: + summary = SummaryMsg.PREFIX.value - summary = SummaryMsg.TITLE.value + red_scopes = [] + for scope, percentages in scope_percentages.items(): + status = CodeMergeStatus.from_threshold_percentages(percentages) + if status == CodeMergeStatus.RED: + red_scopes.append(scope) - if resulting_status != previous_status: - status_msg = SummaryMsg.STATUS_CHANGED.value.format(status=resulting_status.value) + if len(red_scopes) == 0: + summary = f"{summary} {SummaryMsg.BELOW_THRESHOLDS.value}" else: - status_msg = SummaryMsg.STATUS_IS.value.format(status=resulting_status.value) - summary = f"{summary}\n{status_msg}" - - if current_status == BuildStatus.RED: - summary = f"{summary}\n{SummaryMsg.THRESHOLD_EXCEEDED_X2.value}" - if current_status == BuildStatus.YELLOW: - summary = f"{summary}\n{SummaryMsg.THRESHOLD_EXCEEDED.value}" - if current_status == BuildStatus.GREEN: - summary = f"{summary}\n{SummaryMsg.BELOW_THRESHOLDS.value}" - - if previous_status != BuildStatus.RED and resulting_status == BuildStatus.RED: - summary = f"{summary}\n{SummaryMsg.ENTER_RED.value}" - if previous_status == BuildStatus.RED and resulting_status == BuildStatus.RED: - summary = f"{summary}\n{SummaryMsg.STILL_RED.value}" - if previous_status == BuildStatus.RED and resulting_status != BuildStatus.RED: - summary = f"{summary}\n{SummaryMsg.EXIT_RED.value}" - - if resulting_status == BuildStatus.RED: - summary = f"{summary}\n{SummaryMsg.ACTION_ON_RED.value}" - if resulting_status == BuildStatus.YELLOW: - summary = f"{summary}\n{SummaryMsg.ACTION_ON_YELLOW.value}" - if resulting_status == BuildStatus.GREEN: - summary = f"{summary}\n{SummaryMsg.ACTION_ON_GREEN.value}" + summary = f"{summary} {SummaryMsg.THRESHOLD_EXCEEDED.value}" + for scope in red_scopes: + summary = f"{summary}\n\t- {scope}" summary = f"{summary}\n\n{SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - LOGGER.info( - "Got build statuses", - previous_build_status=previous_status.value, - current_build_status=current_status.value, - resulting_build_status=resulting_status.value, - today_is_friday=today_is_friday, - ) - - return resulting_status, summary - - @staticmethod - def _today_is_friday() -> bool: - return datetime.utcnow().weekday() == FRIDAY_INDEX + return summary def main( @@ -446,12 +340,6 @@ def main( notify: Annotated[ bool, typer.Option(help="Whether to send slack notification with the results") ] = False, # default to the more "quiet" setting - input_status_file: Annotated[ - str, typer.Option(help="The file that contains a previous build status") - ] = "input_build_status_file.txt", - output_status_file: Annotated[ - str, typer.Option(help="The file that contains the current build status") - ] = "output_build_status_file.txt", ) -> None: """ Analyze Jira BFs count and Evergreen redness data. @@ -484,10 +372,7 @@ def main( code_lockdown_config=code_lockdown_config, ) - exit_code = orchestrator.evaluate_build_redness( - github_repo, branch, notify, input_status_file, output_status_file - ) - sys.exit(exit_code.value) + orchestrator.evaluate_build_redness(github_repo, branch, notify) if __name__ == "__main__": diff --git a/buildscripts/monitor_build_status/code_lockdown_config.py b/buildscripts/monitor_build_status/code_lockdown_config.py index 0b12ac65c5b..979e9f68f96 100644 --- a/buildscripts/monitor_build_status/code_lockdown_config.py +++ b/buildscripts/monitor_build_status/code_lockdown_config.py @@ -10,6 +10,7 @@ class BfCountThresholds(BaseModel): hot_bf_count: int cold_bf_count: int perf_bf_count: int + include_bfs_older_than_hours: int class TeamGroupConfig(BaseModel): @@ -38,8 +39,8 @@ class CodeLockdownConfig(BaseModel): """ Get group or default team thresholds. - :param group_name: The name of the group or team. - :return: Group or default team thresholds. + :param group_name: The name of the group. + :return: Group thresholds or default team thresholds. """ for group in self.team_groups or []: if group.name == group_name: diff --git a/buildscripts/monitor_build_status/jira_service.py b/buildscripts/monitor_build_status/jira_service.py index 9ad7f6aca49..91800738cdb 100644 --- a/buildscripts/monitor_build_status/jira_service.py +++ b/buildscripts/monitor_build_status/jira_service.py @@ -1,9 +1,11 @@ from __future__ import annotations import re +from datetime import datetime from enum import Enum -from typing import List, NamedTuple, Optional +from typing import Any, List, NamedTuple, Optional +import dateutil.parser from jira import Issue from buildscripts.client.jiraclient import JiraClient @@ -58,6 +60,7 @@ class BfIssue(NamedTuple): assigned_team: str evergreen_projects: List[str] temperature: BfTemperature + created_time: datetime @classmethod def from_jira_issue(cls, issue: Issue) -> BfIssue: @@ -88,8 +91,15 @@ class BfIssue(NamedTuple): assigned_team=assigned_team, evergreen_projects=evergreen_projects, temperature=temperature, + created_time=dateutil.parser.parse(issue.fields.created), ) + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and self.key == other.key + + def __hash__(self) -> int: + return hash(self.key) + class JiraService: def __init__(self, jira_client: JiraClient) -> None: diff --git a/buildscripts/tests/monitor_build_status/test_bfs_report.py b/buildscripts/tests/monitor_build_status/test_bfs_report.py index 91371d78299..a27eee0911a 100644 --- a/buildscripts/tests/monitor_build_status/test_bfs_report.py +++ b/buildscripts/tests/monitor_build_status/test_bfs_report.py @@ -1,4 +1,5 @@ import unittest +from datetime import datetime import buildscripts.monitor_build_status.bfs_report as under_test @@ -24,12 +25,13 @@ class TestBFsReport(unittest.TestCase): assigned_team="team-1", evergreen_projects=["mongodb-mongo-master", "mongodb-mongo-master-nightly"], temperature=under_test.BfTemperature.HOT, + created_time=datetime.now(), ) bfs_report = under_test.BFsReport.empty() bfs_report.add_bf_data(bf_1, evg_projects_info) - self.assertEqual(bfs_report.team_reports["team-1"].hot_bfs, {"BF-1"}) + self.assertEqual(bfs_report.team_reports["team-1"].hot_bfs, {bf_1}) self.assertEqual(len(bfs_report.team_reports["team-1"].cold_bfs), 0) self.assertEqual(len(bfs_report.team_reports["team-1"].perf_bfs), 0) self.assertEqual(len(bfs_report.team_reports.keys()), 1) @@ -40,12 +42,13 @@ class TestBFsReport(unittest.TestCase): assigned_team="team-1", evergreen_projects=["mongodb-mongo-master"], temperature=under_test.BfTemperature.HOT, + created_time=datetime.now(), ) bfs_report = under_test.BFsReport.empty() bfs_report.add_bf_data(bf_1, evg_projects_info) - self.assertEqual(bfs_report.team_reports["team-1"].hot_bfs, {"BF-1"}) + self.assertEqual(bfs_report.team_reports["team-1"].hot_bfs, {bf_1}) self.assertEqual(len(bfs_report.team_reports["team-1"].cold_bfs), 0) self.assertEqual(len(bfs_report.team_reports["team-1"].perf_bfs), 0) self.assertEqual(len(bfs_report.team_reports.keys()), 1) @@ -56,13 +59,14 @@ class TestBFsReport(unittest.TestCase): assigned_team="team-1", evergreen_projects=["mongodb-mongo-master"], temperature=under_test.BfTemperature.COLD, + created_time=datetime.now(), ) bfs_report = under_test.BFsReport.empty() bfs_report.add_bf_data(bf_1, evg_projects_info) self.assertEqual(len(bfs_report.team_reports["team-1"].hot_bfs), 0) - self.assertEqual(bfs_report.team_reports["team-1"].cold_bfs, {"BF-1"}) + self.assertEqual(bfs_report.team_reports["team-1"].cold_bfs, {bf_1}) self.assertEqual(len(bfs_report.team_reports["team-1"].perf_bfs), 0) self.assertEqual(len(bfs_report.team_reports.keys()), 1) @@ -72,6 +76,7 @@ class TestBFsReport(unittest.TestCase): assigned_team="team-1", evergreen_projects=["sys-perf"], temperature=under_test.BfTemperature.HOT, + created_time=datetime.now(), ) bfs_report = under_test.BFsReport.empty() @@ -79,7 +84,7 @@ class TestBFsReport(unittest.TestCase): self.assertEqual(len(bfs_report.team_reports["team-1"].hot_bfs), 0) self.assertEqual(len(bfs_report.team_reports["team-1"].cold_bfs), 0) - self.assertEqual(bfs_report.team_reports["team-1"].perf_bfs, {"BF-1"}) + self.assertEqual(bfs_report.team_reports["team-1"].perf_bfs, {bf_1}) self.assertEqual(len(bfs_report.team_reports.keys()), 1) def test_add_cold_perf_bf(self): @@ -88,6 +93,7 @@ class TestBFsReport(unittest.TestCase): assigned_team="team-1", evergreen_projects=["sys-perf"], temperature=under_test.BfTemperature.COLD, + created_time=datetime.now(), ) bfs_report = under_test.BFsReport.empty() @@ -95,37 +101,5 @@ class TestBFsReport(unittest.TestCase): self.assertEqual(len(bfs_report.team_reports["team-1"].hot_bfs), 0) self.assertEqual(len(bfs_report.team_reports["team-1"].cold_bfs), 0) - self.assertEqual(bfs_report.team_reports["team-1"].perf_bfs, {"BF-1"}) - self.assertEqual(len(bfs_report.team_reports.keys()), 1) - - def test_combine_teams(self): - bfs_report = under_test.BFsReport( - team_reports={ - "Team 1": under_test.CategorizedBFs( - hot_bfs={"HOT-BF-1", "HOT-BF-2"}, - cold_bfs={"COLD-BF-1", "COLD-BF-2"}, - perf_bfs={"PERF-BF-1", "PERF-BF-2"}, - ), - "Team 2": under_test.CategorizedBFs( - hot_bfs={"HOT-BF-3", "HOT-BF-4"}, - cold_bfs={"COLD-BF-3", "COLD-BF-4"}, - perf_bfs={"PERF-BF-3", "PERF-BF-4"}, - ), - } - ) - - bfs_report.combine_teams(["Team 1", "Team 2"], "Group 1") - - self.assertEqual( - bfs_report.team_reports["Group 1"].hot_bfs, - {"HOT-BF-1", "HOT-BF-2", "HOT-BF-3", "HOT-BF-4"}, - ) - self.assertEqual( - bfs_report.team_reports["Group 1"].cold_bfs, - {"COLD-BF-1", "COLD-BF-2", "COLD-BF-3", "COLD-BF-4"}, - ) - self.assertEqual( - bfs_report.team_reports["Group 1"].perf_bfs, - {"PERF-BF-1", "PERF-BF-2", "PERF-BF-3", "PERF-BF-4"}, - ) + self.assertEqual(bfs_report.team_reports["team-1"].perf_bfs, {bf_1}) self.assertEqual(len(bfs_report.team_reports.keys()), 1) diff --git a/buildscripts/tests/monitor_build_status/test_cli.py b/buildscripts/tests/monitor_build_status/test_cli.py index 92e0f095d85..13ec11c497f 100644 --- a/buildscripts/tests/monitor_build_status/test_cli.py +++ b/buildscripts/tests/monitor_build_status/test_cli.py @@ -4,345 +4,57 @@ import buildscripts.monitor_build_status.cli as under_test class TestSummarize(unittest.TestCase): - def test_previous_unknown_current_red_not_friday(self): - previous_build_status = under_test.BuildStatus.UNKNOWN - current_build_status = under_test.BuildStatus.RED - today_is_friday = False + def test_all_thresholds_below_100(self): + scope_percentages = { + "Scope 1": [0.0, 0.0, 0.0], + "Scope 2": [0.0, 0.0, 0.0], + "Scope 3": [0.0, 0.0, 0.0], + "Scope 4": [0.0, 0.0, 0.0], + } - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) + summary = under_test.MonitorBuildStatusOrchestrator._summarize(scope_percentages) - expected_status = under_test.BuildStatus.YELLOW expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" + f"{under_test.SummaryMsg.PREFIX.value} " + f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n\n" f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" ) - self.assertEqual(resulting_build_status, expected_status) self.assertEqual(summary, expected_summary) - def test_previous_green_current_red_not_friday(self): - previous_build_status = under_test.BuildStatus.GREEN - current_build_status = under_test.BuildStatus.RED - today_is_friday = False + def test_all_thresholds_are_100(self): + scope_percentages = { + "Scope 1": [100.0, 100.0, 100.0], + "Scope 2": [100.0, 100.0, 100.0], + "Scope 3": [100.0, 100.0, 100.0], + "Scope 4": [100.0, 100.0, 100.0], + } - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) + summary = under_test.MonitorBuildStatusOrchestrator._summarize(scope_percentages) - expected_status = under_test.BuildStatus.YELLOW expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" + f"{under_test.SummaryMsg.PREFIX.value} " + f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n\n" f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" ) - self.assertEqual(resulting_build_status, expected_status) self.assertEqual(summary, expected_summary) - def test_previous_yellow_current_red_not_friday(self): - previous_build_status = under_test.BuildStatus.YELLOW - current_build_status = under_test.BuildStatus.RED - today_is_friday = False + def test_some_threshold_exceeded_100(self): + scope_percentages = { + "Scope 1": [101.0, 0.0, 0.0], + "Scope 2": [0.0, 101.0, 0.0], + "Scope 3": [0.0, 0.0, 101.0], + "Scope 4": [0.0, 0.0, 0.0], + } - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) + summary = under_test.MonitorBuildStatusOrchestrator._summarize(scope_percentages) - expected_status = under_test.BuildStatus.YELLOW expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_red_current_red_not_friday(self): - previous_build_status = under_test.BuildStatus.RED - current_build_status = under_test.BuildStatus.RED - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.STILL_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_unknown_current_red_on_friday(self): - previous_build_status = under_test.BuildStatus.UNKNOWN - current_build_status = under_test.BuildStatus.RED - today_is_friday = True - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ENTER_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_green_current_red_on_friday(self): - previous_build_status = under_test.BuildStatus.GREEN - current_build_status = under_test.BuildStatus.RED - today_is_friday = True - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ENTER_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_yellow_current_red_on_friday(self): - previous_build_status = under_test.BuildStatus.YELLOW - current_build_status = under_test.BuildStatus.RED - today_is_friday = True - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.ENTER_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_red_current_red_on_friday(self): - previous_build_status = under_test.BuildStatus.RED - current_build_status = under_test.BuildStatus.RED - today_is_friday = True - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED_X2.value}\n" - f"{under_test.SummaryMsg.STILL_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_unknown_current_yellow(self): - previous_build_status = under_test.BuildStatus.UNKNOWN - current_build_status = under_test.BuildStatus.YELLOW - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.YELLOW - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" + f"{under_test.SummaryMsg.PREFIX.value} " f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" + f"\t- Scope 1\n\t- Scope 2\n\t- Scope 3\n\n" f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" ) - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_green_current_yellow(self): - previous_build_status = under_test.BuildStatus.GREEN - current_build_status = under_test.BuildStatus.YELLOW - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.YELLOW - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_yellow_current_yellow(self): - previous_build_status = under_test.BuildStatus.YELLOW - current_build_status = under_test.BuildStatus.YELLOW - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.YELLOW - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_YELLOW.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_red_current_yellow(self): - previous_build_status = under_test.BuildStatus.RED - current_build_status = under_test.BuildStatus.YELLOW - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.RED - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.THRESHOLD_EXCEEDED.value}\n" - f"{under_test.SummaryMsg.STILL_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_RED.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_unknown_current_green(self): - previous_build_status = under_test.BuildStatus.UNKNOWN - current_build_status = under_test.BuildStatus.GREEN - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.GREEN - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_GREEN.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_green_current_green(self): - previous_build_status = under_test.BuildStatus.GREEN - current_build_status = under_test.BuildStatus.GREEN - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.GREEN - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_IS.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_GREEN.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_yellow_current_green(self): - previous_build_status = under_test.BuildStatus.YELLOW - current_build_status = under_test.BuildStatus.GREEN - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.GREEN - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_GREEN.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) - self.assertEqual(summary, expected_summary) - - def test_previous_red_current_green(self): - previous_build_status = under_test.BuildStatus.RED - current_build_status = under_test.BuildStatus.GREEN - today_is_friday = False - - resulting_build_status, summary = under_test.MonitorBuildStatusOrchestrator._summarize( - previous_build_status, current_build_status, today_is_friday - ) - - expected_status = under_test.BuildStatus.GREEN - expected_summary = ( - f"{under_test.SummaryMsg.TITLE.value}\n" - f"{under_test.SummaryMsg.STATUS_CHANGED.value.format(status=expected_status.value)}\n" - f"{under_test.SummaryMsg.BELOW_THRESHOLDS.value}\n" - f"{under_test.SummaryMsg.EXIT_RED.value}\n" - f"{under_test.SummaryMsg.ACTION_ON_GREEN.value}\n\n" - f"{under_test.SummaryMsg.PLAYBOOK_REFERENCE.value}\n" - ) - - self.assertEqual(resulting_build_status, expected_status) self.assertEqual(summary, expected_summary) diff --git a/buildscripts/tests/monitor_build_status/test_jira_service.py b/buildscripts/tests/monitor_build_status/test_jira_service.py index af751859f84..4ed9600d6de 100644 --- a/buildscripts/tests/monitor_build_status/test_jira_service.py +++ b/buildscripts/tests/monitor_build_status/test_jira_service.py @@ -5,45 +5,56 @@ import buildscripts.monitor_build_status.jira_service as under_test class TestBfIssue(unittest.TestCase): + def setUp(self): + self.created = "Mon, 5 Aug 2024 15:05:10 +0000" + def test_parse_assigned_team_from_jira_issue(self): team_name = "Team Name" - jira_issue_1 = MagicMock(fields=MagicMock(customfield_12751=[MagicMock(value=team_name)])) + jira_issue_1 = MagicMock( + fields=MagicMock(customfield_12751=[MagicMock(value=team_name)], created=self.created) + ) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_1) self.assertEqual(bf_issue.assigned_team, team_name) - jira_issue_2 = MagicMock(fields=MagicMock(customfield_12751=[])) + jira_issue_2 = MagicMock(fields=MagicMock(customfield_12751=[], created=self.created)) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_2) self.assertEqual(bf_issue.assigned_team, under_test.UNASSIGNED_LABEL) - jira_issue_3 = MagicMock(fields=MagicMock()) + jira_issue_3 = MagicMock(fields=MagicMock(created=self.created)) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_3) self.assertEqual(bf_issue.assigned_team, under_test.UNASSIGNED_LABEL) def test_parse_evergreen_projects_from_jira_issue(self): evergreen_projects = ["evg-project"] - jira_issue_1 = MagicMock(fields=MagicMock(customfield_14278=evergreen_projects)) + jira_issue_1 = MagicMock( + fields=MagicMock(customfield_14278=evergreen_projects, created=self.created) + ) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_1) self.assertEqual(bf_issue.evergreen_projects, evergreen_projects) - jira_issue_2 = MagicMock(fields=MagicMock(customfield_14278=[])) + jira_issue_2 = MagicMock(fields=MagicMock(customfield_14278=[], created=self.created)) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_2) self.assertEqual(bf_issue.evergreen_projects, []) - jira_issue_3 = MagicMock(fields=MagicMock()) + jira_issue_3 = MagicMock(fields=MagicMock(created=self.created)) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_3) self.assertEqual(bf_issue.evergreen_projects, []) def test_parse_bf_temperature_from_jira_issue(self): bf_temperature = "hot" - jira_issue_1 = MagicMock(fields=MagicMock(customfield_24859=bf_temperature)) + jira_issue_1 = MagicMock( + fields=MagicMock(customfield_24859=bf_temperature, created=self.created) + ) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_1) self.assertEqual(bf_issue.temperature, under_test.BfTemperature.HOT) bf_temperature = "cold" - jira_issue_2 = MagicMock(fields=MagicMock(customfield_24859=bf_temperature)) + jira_issue_2 = MagicMock( + fields=MagicMock(customfield_24859=bf_temperature, created=self.created) + ) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_2) self.assertEqual(bf_issue.temperature, under_test.BfTemperature.COLD) - jira_issue_3 = MagicMock(fields=MagicMock()) + jira_issue_3 = MagicMock(fields=MagicMock(created=self.created)) bf_issue = under_test.BfIssue.from_jira_issue(jira_issue_3) self.assertEqual(bf_issue.temperature, under_test.BfTemperature.NONE) diff --git a/etc/code_lockdown.yml b/etc/code_lockdown.yml index 4cfcece509a..6c49f75cd25 100644 --- a/etc/code_lockdown.yml +++ b/etc/code_lockdown.yml @@ -1,12 +1,14 @@ overall_thresholds: - hot_bf_count: 15 - cold_bf_count: 50 - perf_bf_count: 15 + hot_bf_count: 30 + cold_bf_count: 100 + perf_bf_count: 30 + include_bfs_older_than_hours: 168 # 7 days team_default_thresholds: hot_bf_count: 3 cold_bf_count: 10 perf_bf_count: 5 + include_bfs_older_than_hours: 48 team_groups: ###################################################################### @@ -14,11 +16,48 @@ team_groups: ###################################################################### # - name: Group Name # teams: - # - Team Name 1 # Should exactly match "Assigned Teams" field value + # - Team Name 1 # Should exactly match "Assigned Teams" Jira BF field value # - Team Name 2 # - Team Name 3 # thresholds: # hot_bf_count: 3 # cold_bf_count: 10 # perf_bf_count: 5 + # include_bfs_older_than_hours: 168 # 7 days ###################################################################### + + # Core Server Team VP orgs as described in https://wiki.corp.mongodb.com/pages/viewpage.action?spaceKey=KERNEL&title=Server+Home + - name: "Clusters & Integrations" + teams: + - Server Security + - Networking & Observability + - Workload Scheduling + - Server Programmability + - Cluster Scalability + - Catalog and Routing + thresholds: + hot_bf_count: 15 + cold_bf_count: 50 + perf_bf_count: 15 + include_bfs_older_than_hours: 168 # 7 days + - name: "Durable Transactions & Availability" + teams: + - Replication + - Storage Execution + - RSS Sydney + - Storage Engines + thresholds: + hot_bf_count: 15 + cold_bf_count: 50 + perf_bf_count: 15 + include_bfs_older_than_hours: 168 # 7 days + - name: "Query" + teams: + - Query Execution + - Query Optimization + - Query Integration + thresholds: + hot_bf_count: 15 + cold_bf_count: 50 + perf_bf_count: 15 + include_bfs_older_than_hours: 168 # 7 days diff --git a/etc/evergreen_yml_components/tasks/misc_tasks.yml b/etc/evergreen_yml_components/tasks/misc_tasks.yml index 2f1f2e09f7e..8535f7ce939 100644 --- a/etc/evergreen_yml_components/tasks/misc_tasks.yml +++ b/etc/evergreen_yml_components/tasks/misc_tasks.yml @@ -1103,26 +1103,6 @@ tasks: - func: "set up venv" - func: "upload pip requirements" - func: "configure evergreen api credentials" - # Attempting to download build status file that was uploaded by previous run of this task - # `remote_file` location should match uploading file location in steps below - # `optional: true` is to pass this step when this task is running for the first time - - command: s3.get - params: - aws_key: ${aws_key} - aws_secret: ${aws_secret} - remote_file: ${project}/monitor_build_status/${branch_name}/build_status_latest_file.txt - bucket: mciuploads - local_file: src/input_build_status_file.txt - optional: true - # The same as above but for patches for testing purposes - - command: s3.get - params: - aws_key: ${aws_key} - aws_secret: ${aws_secret} - remote_file: ${project}/monitor_build_status_testing/${branch_name}/build_status_latest_file_testing.txt - bucket: mciuploads - local_file: src/input_build_status_file_testing.txt - optional: true - command: subprocess.exec type: test params: @@ -1134,41 +1114,6 @@ tasks: JIRA_AUTH_ACCESS_TOKEN_SECRET: ${jira_auth_access_token_secret} JIRA_AUTH_CONSUMER_KEY: ${jira_auth_consumer_key} JIRA_AUTH_KEY_CERT: ${jira_auth_key_cert} - # Uploading build status file after each run of this task to be consumed by the next run - # `remote_file` location should match downloading file location in steps above - - command: s3.put - params: - aws_key: ${aws_key} - aws_secret: ${aws_secret} - local_file: src/output_build_status_file.txt - remote_file: ${project}/monitor_build_status/${branch_name}/build_status_latest_file.txt - bucket: mciuploads - permissions: public-read - content_type: text/plain - display_name: Build Status Latest - patchable: false - # The same as above but for patches for testing purposes to avoid overriding the file - # that is used on the waterfall runs - # However `remote_file` location could be changed here to intentionally override the file - # that is used on the waterfall from the patch in case of emergency, e.g. build status was - # evaluated incorrectly on the waterfall and incorrect status was uploaded on S3 - - command: s3.put - params: - aws_key: ${aws_key} - aws_secret: ${aws_secret} - local_file: src/output_build_status_file_testing.txt - remote_file: ${project}/monitor_build_status_testing/${branch_name}/build_status_latest_file_testing.txt - bucket: mciuploads - permissions: public-read - content_type: text/plain - display_name: Build Status Latest Patch Testing - patch_only: true - - command: subprocess.exec - type: test - params: - binary: bash - args: - - "src/evergreen/monitor_build_status_exit.sh" - name: monitor_mongo_fork_10gen tags: ["assigned_to_jira_team_devprod_correctness", "auxiliary"] diff --git a/evergreen/monitor_build_status_exit.sh b/evergreen/monitor_build_status_exit.sh deleted file mode 100644 index 8551f51337d..00000000000 --- a/evergreen/monitor_build_status_exit.sh +++ /dev/null @@ -1,16 +0,0 @@ -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" -. "$DIR/prelude.sh" - -set -o errexit -set -o verbose - -cd src - -if [ -f monitor_build_status_command_exit_code.txt ]; then - exit_code=$(cat monitor_build_status_command_exit_code.txt) -else - exit_code=0 -fi - -echo "Exiting monitor_build_status with code $exit_code" -exit "$exit_code" diff --git a/evergreen/monitor_build_status_run.sh b/evergreen/monitor_build_status_run.sh index 9aec413127b..313796fe1d9 100644 --- a/evergreen/monitor_build_status_run.sh +++ b/evergreen/monitor_build_status_run.sh @@ -8,15 +8,9 @@ cd src activate_venv command_invocation="$python buildscripts/monitor_build_status/cli.py" -if [ "${is_patch}" = "true" ]; then - command_invocation="$command_invocation --input-status-file input_build_status_file_testing.txt" - command_invocation="$command_invocation --output-status-file output_build_status_file_testing.txt" -else +if [ "${is_patch}" != "true" ]; then command_invocation="$command_invocation --notify" fi echo "Verbatim monitor_build_status invocation: ${command_invocation}" -set +o errexit eval "${command_invocation}" -echo "$?" > monitor_build_status_command_exit_code.txt -set -o errexit