[bct] Support regex suppressions (#37196)
* add regex suppressions * clean up ignore logic * pass ignores at tracker start up * add ListResult suppression * fix model, add test * update allowlist --------- Co-authored-by: Catalina Peralta <caperal@microsoft.com>
This commit is contained in:
Родитель
e964d988b6
Коммит
392e0aef50
|
@ -5,6 +5,7 @@
|
|||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
import re
|
||||
from typing import List, Optional, NamedTuple, Protocol, runtime_checkable, Union
|
||||
|
||||
class BreakingChange(NamedTuple):
|
||||
|
@ -22,6 +23,15 @@ class Suppression(NamedTuple):
|
|||
function_name: Optional[str] = None
|
||||
parameter_or_property_name: Optional[str] = None
|
||||
|
||||
class RegexSuppression:
|
||||
value: str
|
||||
|
||||
def __init__(self, value: str):
|
||||
self.value = value
|
||||
|
||||
def match(self, compare_value: str) -> bool:
|
||||
return True if re.fullmatch(self.value, compare_value) else False
|
||||
|
||||
@runtime_checkable
|
||||
class ChangesChecker(Protocol):
|
||||
name: str
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
from _models import RegexSuppression
|
||||
|
||||
RUN_BREAKING_CHANGES_PACKAGES = ["azure-mgmt-*", "azure-ai-contentsafety", "azure-ai-vision-face"]
|
||||
|
||||
|
@ -16,6 +17,7 @@ IGNORE_BREAKING_CHANGES = {
|
|||
# Changes due to latest dpg design + need to support overloads in this tool
|
||||
("ChangedParameterOrdering", "*", "*", "__init__"),
|
||||
# Changes due to latest dpg design
|
||||
("RemovedOrRenamedClass", "*", RegexSuppression(".*ListResult$")),
|
||||
("ChangedParameterKind", "*", "*", "*", "top"),
|
||||
("ChangedParameterKind", "*", "*", "*", "filter"),
|
||||
("ChangedParameterKind", "*", "*", "*", "skip"),
|
||||
|
|
|
@ -10,8 +10,7 @@ import re
|
|||
from enum import Enum
|
||||
from typing import Any, Dict, List, Union
|
||||
from copy import deepcopy
|
||||
from breaking_changes_allowlist import IGNORE_BREAKING_CHANGES
|
||||
from _models import ChangesChecker, Suppression
|
||||
from _models import ChangesChecker, Suppression, RegexSuppression
|
||||
|
||||
|
||||
class BreakingChangeType(str, Enum):
|
||||
|
@ -98,7 +97,7 @@ class BreakingChangesTracker:
|
|||
self._class_name = None
|
||||
self._function_name = None
|
||||
self._parameter_name = None
|
||||
self.ignore = kwargs.get("ignore", None)
|
||||
self.ignore = kwargs.get("ignore", {})
|
||||
checkers: List[ChangesChecker] = kwargs.get("checkers", [])
|
||||
for checker in checkers:
|
||||
if not isinstance(checker, ChangesChecker):
|
||||
|
@ -593,6 +592,11 @@ class BreakingChangesTracker:
|
|||
for b, i in zip(bc, ignored):
|
||||
if i == "*":
|
||||
continue
|
||||
if isinstance(i, RegexSuppression) and b is not None:
|
||||
if i.match(b):
|
||||
continue
|
||||
else:
|
||||
return False
|
||||
if b != i:
|
||||
return False
|
||||
return True
|
||||
|
@ -625,7 +629,7 @@ class BreakingChangesTracker:
|
|||
break
|
||||
|
||||
def report_changes(self) -> None:
|
||||
ignore_changes = self.ignore if self.ignore else IGNORE_BREAKING_CHANGES
|
||||
ignore_changes = self.ignore if self.ignore else {}
|
||||
self.get_reportable_changes(ignore_changes, self.breaking_changes)
|
||||
|
||||
# If there are no breaking changes after the ignore check, return early
|
||||
|
|
|
@ -9,7 +9,6 @@ from enum import Enum
|
|||
from typing import Any, Dict
|
||||
import jsondiff
|
||||
from breaking_changes_tracker import BreakingChangesTracker
|
||||
from breaking_changes_allowlist import IGNORE_BREAKING_CHANGES
|
||||
|
||||
class ChangeType(str, Enum):
|
||||
ADDED_CLIENT = "AddedClient"
|
||||
|
@ -177,7 +176,7 @@ class ChangelogTracker(BreakingChangesTracker):
|
|||
|
||||
|
||||
def report_changes(self) -> None:
|
||||
ignore_changes = self.ignore if self.ignore else IGNORE_BREAKING_CHANGES
|
||||
ignore_changes = self.ignore if self.ignore else {}
|
||||
self.get_reportable_changes(ignore_changes, self.breaking_changes)
|
||||
self.get_reportable_changes(ignore_changes, self.features_added)
|
||||
# Code borrowed and modified from the previous change log tool
|
||||
|
|
|
@ -21,7 +21,7 @@ import subprocess
|
|||
from enum import Enum
|
||||
from typing import Dict, Union, Type, Callable, Optional
|
||||
from packaging_tools.venvtools import create_venv_with_package
|
||||
from breaking_changes_allowlist import RUN_BREAKING_CHANGES_PACKAGES
|
||||
from breaking_changes_allowlist import RUN_BREAKING_CHANGES_PACKAGES, IGNORE_BREAKING_CHANGES
|
||||
from breaking_changes_tracker import BreakingChangesTracker
|
||||
from changelog_tracker import ChangelogTracker
|
||||
from pathlib import Path
|
||||
|
@ -445,9 +445,15 @@ def test_compare_reports(pkg_dir: str, changelog: bool, source_report: str = "st
|
|||
stable = report_azure_mgmt_versioned_module(stable)
|
||||
current = report_azure_mgmt_versioned_module(current)
|
||||
|
||||
checker = BreakingChangesTracker(stable, current, package_name, checkers = CHECKERS)
|
||||
checker = BreakingChangesTracker(
|
||||
stable,
|
||||
current,
|
||||
package_name,
|
||||
checkers = CHECKERS,
|
||||
ignore = IGNORE_BREAKING_CHANGES
|
||||
)
|
||||
if changelog:
|
||||
checker = ChangelogTracker(stable, current, package_name, checkers = CHECKERS)
|
||||
checker = ChangelogTracker(stable, current, package_name, checkers = CHECKERS, ignore = IGNORE_BREAKING_CHANGES)
|
||||
checker.run_checks()
|
||||
|
||||
remove_json_files(pkg_dir)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
from _models import RegexSuppression
|
||||
|
||||
def test_regex_suppressions():
|
||||
regex_suppression = RegexSuppression(".*")
|
||||
assert regex_suppression.match("some_string") == True
|
||||
assert regex_suppression.match("another_string") == True
|
||||
|
||||
regex_suppression = RegexSuppression(".*ListResult$")
|
||||
assert regex_suppression.match("FooListResult") == True
|
Загрузка…
Ссылка в новой задаче