@@ -14,65 +14,86 @@ jobs:
1414 - name : Checkout code
1515 uses : actions/checkout@v4
1616 with :
17- fetch-depth : 0
17+ fetch-depth : 0 # Required for accessing the main branch history
1818
1919 - name : Set up Python
2020 uses : actions/setup-python@v5
2121 with :
2222 python-version : ' 3.10'
2323
24- - name : Install dependencies
24+ - name : Install the latest version of uv
2525 uses : astral-sh/setup-uv@v5
26- with :
27- version : " latest"
2826
29- - name : Install project
27+ - name : Install dependencies
28+ # Syncing installs the package and its dependencies (populating google.* namespace)
29+ # Installing 'griffe' ensures the tool is available in the environment
3030 run : |
3131 uv sync --extra test
3232 uv pip install griffe
3333
3434 - name : Run Breaking Change Detection
35+ # Uses 'uv run python' to execute in the environment with all dependencies installed
3536 run : |
3637 uv run python - <<EOF
3738 import sys
3839 import griffe
3940 from griffe import find_breaking_changes, load, load_git
4041
41- def print_debug_info(api_obj, label):
42+ def check_return_types(old_obj, new_obj):
43+ """Custom check to strictly compare return type annotations."""
44+ errors = []
45+ # Check Runner.run specifically, or extend to check all methods
4246 try:
43- # Navigate to Runner.run to check what Griffe sees
44- runner = api_obj.members["Runner"]
45- run_method = runner.members["run"]
46- print(f"DEBUG [{label}]: Runner.run return annotation: '{run_method.returns}'")
47- except KeyError as e:
48- print(f"DEBUG [{label}]: Could not find 'Runner.run' member. Missing: {e}")
49- print(f"DEBUG [{label}]: Available members: {list(api_obj.members.keys())}")
47+ old_run = old_obj.members["Runner"].members["run"]
48+ new_run = new_obj.members["Runner"].members["run"]
49+
50+ # Convert to string and strip to compare the annotation text
51+ old_ret = str(old_run.returns).strip()
52+ new_ret = str(new_run.returns).strip()
53+
54+ if old_ret != new_ret:
55+ errors.append(
56+ f"Breaking Change in {new_run.path}: Return type changed from '{old_ret}' to '{new_ret}'"
57+ )
58+ except KeyError:
59+ pass # Member missing (will be caught by standard checks)
60+ except AttributeError:
61+ pass # Member might not be a function
62+ return errors
5063
5164 try:
52- # 1. Load NEW API (Force static analysis )
53- print("Loading new API from src/...")
65+ print("Loading new API (from local source)..." )
66+ # allow_inspection=False forces static analysis, preventing sys.modules caching issues
5467 new_api = load("google.adk", search_paths=["src"], allow_inspection=False)
55- print(f"DEBUG: New API filepath: {new_api.filepath}")
56- print_debug_info(new_api, "NEW")
5768
58- # 2. Load OLD API (Force static analysis from git)
59- print("Loading old API from main branch...")
69+ print("Loading baseline API (from main branch)...")
6070 old_api = load_git("google.adk", ref="main", search_paths=["src"], allow_inspection=False)
61- print(f"DEBUG: Old API filepath: {old_api.filepath}")
62- print_debug_info(old_api, "OLD")
6371
64- # 3. Compare
65- print("Comparing...")
72+ print("Running detection...")
73+
74+ # 1. Standard Griffe Checks (Removals, Parameter changes)
6675 breakages = list(find_breaking_changes(old_api, new_api))
6776
77+ # 2. Custom Return Type Checks (Workaround for Griffe limitation)
78+ custom_errors = check_return_types(old_api, new_api)
79+
80+ found_issues = False
81+
6882 if breakages:
69- print(f"::error::Found {len(breakages)} breaking changes!")
83+ found_issues = True
84+ print(f"::error::Found {len(breakages)} standard breaking changes!")
7085 for breakage in breakages:
7186 print(breakage.explain())
87+
88+ if custom_errors:
89+ found_issues = True
90+ print(f"::error::Found {len(custom_errors)} return type mismatches!")
91+ for error in custom_errors:
92+ print(f"- {error}")
93+
94+ if found_issues:
7295 sys.exit(1)
73-
74- # If we see different return types in DEBUG logs but 0 breakages here,
75- # it means Griffe considers them compatible.
96+
7697 print("Success: No breaking changes detected.")
7798
7899 except Exception as e:
0 commit comments