blob: 29e338f4d162eb337c77f9b330681381530a3d54 [file] [log] [blame]
load(
"@io_bazel_rules_go//go/private:context.bzl",
"go_context",
)
load(
"@io_bazel_rules_go//go/private:go_repository.bzl",
"env_execute",
)
load(
"@io_bazel_rules_go//go/private:rules/rule.bzl",
"go_rule",
)
load(
"@io_bazel_rules_go//go/private:skylib/lib/paths.bzl",
"paths",
)
load(
"@io_bazel_rules_go//go/private:skylib/lib/shell.bzl",
"shell",
)
# _bazelrc is the bazel.rc file that sets the default options for tests
_bazelrc = """
build --verbose_failures
build --sandbox_debug
build --test_output=errors
build --spawn_strategy=standalone
build --genrule_strategy=standalone
test --test_strategy=standalone
build:isolate --
build:fetch --fetch=True
"""
# _basic_workspace is the content appended to all test workspace files
# it contains the calls required to make the go rules work
_basic_workspace = """
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
load("@io_bazel_rules_go//proto:def.bzl", "proto_register_toolchains")
go_rules_dependencies()
proto_register_toolchains()
"""
# _bazel_test_script_template is hte template for the bazel invocation script
_bazel_test_script_template = """
echo running in {work_dir}
unset TEST_TMPDIR
RULES_GO_OUTPUT={output}
mkdir -p {work_dir}
mkdir -p {cache_dir}
cp -f {workspace} {work_dir}/WORKSPACE
cp -f {build} {work_dir}/BUILD.bazel
extra_files=({extra_files})
if [ "${{#extra_files[@]}}" -ne 0 ]; then
cp -f "${{extra_files[@]}}" {work_dir}/
fi
cd {work_dir}
{bazel} --bazelrc {bazelrc} {command} --experimental_repository_cache={cache_dir} --config {config} {args} {target} >& bazel-output.txt
result=$?
{check}
if [ "$result" -ne 0 ]; then
cat bazel-output.txt
fi
exit $result
"""
# _env_build_template is the template for the bazel test environment repository build file
_env_build_template = """
load("@io_bazel_rules_go//tests:bazel_tests.bzl", "bazel_test_settings")
bazel_test_settings(
name = "settings",
bazel = "{bazel}",
exec_root = "{exec_root}",
scratch_dir = "{scratch_dir}",
visibility = ["//visibility:public"],
)
filegroup(
name = "bazelrc",
srcs = ["test.bazelrc"],
visibility = ["//visibility:public"],
)
"""
CURRENT_VERSION = "current"
def _bazel_test_script_impl(ctx):
go = go_context(ctx)
script_file = go.declare_file(go, ext=".bash")
if ctx.attr.go_version == CURRENT_VERSION:
register = 'go_register_toolchains()\n'
elif ctx.attr.go_version != None:
register = 'go_register_toolchains(go_version="{}")\n'.format(ctx.attr.go_version)
workspace_content = 'workspace(name = "bazel_test")\n\n'
for ext in ctx.attr.externals:
root = ext.label.workspace_root
_,_,name = ext.label.workspace_root.rpartition("/")
workspace_content += 'local_repository(name="{name}", path="{exec_root}/{root}")\n'.format(
name = name,
root = root,
exec_root = ctx.attr._settings.exec_root,
)
if ctx.attr.workspace:
workspace_content += ctx.attr.workspace
else:
workspace_content += _basic_workspace.format()
workspace_content += register
workspace_file = go.declare_file(go, path="WORKSPACE.in")
ctx.actions.write(workspace_file, workspace_content)
build_file = go.declare_file(go, path="BUILD.in")
ctx.actions.write(build_file, ctx.attr.build)
targets = ["@" + ctx.workspace_name + "//" + ctx.label.package + t if t.startswith(":") else t for t in ctx.attr.targets]
output = "external/" + ctx.workspace_name + "/" + ctx.label.package
script_content = _bazel_test_script_template.format(
bazelrc = shell.quote(ctx.attr._settings.exec_root + "/" + ctx.file._bazelrc.path),
config = ctx.attr.config,
extra_files = " ".join([shell.quote(paths.join(ctx.attr._settings.exec_root, "execroot", "io_bazel_rules_go", file.path)) for file in ctx.files.extra_files]),
command = ctx.attr.command,
args = " ".join(ctx.attr.args),
target = " ".join(targets),
check = ctx.attr.check,
workspace = shell.quote(workspace_file.short_path),
build = shell.quote(build_file.short_path),
output = shell.quote(output),
bazel = ctx.attr._settings.bazel,
work_dir = shell.quote(ctx.attr._settings.scratch_dir + "/" + ctx.attr.config),
cache_dir = shell.quote(ctx.attr._settings.scratch_dir + "/cache"),
)
ctx.actions.write(output = script_file, is_executable = True, content = script_content)
return struct(
files = depset([script_file]),
runfiles = ctx.runfiles(
[workspace_file, build_file] + ctx.files.extra_files,
collect_data = True,
),
)
_bazel_test_script = go_rule(
_bazel_test_script_impl,
attrs = {
"command": attr.string(
mandatory = True,
values = [
"build",
"test",
"coverage",
"run",
],
),
"args": attr.string_list(default = []),
"targets": attr.string_list(mandatory = True),
"externals": attr.label_list(allow_files = True),
"go_version": attr.string(default = CURRENT_VERSION),
"workspace": attr.string(),
"build": attr.string(),
"check": attr.string(),
"config": attr.string(default = "isolate"),
"extra_files": attr.label_list(allow_files = True),
"data": attr.label_list(
allow_files = True,
cfg = "data",
),
"_bazelrc": attr.label(
allow_files = True,
single_file = True,
default = "@bazel_test//:bazelrc",
),
"_settings": attr.label(default = Label("@bazel_test//:settings")),
},
)
def bazel_test(name, command = None, args = None, targets = None, go_version = None, tags = [], externals = [], workspace = "", build = "", check = "", config = None, extra_files = []):
script_name = name+"_script"
externals = externals + [
"@io_bazel_rules_go//:AUTHORS",
]
if go_version == None or go_version == CURRENT_VERSION:
externals.append("@go_sdk//:packages.txt")
_bazel_test_script(
name = script_name,
command = command,
args = args,
targets = targets,
externals = externals,
go_version = go_version,
workspace = workspace,
build = build,
check = check,
config = config,
extra_files = extra_files,
)
native.sh_test(
name = name,
size = "large",
timeout = "moderate",
srcs = [":" + script_name],
tags = ["local", "bazel", "exclusive"] + tags,
data = [
"@bazel_gazelle//cmd/gazelle",
"@bazel_test//:bazelrc",
"@io_bazel_rules_go//tests:rules_go_deps",
],
)
def _md5_sum_impl(ctx):
go = go_context(ctx)
out = go.declare_file(go, ext=".md5")
arguments = ctx.actions.args()
arguments.add(["-output", out.path])
arguments.add(ctx.files.srcs)
ctx.actions.run(
inputs = ctx.files.srcs,
outputs = [out],
mnemonic = "GoMd5sum",
executable = ctx.file._md5sum,
arguments = [arguments],
)
return struct(files=depset([out]))
md5_sum = go_rule(
_md5_sum_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"_md5sum": attr.label(
allow_files = True,
single_file = True,
default = Label("@io_bazel_rules_go//go/tools/builders:md5sum"),
),
},
)
def _test_environment_impl(ctx):
# Find bazel
bazel = ""
if "BAZEL" in ctx.os.environ:
bazel = ctx.os.environ["BAZEL"]
elif "BAZEL_VERSION" in ctx.os.environ:
home = ctx.os.environ["HOME"]
bazel = home + "/.bazel/{0}/bin/bazel".format(ctx.os.environ["BAZEL_VERSION"])
if bazel == "" or not ctx.path(bazel).exists:
bazel = ctx.which("bazel")
# Get a temporary directory to use as our scratch workspace
if ctx.os.name.startswith('windows'):
scratch_dir = ctx.os.environ["TMP"].replace("\\","/") + "/bazel_go_test"
else:
result = env_execute(ctx, ["mktemp", "-d"])
if result.return_code:
fail("failed to create temporary directory for bazel tests: {}".format(result.stderr))
scratch_dir = result.stdout.strip()
# Work out where we are running so we can find externals
exec_root, _, _ = str(ctx.path(".")).rpartition("/external/")
# build the basic environment
ctx.file("WORKSPACE", 'workspace(name = "{}")'.format(ctx.name))
ctx.file("BUILD.bazel", _env_build_template.format(
bazel = bazel,
exec_root = exec_root,
scratch_dir = scratch_dir,
))
ctx.file("test.bazelrc", content=_bazelrc)
_test_environment = repository_rule(
implementation = _test_environment_impl,
attrs = {},
environ = [
"BAZEL",
"BAZEL_VERSION",
"HOME",
],
)
def _bazel_test_settings_impl(ctx):
return struct(
bazel = ctx.attr.bazel,
exec_root = ctx.attr.exec_root,
scratch_dir = ctx.attr.scratch_dir,
)
bazel_test_settings = rule(
_bazel_test_settings_impl,
attrs = {
"bazel": attr.string(mandatory = True),
"exec_root": attr.string(mandatory = True),
"scratch_dir": attr.string(mandatory = True),
},
)
def test_environment():
_test_environment(name="bazel_test")