[ssci] Script to run validation on all metadata files
Adds script metadata/scan.py which can be used to search for and validate Chromium dependency metadata files, given a repository root directory. Bug: b:277147404 Change-Id: Ibde0eeb7babe0b1e3f9c7f887bece629d390974a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4823596 Commit-Queue: Anne Redulla <aredulla@google.com> Reviewed-by: Rachael Newitt <renewitt@google.com>changes/96/4823596/3
parent
e36c6bba14
commit
427f0f43ad
@ -1,4 +1,18 @@
|
||||
# Validation for Chromium's Third Party Metadata Files
|
||||
|
||||
This directory contains the code to validate Chromium's third party metadata
|
||||
This directory contains the code to validate Chromium third party metadata
|
||||
files, i.e. `README.chromium` files.
|
||||
|
||||
## Prerequisites
|
||||
1. Have the Chromium source code
|
||||
[checked out](https://chromium.googlesource.com/chromium/src/+/main/docs/#checking-out-and-building) on disk
|
||||
1. Ensure you've run `gclient runhooks` on your source checkout
|
||||
|
||||
## Run
|
||||
`metadata/scan.py` can be used to search for and validate all Chromium third
|
||||
party metadata files within a repository. For example, if your `chromium/src`
|
||||
checkout is at `~/my/path/to/chromium/src`, run the following command from the
|
||||
root directory of `depot_tools`:
|
||||
```
|
||||
vpython3 --vpython-spec=.vpython3 metadata/scan.py ~/my/path/to/chromium/src
|
||||
```
|
||||
|
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2023 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
import os
|
||||
import sys
|
||||
|
||||
_THIS_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
# The repo's root directory.
|
||||
_ROOT_DIR = os.path.abspath(os.path.join(_THIS_DIR, ".."))
|
||||
|
||||
# Add the repo's root directory for clearer imports.
|
||||
sys.path.insert(0, _ROOT_DIR)
|
||||
|
||||
import metadata.discover
|
||||
import metadata.validate
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Helper to parse args to this script."""
|
||||
parser = argparse.ArgumentParser()
|
||||
repo_root_dir = parser.add_argument(
|
||||
"repo_root_dir",
|
||||
help=("The path to the repository's root directory, which will be "
|
||||
"scanned for Chromium metadata files, e.g. '~/chromium/src'."),
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Check the repo root directory exists.
|
||||
src_dir = os.path.abspath(args.repo_root_dir)
|
||||
if not os.path.exists(src_dir) or not os.path.isdir(src_dir):
|
||||
raise argparse.ArgumentError(
|
||||
repo_root_dir,
|
||||
f"Invalid repository root directory '{src_dir}' - not found",
|
||||
)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Runs validation on all metadata files within the directory specified by the
|
||||
repo_root_dir arg.
|
||||
"""
|
||||
config = parse_args()
|
||||
src_dir = os.path.abspath(config.repo_root_dir)
|
||||
|
||||
metadata_files = metadata.discover.find_metadata_files(src_dir)
|
||||
file_count = len(metadata_files)
|
||||
print(f"Found {file_count} metadata files.")
|
||||
|
||||
invalid_file_count = 0
|
||||
|
||||
# Key is constructed from the result severity and reason;
|
||||
# Value is a list of files affected by that reason at that severity.
|
||||
all_reasons = defaultdict(list)
|
||||
for filepath in metadata_files:
|
||||
file_results = metadata.validate.validate_file(filepath,
|
||||
repo_root_dir=src_dir)
|
||||
invalid = False
|
||||
if file_results:
|
||||
relpath = os.path.relpath(filepath, start=src_dir)
|
||||
print(f"\n{len(file_results)} problem(s) in {relpath}:")
|
||||
for result in file_results:
|
||||
print(f" {result}")
|
||||
summary_key = "{severity} - {reason}".format(
|
||||
severity=result.get_severity_prefix(), reason=result.get_reason())
|
||||
all_reasons[summary_key].append(relpath)
|
||||
if result.is_fatal():
|
||||
invalid = True
|
||||
|
||||
if invalid:
|
||||
invalid_file_count += 1
|
||||
|
||||
print("\n\nDone.\nSummary:")
|
||||
for summary_key, affected_files in all_reasons.items():
|
||||
count = len(affected_files)
|
||||
plural = "s" if count > 1 else ""
|
||||
print(f"\n {count} file{plural}: {summary_key}")
|
||||
for affected_file in affected_files:
|
||||
print(f" {affected_file}")
|
||||
|
||||
print(f"\n\n{invalid_file_count} / {file_count} metadata files are invalid, "
|
||||
"i.e. the file has at least one fatal validation issue.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue