Skip to content

Commit cf22f6f

Browse files
committed
scripts: set_assignee: request review from maintainers of changed areas
Also request reviewes from maintainers of changes areas in the maintainer file. Signed-off-by: Anas Nashif <[email protected]>
1 parent 7746d06 commit cf22f6f

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

.github/workflows/assigner.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
FLAGS+=" -r ${{ github.event.repository.name }}"
6464
FLAGS+=" -M MAINTAINERS.yml"
6565
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
66-
FLAGS+=" -P ${{ github.event.pull_request.number }} --updated-manifest pr_west.yml"
66+
FLAGS+=" -P ${{ github.event.pull_request.number }} --updated-manifest pr_west.yml --updated-mantainer-file pr_MAINTAINERS.yml"
6767
elif [ "${{ github.event_name }}" = "issues" ]; then
6868
FLAGS+=" -I ${{ github.event.issue.number }}"
6969
elif [ "${{ github.event_name }}" = "schedule" ]; then

scripts/ci/set_assignees.py

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,24 @@
99
import sys
1010
import time
1111
from collections import defaultdict
12+
from pathlib import Path
1213

14+
import yaml
1315
from github import Auth, Github, GithubException
1416
from github.GithubException import UnknownObjectException
1517
from west.manifest import Manifest, ManifestProject
1618

1719
TOP_DIR = os.path.join(os.path.dirname(__file__))
18-
sys.path.insert(0, os.path.join(TOP_DIR, "scripts"))
20+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
1921
from get_maintainer import Maintainers # noqa: E402
2022

21-
zephyr_base = os.getenv('ZEPHYR_BASE', os.path.join(TOP_DIR, '..'))
23+
ZEPHYR_BASE = os.environ.get('ZEPHYR_BASE')
24+
if ZEPHYR_BASE:
25+
ZEPHYR_BASE = Path(ZEPHYR_BASE)
26+
else:
27+
ZEPHYR_BASE = Path(__file__).resolve().parents[2]
28+
# Propagate this decision to child processes.
29+
os.environ['ZEPHYR_BASE'] = str(ZEPHYR_BASE)
2230

2331

2432
def log(s):
@@ -71,10 +79,22 @@ def parse_args():
7179
help="Updated manifest file to compare against current west.yml",
7280
)
7381

82+
parser.add_argument(
83+
"--updated-maintainer-file",
84+
default=None,
85+
help="Updated maintainer file to compare against current MAINTAINERS.yml",
86+
)
87+
7488
parser.add_argument("-v", "--verbose", action="count", default=0, help="Verbose Output")
7589

7690
args = parser.parse_args()
7791

92+
def load_areas(filename: str):
93+
with open(filename) as f:
94+
doc = yaml.safe_load(f)
95+
return {
96+
k: v for k, v in doc.items() if isinstance(v, dict) and ("files" in v or "files-regex" in v)
97+
}
7898

7999
def process_manifest(old_manifest_file):
80100
log("Processing manifest changes")
@@ -104,6 +124,93 @@ def process_manifest(old_manifest_file):
104124
log(f'manifest areas: {areas}')
105125
return areas
106126

127+
def set_or_empty(d, key):
128+
return set(d.get(key, []) or [])
129+
130+
def compare_areas(old, new, repo_fullname=None, token=None):
131+
old_areas = set(old.keys())
132+
new_areas = set(new.keys())
133+
134+
changed_areas = set()
135+
added_areas = new_areas - old_areas
136+
removed_areas = old_areas - new_areas
137+
common_areas = old_areas & new_areas
138+
139+
print("=== Areas Added ===")
140+
for area in sorted(added_areas):
141+
print(f"+ {area}")
142+
143+
print("\n=== Areas Removed ===")
144+
for area in sorted(removed_areas):
145+
print(f"- {area}")
146+
147+
print("\n=== Area Changes ===")
148+
for area in sorted(common_areas):
149+
changes = []
150+
old_entry = old[area]
151+
new_entry = new[area]
152+
153+
# Compare maintainers
154+
old_maint = set_or_empty(old_entry, "maintainers")
155+
new_maint = set_or_empty(new_entry, "maintainers")
156+
added_maint = new_maint - old_maint
157+
removed_maint = old_maint - new_maint
158+
if added_maint:
159+
changes.append(f" Maintainers added: {', '.join(sorted(added_maint))}")
160+
if removed_maint:
161+
changes.append(f" Maintainers removed: {', '.join(sorted(removed_maint))}")
162+
163+
# Compare collaborators
164+
old_collab = set_or_empty(old_entry, "collaborators")
165+
new_collab = set_or_empty(new_entry, "collaborators")
166+
added_collab = new_collab - old_collab
167+
removed_collab = old_collab - new_collab
168+
if added_collab:
169+
changes.append(f" Collaborators added: {', '.join(sorted(added_collab))}")
170+
if removed_collab:
171+
changes.append(f" Collaborators removed: {', '.join(sorted(removed_collab))}")
172+
173+
# Compare status
174+
old_status = old_entry.get("status")
175+
new_status = new_entry.get("status")
176+
if old_status != new_status:
177+
changes.append(f" Status changed: {old_status} -> {new_status}")
178+
179+
# Compare labels
180+
old_labels = set_or_empty(old_entry, "labels")
181+
new_labels = set_or_empty(new_entry, "labels")
182+
added_labels = new_labels - old_labels
183+
removed_labels = old_labels - new_labels
184+
if added_labels:
185+
changes.append(f" Labels added: {', '.join(sorted(added_labels))}")
186+
if removed_labels:
187+
changes.append(f" Labels removed: {', '.join(sorted(removed_labels))}")
188+
189+
# Compare files
190+
old_files = set_or_empty(old_entry, "files")
191+
new_files = set_or_empty(new_entry, "files")
192+
added_files = new_files - old_files
193+
removed_files = old_files - new_files
194+
if added_files:
195+
changes.append(f" Files added: {', '.join(sorted(added_files))}")
196+
if removed_files:
197+
changes.append(f" Files removed: {', '.join(sorted(removed_files))}")
198+
199+
# Compare files-regex
200+
old_regex = set_or_empty(old_entry, "files-regex")
201+
new_regex = set_or_empty(new_entry, "files-regex")
202+
added_regex = new_regex - old_regex
203+
removed_regex = old_regex - new_regex
204+
if added_regex:
205+
changes.append(f" files-regex added: {', '.join(sorted(added_regex))}")
206+
if removed_regex:
207+
changes.append(f" files-regex removed: {', '.join(sorted(removed_regex))}")
208+
209+
if changes:
210+
changed_areas.add(area)
211+
print(f"area changed: {area}")
212+
213+
return added_areas | removed_areas | changed_areas
107214

108215
def process_pr(gh, maintainer_file, number):
109216
gh_repo = gh.get_repo(f"{args.org}/{args.repo}")
@@ -129,6 +236,7 @@ def process_pr(gh, maintainer_file, number):
129236
meta_areas = ['Release Notes', 'Documentation', 'Samples', 'Tests']
130237

131238
collab_per_path = []
239+
additional_reviews = set()
132240
for changed_file in fn:
133241
num_files += 1
134242
log(f"file: {changed_file.filename}")
@@ -144,6 +252,22 @@ def process_pr(gh, maintainer_file, number):
144252
area_match = maintainer_file.name2areas(_area)
145253
if area_match:
146254
areas.extend(area_match)
255+
elif changed_file.filename in ['MAINTAINERS.yml']:
256+
areas = maintainer_file.path2areas(changed_file.filename)
257+
if args.updated_maintainer_file:
258+
log(
259+
"No updated maintainer file, cannot process MAINTAINERS.yml changes, skipping..."
260+
)
261+
262+
old_areas = load_areas(args.updated_maintainer_file)
263+
new_areas = load_areas('MAINTAINERS.yml')
264+
changed_areas = compare_areas(old_areas, new_areas)
265+
for _area in changed_areas:
266+
area_match = maintainer_file.name2areas(_area)
267+
if area_match:
268+
# get list of maintainers for changed area
269+
additional_reviews.update(maintainer_file.areas[_area].maintainers)
270+
log(f"MAINTAINERS.yml changed, adding reviewrs: {additional_reviews}")
147271
else:
148272
areas = maintainer_file.path2areas(changed_file.filename)
149273
for _area in areas:
@@ -192,6 +316,8 @@ def process_pr(gh, maintainer_file, number):
192316
collab += collab_per_path
193317

194318
collab = list(dict.fromkeys(collab))
319+
# add more reviewers based on maintainer file changes.
320+
collab += list(additional_reviews)
195321
log(f"collab: {collab}")
196322

197323
_all_maintainers = dict(

0 commit comments

Comments
 (0)