Source code
Revision control
Copy as Markdown
Other Tools
# This Source Code Form is subject to the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
import re
import mozpack.path as mozpath
from mozlint import result
from mozlint.pathutils import expand_exclusions
# Must stay in sync with WPT_SUBSUITES in
# taskcluster/gecko_taskgraph/util/chunking.py. The chunking logic routes
# tests to subsuite CI jobs by checking whether the test's directory path
# starts with one of these strings. Tests in matching directories that lack the
# corresponding tag will be excluded from all CI jobs.
WPT_SUBSUITE_PATHS = {
"canvas": ["html/canvas"],
"webgpu": ["webgpu"],
"webcodecs": [
"webcodecs",
"media-source/mse-for-webcodecs",
],
"eme": ["encrypted-media"],
"webrtc": ["webrtc"],
}
# Must stay in sync with WPT_SUBSUITES in taskcluster/gecko_taskgraph/util/chunking.py.
_TESTS_META_PAIRS = [
("testing/web-platform/tests", "testing/web-platform/meta"),
("testing/web-platform/mozilla/tests", "testing/web-platform/mozilla/meta"),
]
_TAGS_RE = re.compile(r"^\s*tags:\s*\[([^\]]*)\]")
def _get_ini_tags(ini_path):
tags = set()
try:
with open(ini_path) as f:
for line in f:
m = _TAGS_RE.match(line)
if m:
for tag in m.group(1).split(","):
tags.add(tag.strip())
except OSError:
pass
return tags
def _effective_tags(rel_path, meta_root):
tags = set()
tags |= _get_ini_tags(mozpath.join(meta_root, rel_path + ".ini"))
parts = rel_path.split("/")
for depth in range(len(parts)):
tags |= _get_ini_tags(mozpath.join(meta_root, *parts[:depth], "__dir__.ini"))
return tags
def lint(paths, config, fix=None, **lintargs):
results = []
# expand_exclusions yields forward-slash-normalized paths (via mozpath.normsep),
# so all path matching below is done in forward-slash form to work on Windows too.
root = mozpath.normsep(lintargs["root"])
for path in expand_exclusions(paths, config, lintargs["root"]):
for tests_root, meta_root in _TESTS_META_PAIRS:
abs_tests_root = mozpath.join(root, tests_root)
if not path.startswith(abs_tests_root + "/"):
continue
rel_path = path[len(abs_tests_root) + 1 :]
url_dir = "/".join(rel_path.split("/")[:-1]) + "/"
for subsuite, subsuite_paths in WPT_SUBSUITE_PATHS.items():
if not any(url_dir.startswith(p) for p in subsuite_paths):
continue
tags = _effective_tags(rel_path, mozpath.join(root, meta_root))
if not any(t == subsuite or t.startswith(subsuite + "-") for t in tags):
results.append(
result.from_config(
config,
path=path,
lineno=1,
message=(
f"Test is in a '{subsuite}' subsuite directory but has no "
f"'{subsuite}' tag in its metadata. It will not run in any "
f"CI job. Add 'tags: [{subsuite}]' to the test's .ini file "
f"or a parent __dir__.ini."
),
level="error",
)
)
return {"results": results, "fixed": 0}