Skip to content

Commit 4419089

Browse files
carlescufifabiobaltieri
authored andcommitted
action: Check additional metadata in projects
Until now this action was only looking at differences in revision for all the projects in the manifest. However, there are other items of metadata that can be highly sensitive, and changes to those must be monitored and reported. This commit introduces additional checks for the following metadata items: - URL: part of the manifest, URL to the project repository - Submodules: part of the manifest, enabled submodules when running west update - West commands: part of the manifest, pointer to a file defining extensions commands for west itself - module.yml: the Zephyr module metadata file If any of the items above is added, removed or changed, the DNM label will not be removed from the Pull Request, in order for a human to decide if the PR is to be merged or not. Signed-off-by: Carles Cufi <[email protected]>
1 parent ebe8cfa commit 4419089

File tree

1 file changed

+75
-5
lines changed

1 file changed

+75
-5
lines changed

action.py

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def manifest_at_rev(sha):
260260

261261
return (old_manifest, new_manifest)
262262

263-
def _get_merge_status(len_a, len_r, len_pr, impostor_shas):
263+
def _get_merge_status(len_a, len_r, len_pr, len_meta, impostor_shas, unreachables):
264264
strs = []
265265
def plural(count):
266266
return 's' if count > 1 else ''
@@ -271,13 +271,17 @@ def plural(count):
271271
strs.append(f'{len_r} removed project{plural(len_r)}')
272272
if len_pr:
273273
strs.append(f'{len_pr} project{plural(len_pr)} with PR revision')
274+
if len_meta:
275+
strs.append(f'{len_meta} project{plural(len_meta)} with metadata changes')
274276
if impostor_shas:
275277
strs.append(f'{impostor_shas} impostor SHA{plural(impostor_shas)}')
278+
if unreachables:
279+
strs.append(f'{unreachables} unreachable repo{plural(unreachables)}')
276280

277281
if not len(strs):
278282
return False, '\u2705 **All manifest checks OK**'
279283

280-
n = '\u274c **DNM label due to: '
284+
n = '\U000026D4 **DNM label due to: '
281285
for i, s in enumerate(strs):
282286
if i == (len(strs) - 1):
283287
_s = f'and {s}' if len(strs) > 1 else s
@@ -445,6 +449,8 @@ def main():
445449
log(f'projs_names: {str(projs_names)}')
446450

447451
impostor_shas = 0
452+
unreachables = 0
453+
files = dict()
448454
# Link main PR to project PRs
449455
strs = list()
450456
if message:
@@ -462,6 +468,8 @@ def main():
462468
new_rev = None if p in rprojs else p[1]
463469
or_note = ' (Added)' if not old_rev else ''
464470
nr_note = ' (Removed)' if not new_rev else ''
471+
name_note = ' \U0001F195' if not old_rev else ' \U0000274c ' if \
472+
not new_rev else ''
465473
url = manifest.get_projects([p[0]])[0].url
466474
re_url = re.compile(r'https://github\.com/'
467475
'([A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+)/?')
@@ -470,15 +478,18 @@ def main():
470478
except (GithubException, TypeError) as error:
471479
log(error)
472480
log(f"Can't get repo for {p[0]}; output will be limited")
473-
strs.append(f'| {p[0]} | {old_rev}{or_note} | {new_rev}{nr_note} | N/A |')
481+
strs.append(f'| {p[0]}{name_note} | {old_rev}{or_note} | {new_rev}{nr_note} | N/A |')
482+
unreachables += 1
474483
continue
475484

476-
line = f'| {p[0]} | {fmt_rev(repo, old_rev)}{or_note} '
485+
line = f'| {p[0]}{name_note} | {fmt_rev(repo, old_rev)}{or_note} '
477486
if p in pr_projs:
478487
pr = repo.get_pull(int(re_rev.match(new_rev)[1]))
479488
line += f'| {pr.html_url}{nr_note} '
480489
line += f'| [{repo.full_name}#{pr.number}/files]' + \
481490
f'({pr.html_url}/files) |'
491+
# Store files changed
492+
files[p[0]] = [f for f in pr.get_files()]
482493
else:
483494
if check_impostor and new_rev and is_impostor(repo, new_rev):
484495
impostor_shas += 1
@@ -489,14 +500,73 @@ def main():
489500
line += f'| [{repo.full_name}@{shorten_rev(old_rev)}..' + \
490501
f'{shorten_rev(new_rev)}]' + \
491502
f'({repo.html_url}/compare/{old_rev}..{new_rev}) |'
503+
# Store files changed
504+
try:
505+
c = repo.compare(old_rev, new_rev)
506+
files[p[0]] = [f for f in c.files]
507+
except GithubException as e:
508+
log(e)
509+
log(f"Can't get files changed for {p[0]}")
492510
else:
493511
line += '| N/A |'
494512

495513
strs.append(line)
496514

515+
def _hashable(o):
516+
if isinstance(o, list):
517+
return frozenset(o)
518+
return o
519+
520+
def _module_changed(p):
521+
if p.name in files:
522+
for f in files[p.name]:
523+
if ('zephyr/module.yml' in f.filename or
524+
'zephyr/module.yaml' in f.filename):
525+
return True
526+
return False
527+
528+
# Check additional metadata
529+
meta_op = set((p.name, p.url, _hashable(p.submodules),
530+
_hashable(p.west_commands), False) for p in ops)
531+
meta_np = set((p.name, p.url, _hashable(p.submodules),
532+
_hashable(p.west_commands), _module_changed(p)) for p in nps)
533+
534+
log('Metadata sets')
535+
(_, meta_rprojs, meta_uprojs, meta_aprojs) = _get_sets(meta_op, meta_np)
536+
meta_projs = meta_uprojs | meta_aprojs
537+
538+
def _cmp_old_new(p, index, force_change=False):
539+
old = None if p in meta_aprojs else next(filter(lambda _p: _p[0] == p[0], meta_op))[index]
540+
new = next(filter(lambda _p: _p[0] == p[0], meta_np))[index]
541+
log(f'name: {p[0]} index: {index} old: {old} new: {new}')
542+
# Special handling for an added project
543+
if old is None and not new:
544+
return ''
545+
# Select which symbol to show
546+
if not old and new:
547+
return '\U0001F195' if not force_change else '\u270f' # added
548+
elif not new and old:
549+
return '\u274c' # removed
550+
elif new != old:
551+
return '\u270f' # modified
552+
else:
553+
return ''
554+
555+
if len(meta_uprojs):
556+
strs.append('\n\nAdditional metadata changed:\n')
557+
strs.append('| Name | URL | Submodules | West cmds | `module.yml` | ')
558+
strs.append('| ---- | --- | ---------- | --------- | ------------ | ')
559+
for p in sorted(meta_uprojs, key=lambda _p: _p[0]):
560+
url = _cmp_old_new(p, 1)
561+
subms = _cmp_old_new(p, 2)
562+
wcmds = _cmp_old_new(p, 3)
563+
mys = _cmp_old_new(p, 4, True)
564+
line = f'| {p[0]} | {url} | {subms} | {wcmds} | {mys} |'
565+
strs.append(line)
566+
497567
# Add a note about the merge status of the manifest PR
498568
dnm, status_note = _get_merge_status(len(aprojs), len(rprojs), len(pr_projs),
499-
impostor_shas)
569+
len(meta_uprojs), impostor_shas, unreachables)
500570
status_note = f'\n\n{status_note}'
501571

502572
message = '\n'.join(strs) + status_note + NOTE

0 commit comments

Comments
 (0)