"""Implementation for shellcheck_test.""" def _impl(ctx): """Implementation for shellchecking a single file. A macro is provided to allow declaring multiple at one time.""" ctx.actions.expand_template( template = ctx.file._shellcheck_sh_tpl, output = ctx.outputs.executable, is_executable = True, substitutions = { "{{file}}": ctx.file.src.short_path, "{{shell2junit_path}}": ctx.file._sh2junit_sh.short_path, "{{shellcheck_path}}": ctx.executable._shellcheck.short_path, }, ) return DefaultInfo( executable = ctx.outputs.executable, runfiles = ctx.runfiles( files = [ ctx.file._shellcheck, ctx.file._sh2junit_sh, ctx.file.src, ], ), ) _shellcheck_test = rule( doc = "Bazel rule for linting shell scripts using shellcheck as a test.", implementation = _impl, test = True, attrs = { "src": attr.label( doc = "Shell script to lint", allow_single_file = [".sh"], mandatory = True, ), "_shellcheck": attr.label( default = Label("//hack/build/rules/shellcheck:shellcheck"), allow_single_file = True, executable = True, cfg = "exec", ), "_shellcheck_sh_tpl": attr.label( default = Label("//hack/build/rules/shellcheck:shellcheck.sh.tpl"), allow_single_file = True, executable = False, ), "_sh2junit_sh": attr.label( default = Label("//third_party/sh/shell2junit"), allow_single_file = True, executable = False, ), }, ) # buildifier: disable=unnamed-macro # the name comes from the files def shellcheck_test(srcs): for s in srcs: _shellcheck_test( name = "{0}_test".format(s.replace("-", "_").replace(".", "_")), src = s, )