Source code

Revision control

Copy as Markdown

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at
import difflib
import os
import sys
import yaml
from manifestparser import TestManifest
from mozlint import result
from mozlint.pathutils import expand_exclusions
from mozpack import path as mozpath
# Since this linter matches on all files with .ini extensions, we can omit
# those extensions from this allowlist, which makes it easier to match
# against variants like "mochitest-serviceworker.ini".
FILENAME_ALLOWLIST = ["mochitest", "browser", "chrome", "a11y"]
here = os.path.abspath(os.path.dirname(__file__))
ERROR_LEVEL_MANIFESTS_PATH = os.path.join(here, "error-level-manifests.yml")
def lint(paths, config, fix=None, **lintargs):
error_level_manifests = yaml.safe_load(f)
except (IOError, ValueError) as e:
print("{}: error:\n {}".format(ERROR_LEVEL_MANIFESTS_PATH, e), file=sys.stderr)
topsrcdir = lintargs["root"]
results = []
file_names = list(expand_exclusions(paths, config, lintargs["root"]))
for file_name in file_names:
name = os.path.basename(file_name)
if not any(name.startswith(allowed) for allowed in FILENAME_ALLOWLIST):
manifest = TestManifest(manifests=(file_name,), strict=False)
test_names = [test["name"] for test in manifest.tests]
sorted_test_names = sorted(test_names)
if test_names != sorted_test_names:
rel_file_path = mozpath.relpath(file_name, topsrcdir)
level = "warning"
if (mozpath.normsep(rel_file_path) in error_level_manifests) or (
mozpath.match(rel_file_path, e)
for e in error_level_manifests
if "*" in e
level = "error"
diff_instance = difflib.Differ()
diff_result =, sorted_test_names)
diff_list = list(diff_result)
res = {
"path": rel_file_path,
"lineno": 0,
"column": 0,
"message": (
"The mochitest test manifest is not in alphabetical order. "
"Expected ordering: \n\n%s\n\n" % "\n".join(sorted_test_names)
"level": level,
"diff": "\n".join(diff_list),
results.append(result.from_config(config, **res))
return {"results": results, "fixed": 0}