Skip to content

Commit

Permalink
feat: gazelle_test test rule (#1785)
Browse files Browse the repository at this point in the history
* feat: gazelle_test test rule

* remove no_sandbox attr and add symlink check

* use readlink
  • Loading branch information
hunshcn authored May 30, 2024
1 parent f738979 commit b47ccd0
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 47 deletions.
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,19 @@ You can also pass additional arguments to Gazelle after a ``--`` argument.
After running ``update-repos``, you might want to run ``bazel run //:gazelle`` again, as the
``update-repos`` command can affect the output of a normal run of Gazelle.

To verify that all BUILD files are update-to-date, you can use the ``gazelle_test`` rule.

.. code:: bzl
load("@bazel_gazelle//:def.bzl", "gazelle_test")
gazelle_test(
name = "gazelle_test",
workspace = "//:BUILD.bazel", # a file in the workspace root, where the gazelle will be run
)
However, please note that gazelle_test cannot be cached.

Running Gazelle with Go
~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
148 changes: 102 additions & 46 deletions def.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,59 @@ def _rlocation_path(ctx, file):
else:
return ctx.workspace_name + "/" + file.short_path

def _gazelle_runner_impl(ctx):
def _gazelle_runner_attr_factory(test_runner = False):
attrs = {
"gazelle": attr.label(
allow_single_file = True,
default = "//cmd/gazelle",
executable = True,
cfg = "target",
),
"command": attr.string(
values = [
"fix",
"update",
"update-repos",
],
default = "update",
),
"mode": attr.string(
values = ["", "print", "fix", "diff"],
default = "",
),
"external": attr.string(
values = ["", "external", "static", "vendored"],
default = "",
),
"build_tags": attr.string_list(),
"prefix": attr.string(),
"extra_args": attr.string_list(),
"data": attr.label_list(allow_files = True),
"env": attr.string_dict(),
"_repo_config": attr.label(
default = "@bazel_gazelle_go_repository_config//:WORKSPACE" if GAZELLE_IS_BAZEL_MODULE else None,
allow_single_file = True,
),
"_template": attr.label(
default = "//internal:gazelle.bash.in",
allow_single_file = True,
),
}
if test_runner:
attrs.update({
"workspace": attr.label(
allow_single_file = True,
doc = "Label of the WORKSPACE file",
mandatory = True,
),
"mode": attr.string(
values = ["diff"],
default = "diff",
),
})
return attrs

def _gazelle_runner_impl_factory(ctx, test_runner = False):
args = [ctx.attr.command]
if ctx.attr.mode:
args.extend(["-mode", ctx.attr.mode])
Expand Down Expand Up @@ -102,6 +154,7 @@ def _gazelle_runner_impl(ctx):
"@@GOTOOL@@": shell.quote(_rlocation_path(ctx, go_tool)),
"@@ENV@@": env,
"@@REPO_CONFIG_PATH@@": shell.quote(_rlocation_path(ctx, repo_config)) if repo_config else "",
"@@WORKSPACE@@": ctx.file.workspace.path if test_runner else "",
}
ctx.actions.expand_template(
template = ctx.file._template,
Expand All @@ -112,7 +165,7 @@ def _gazelle_runner_impl(ctx):
runfiles = ctx.runfiles(files = [
ctx.executable.gazelle,
go_tool,
] + ([repo_config] if repo_config else [])).merge(
] + ([repo_config] if repo_config else []) + ([ctx.file.workspace] if test_runner else [])).merge(
ctx.attr.gazelle[DefaultInfo].default_runfiles,
)
for d in ctx.attr.data:
Expand All @@ -123,50 +176,27 @@ def _gazelle_runner_impl(ctx):
executable = out_file,
)]

def _gazelle_runner_impl(ctx):
return _gazelle_runner_impl_factory(ctx)

def _gazelle_test_runner_impl(ctx):
return _gazelle_runner_impl_factory(ctx, test_runner = True)

_gazelle_runner = rule(
implementation = _gazelle_runner_impl,
attrs = {
"gazelle": attr.label(
allow_single_file = True,
default = "//cmd/gazelle",
executable = True,
cfg = "target",
),
"command": attr.string(
values = [
"fix",
"update",
"update-repos",
],
default = "update",
),
"mode": attr.string(
values = ["", "print", "fix", "diff"],
default = "",
),
"external": attr.string(
values = ["", "external", "static", "vendored"],
default = "",
),
"build_tags": attr.string_list(),
"prefix": attr.string(),
"extra_args": attr.string_list(),
"data": attr.label_list(allow_files = True),
"env": attr.string_dict(),
"_repo_config": attr.label(
default = "@bazel_gazelle_go_repository_config//:WORKSPACE" if GAZELLE_IS_BAZEL_MODULE else None,
allow_single_file = True,
),
"_template": attr.label(
default = "//internal:gazelle.bash.in",
allow_single_file = True,
),
},
attrs = _gazelle_runner_attr_factory(),
executable = True,
toolchains = ["@io_bazel_rules_go//go:toolchain"],
)

def gazelle(name, **kwargs):
_gazelle_test_runner = rule(
implementation = _gazelle_test_runner_impl,
attrs = _gazelle_runner_attr_factory(test_runner = True),
executable = True,
toolchains = ["@io_bazel_rules_go//go:toolchain"],
)

def _gazelle_kwargs_prepare(name, kwargs):
if "args" in kwargs:
# The args attribute has special meaning for executable rules, but we
# always want extra_args here instead.
Expand All @@ -176,21 +206,47 @@ def gazelle(name, **kwargs):
kwargs.pop("args")

visibility = kwargs.pop("visibility", default = None)
return name + "-runner", visibility

def gazelle(name, **kwargs):
runner_name, visibility = _gazelle_kwargs_prepare(name, kwargs)

tags_set = {t: "" for t in kwargs.pop("tags", [])}
tags_set["manual"] = ""
tags = [k for k in tags_set.keys()]
runner_name = name + "-runner"
_gazelle_runner(
name = runner_name,
tags = tags,
**kwargs
)
tags_set = {t: "" for t in kwargs.pop("tags", [])}
tags_set["manual"] = ""
tags = tags_set.keys()
native.sh_binary(
name = name,
srcs = [runner_name],
tags = tags,
srcs = [runner_name],
visibility = visibility,
deps = ["@bazel_tools//tools/bash/runfiles"],
data = kwargs["data"] if "data" in kwargs else [],
)

def gazelle_test(name, **kwargs):
runner_name, visibility = _gazelle_kwargs_prepare(name, kwargs)

_gazelle_test_runner(
name = runner_name,
**kwargs
)

# Note: the "external" tag is a workaround for
# https://github.com/bazelbuild/bazel/issues/15516.
tags_set = {t: "" for t in kwargs.pop("tags", [])}
tags_set["no-sandbox"] = ""
tags_set["no-cache"] = ""
tags_set["external"] = ""
tags = tags_set.keys()
native.sh_test(
name = name,
srcs = [runner_name],
visibility = visibility,
tags = tags,
deps = ["@bazel_tools//tools/bash/runfiles"],
data = kwargs["data"] if "data" in kwargs else [],
)
5 changes: 5 additions & 0 deletions internal/gazelle.bash.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ GAZELLE_PATH=@@GAZELLE_PATH@@
ARGS=@@ARGS@@
GOTOOL=@@GOTOOL@@
REPO_CONFIG_PATH=@@REPO_CONFIG_PATH@@
WORKSPACE="@@WORKSPACE@@"

@@ENV@@

Expand Down Expand Up @@ -76,6 +77,10 @@ if [ -z "$gazelle_path" ]; then
echo "error: could not locate gazelle binary" >&2
exit 1
fi
if [[ -n "${TEST_WORKSPACE+x}" && -n "$WORKSPACE" ]]; then
BUILD_WORKSPACE_DIRECTORY="$(dirname "$(readlink ${WORKSPACE})")"
export BUILD_WORKSPACE_DIRECTORY
fi
if [ -z "${BUILD_WORKSPACE_DIRECTORY-}" ]; then
echo "error: BUILD_WORKSPACE_DIRECTORY not set" >&2
exit 1
Expand Down
7 changes: 6 additions & 1 deletion tests/bcr/go_mod/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
load("@gazelle//:def.bzl", "gazelle")
load("@gazelle//:def.bzl", "gazelle", "gazelle_test")

# gazelle:go_naming_convention import
# gazelle:go_naming_convention_external import
gazelle(name = "gazelle")

gazelle_test(
name = "gazelle_test",
workspace = "//:BUILD.bazel",
)

0 comments on commit b47ccd0

Please sign in to comment.