From 5d6bf81321504f337449e3e02006314907e56240 Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Tue, 20 Sep 2022 14:37:45 -0700 Subject: [PATCH] Create a `licence_test` rule The `license_test` rule executes the licence checker as a bazel test (rather than an executable), thus allowing an upstream project to use the rule as part of a set of presubmit tests. Signed-off-by: Chris Frantz --- rules/licence-checker-runner.template.sh | 12 ++- rules/rules.bzl | 105 ++++++++++++++--------- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/rules/licence-checker-runner.template.sh b/rules/licence-checker-runner.template.sh index d28b1aa..015a5c4 100644 --- a/rules/licence-checker-runner.template.sh +++ b/rules/licence-checker-runner.template.sh @@ -3,8 +3,16 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -if ! cd "$BUILD_WORKSPACE_DIRECTORY"; then - echo "Unable to change to workspace (BUILD_WORKSPACE_DIRECTORY: ${BUILD_WORKSPACE_DIRECTORY})" +WORKSPACE="@@WORKSPACE@@" + +if [[ ! -z "${WORKSPACE}" ]]; then + REPO="$(dirname "$(realpath ${WORKSPACE})")" + cd ${REPO} || exit 1 +elif [[ ! -z "${BUILD_WORKSPACE_DIRECTORY+is_set}" ]]; then + cd ${BUILD_WORKSPACE_DIRECTORY} || exit 1 +else + echo "Neither WORKSPACE nor BUILD_WORKSPACE_DIRECTORY were set." + echo "If this is a test rule, add 'workspace = \"//:WORKSPACE\"' to your rule." exit 1 fi diff --git a/rules/rules.bzl b/rules/rules.bzl index d7444b2..22a0533 100644 --- a/rules/rules.bzl +++ b/rules/rules.bzl @@ -17,7 +17,7 @@ def _licence_check_impl(ctx): substitutions = { "@@LICENCE@@": "'''" + ctx.attr.licence + "'''", "@@MATCH_REGEX@@": "true" if ctx.attr.match_regex else "false", - "@@EXCLUDE_PATHS@@": ', '.join(['"{}"'.format(pat) for pat in ctx.attr.exclude_patterns]), + "@@EXCLUDE_PATHS@@": ", ".join(['"{}"'.format(pat) for pat in ctx.attr.exclude_patterns]), }, ) @@ -35,6 +35,7 @@ def _licence_check_impl(ctx): command = 'touch "{}"'.format(checker.path), ) + workspace = ctx.file.workspace.path if ctx.file.workspace else "" script = ctx.actions.declare_file(ctx.label.name + ".bash") ctx.actions.expand_template( template = ctx.file._runner, @@ -42,13 +43,18 @@ def _licence_check_impl(ctx): substitutions = { "@@LICENCE_CHECKER@@": ctx.executable.licence_check.path, "@@CONFIG@@": config.path, + "@@WORKSPACE@@": workspace, }, is_executable = True, ) - runfiles = ctx.runfiles(files = [config, checker], transitive_files = ctx.attr.licence_check.files) + files = [config, checker] + if ctx.file.workspace: + files.append(ctx.file.workspace) + + runfiles = ctx.runfiles(files = files, transitive_files = ctx.attr.licence_check.files) runfiles = runfiles.merge( - ctx.attr.licence_check.default_runfiles, + ctx.attr.licence_check.default_runfiles, ) return DefaultInfo( @@ -56,47 +62,67 @@ def _licence_check_impl(ctx): executable = script, ) +licence_check_attrs = { + "config": attr.label( + allow_single_file = True, + doc = "HJSON configuration file override for the licence checker", + ), + "licence": attr.string( + mandatory = True, + doc = "Text of the licence header to use", + ), + "match_regex": attr.bool( + default = False, + doc = "Whether to use regex-matching for the licence text", + ), + "exclude_patterns": attr.string_list( + default = [], + doc = "File patterns to exclude from licence enforcement", + ), + "licence_check": attr.label( + default = "//licence-checker", + cfg = "host", + executable = True, + doc = "The licence checker executable", + ), + "workspace": attr.label( + allow_single_file = True, + doc = "Label of the WORKSPACE file", + ), + "_runner": attr.label( + default = "//rules:licence-checker-runner.template.sh", + allow_single_file = True, + ), + "_config": attr.label( + default = "//rules:licence-checker-config.template.hjson", + allow_single_file = True, + ), +} + licence_check = rule( implementation = _licence_check_impl, - attrs = { - "config": attr.label( - allow_single_file = True, - doc = "HJSON configuration file override for the licence checker", - ), - "licence": attr.string( - mandatory = True, - doc = "Text of the licence header to use", - ), - "match_regex": attr.bool( - default = False, - doc = "Whether to use regex-matching for the licence text", - ), - "exclude_patterns": attr.string_list( - default = [], - doc = "File patterns to exclude from licence enforcement", - ), - "licence_check": attr.label( - default = "//licence-checker", - cfg = "host", - executable = True, - doc = "The licence checker executable", - ), - "_runner": attr.label( - default = "//rules:licence-checker-runner.template.sh", - allow_single_file = True, - ), - "_config": attr.label( - default = "//rules:licence-checker-config.template.hjson", - allow_single_file = True, - ), - "_sh_runfiles": attr.label( - default = "@bazel_tools//tools/bash/runfiles", - allow_single_file = True, - ), - }, + attrs = licence_check_attrs, executable = True, ) +_licence_test = rule( + implementation = _licence_check_impl, + attrs = licence_check_attrs, + test = True, +) + +def _ensure_tag(tags, *tag): + for t in tag: + if t not in tags: + tags.append(t) + return tags + +def licence_test(**kwargs): + # Note: the "external" tag is a workaround for bazelbuild#15516. + tags = kwargs.get("tags", []) + kwargs["tags"] = _ensure_tag(tags, "no-sandbox", "no-cache", "external") + _licence_test(**kwargs) + def _yapf_check_impl(ctx): # Hack to make Bazel build the checker correctly. # @@ -173,4 +199,3 @@ yapf_check = rule( }, executable = True, ) -