blob: cdd903dc295beab63b6ac0d94075159bf9fad108 [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""SHAC check enforcing a one-way presubmit ratchet against direct //prebuilt references."""
load("./common.star", "cipd_platform_name", "get_fuchsia_dir", "os_exec")
# LINT.IfChange
_EXCLUDED_PATHS = (
"build/bazel/rules/cipd_prebuilt.bzl",
"scripts/shac/bazel_lint/checks/tests/root_package_labels_test.star",
"scripts/shac/prebuilts.star",
"scripts/shac/tests/prebuilts_test.star",
)
_EXCLUDED_DIR_PREFIXES = (
"build/prebuilt/",
"third_party/",
"docs/",
"manifests/",
"tools/check-licenses/assets/readmes/",
)
_EXCLUDED_BASENAMES = (
"OWNERS",
"LICENSE",
"AUTHORS",
"PATENTS",
"README",
"NOTICE",
"COPYING",
"CONTRIBUTORS",
"CODEOWNERS",
)
_CHECKED_SUFFIXES = (
".gn",
".gni",
".bazel",
".bzl",
".fx",
".sh",
".bash",
".py",
".star",
".cmake",
".c",
".cc",
".cpp",
".h",
".hpp",
".rs",
".go",
".dart",
)
# LINT.ThenChange(//build/prebuilt/on_demand_migration/scripts/ratchet/languages.py)
def _is_checked_file(path):
if path in _EXCLUDED_PATHS:
return False
for prefix in _EXCLUDED_DIR_PREFIXES:
if path.startswith(prefix):
return False
if path.startswith("testdata/") or "/testdata/" in path:
return False
basename = path.rsplit("/", 1)[-1]
if basename in _EXCLUDED_BASENAMES:
return False
if basename == "CMakeLists.txt":
return True
if "." not in basename:
return True
for suffix in _CHECKED_SUFFIXES:
if basename.endswith(suffix):
return True
return False
def check_no_new_direct_prebuilts(ctx):
"""Enforces a one-way ratchet against direct //prebuilt references.
Args:
ctx: A SHAC ctx instance.
"""
files = [
path
for path in ctx.scm.affected_files()
if _is_checked_file(path)
]
if not files:
return
fuchsia_dir = get_fuchsia_dir(ctx)
python_bin = "%s/prebuilt/third_party/python3/%s/bin/python3" % (
fuchsia_dir,
cipd_platform_name(ctx),
)
checker_script = (
"%s/build/prebuilt/on_demand_migration/scripts/ratchet/ratchet.py" %
fuchsia_dir
)
files_file = ctx.io.tempfile("\n".join(files) + "\n")
completed = os_exec(
ctx,
[
python_bin,
checker_script,
"--root",
ctx.scm.root,
"--json",
"--files-from",
files_file,
],
ok_retcodes = (0, 1),
).wait()
findings = json.decode(completed.stdout)
if type(findings) != "list":
fail("Expected a list of findings from %s (exit code %d), got: %s\nstderr: %s" % (
checker_script,
completed.retcode,
completed.stdout,
completed.stderr,
))
if bool(completed.retcode) != bool(findings):
fail("%s exited with code %d, but reported %d findings" % (
checker_script,
completed.retcode,
len(findings),
))
for finding in findings:
ctx.emit.finding(
level = finding.get("level", "error"),
filepath = finding["filepath"],
line = finding["line"],
col = finding["col"],
message = finding["message"],
)
def register_prebuilt_checks():
shac.register_check(shac.check(check_no_new_direct_prebuilts))