blob: 8f725858331fa85556cfa92172aa067c3b5a79f0 [file] [log] [blame]
# Copyright 2023 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.
def black(ctx):
tools_dir = _install_tools(ctx)
py_files = [
f
for f in ctx.scm.affected_files()
if f.endswith(".py") and
# recipes.py is vendored from the recipe engine and should be
# ignored.
f != "recipes.py"
]
if not py_files:
return
original_contents = {}
procs = {}
for filepath in py_files:
original = str(ctx.io.read_file(filepath))
original_contents[filepath] = original
procs[filepath] = ctx.os.exec([tools_dir + "/black", "-"], stdin = original)
for filepath, proc in procs.items():
res = proc.wait()
original = original_contents[filepath]
if res.stdout != original:
ctx.emit.finding(
filepath = filepath,
level = "error",
replacements = [res.stdout],
)
def proto_format(ctx):
tools_dir = _install_tools(ctx)
procs = []
for p in ctx.scm.affected_files():
if not p.endswith(".proto"):
continue
# TODO(olivernewman): Use a single `buf format` invocation and the
# --diff option once shac knows how to parse diffs.
cmd = [
tools_dir + "/buf",
"format",
"--exit-code",
p,
]
procs.append((p, ctx.os.exec(cmd, ok_retcodes = [0, 100])))
for p, proc in procs:
res = proc.wait()
if res.retcode == 100:
ctx.emit.finding(
filepath = p,
level = "error",
replacements = [res.stdout],
)
def _install_tools(ctx):
install_dir = ctx.scm.root + "/.tools"
ctx.os.exec(
["scripts/install-shac-tools.sh", install_dir],
allow_network = True,
).wait()
return install_dir
def check_deps(ctx):
res = ctx.os.exec(
[
"python3",
"scripts/cleanup_deps.py",
"--check",
"--json-output",
"-",
],
ok_retcodes = [0, 65],
).wait()
if res.retcode == 65:
for file in json.decode(res.stdout):
# TODO(olivernewman): Parse the diff so fixes can be applied with
# `shac fix`.
ctx.emit.finding(
filepath = file,
message = "DEPS are malformatted. Run ./scripts/cleanup_deps.py to fix.",
level = "error",
)
def recipe_style_guide(ctx):
"""Enforces http://go/fuchsia-recipe-docs#style-guide."""
procs = []
for f in ctx.scm.affected_files():
if f.endswith(".json") and ".expected" in f:
test_name = f.split("/")[-1].rsplit(".", 1)[0]
if " " in test_name:
# It would be nicer to parse the recipe file to find test case
# names because then we could emit the finding at the place
# where the test name is defined. But because tests are
# generated by arbitrary Python code, it's practically
# impossible to parse out their names in a foolproof way.
ctx.emit.finding(
filepath = f,
message = "Test name %r should not contain spaces" % test_name,
level = "error",
)
if not f.endswith(".py"):
continue
procs.append(ctx.os.exec(["python3", "scripts/enforce_style_guide.py", f]))
for proc in procs:
res = proc.wait()
for finding in json.decode(res.stdout):
ctx.emit.finding(**finding)
shac.register_check(shac.check(black, formatter = True))
shac.register_check(shac.check(proto_format, formatter = True))
shac.register_check(check_deps)
shac.register_check(recipe_style_guide)