Introduce `["all"]` scope for nogo (#4678)
**What type of PR is this?**
Feature
**What does this PR do? Why is it needed?**
**Which issues(s) does this PR fix?**
Work towards https://github.com/bazel-contrib/rules_go/issues/4241 and
be a rebased version of #4277
**Other notes for review**
Co-authored-by: Fabian Meumertzheim <fabian@meumertzhe.im>
diff --git a/go/private/extensions.bzl b/go/private/extensions.bzl
index 373d41d..c17e511 100644
--- a/go/private/extensions.bzl
+++ b/go/private/extensions.bzl
@@ -83,16 +83,15 @@
),
"includes": attr.label_list(
default = NOGO_DEFAULT_INCLUDES,
- # The special include "all" is undocumented on purpose: With it, adding a new transitive
- # dependency to a Go module can cause a build failure if the new dependency has lint
- # issues.
doc = """
A Go target is checked with nogo if its package matches at least one of the entries in 'includes'
and none of the entries in 'excludes'. By default, nogo is applied to all targets in the main
repository.
Uses the same format as 'visibility', i.e., every entry must be a label that ends with ':__pkg__' or
-':__subpackages__'.
+':__subpackages__'. As an exception to this rule, the special value ["all"] is allowed for 'includes'
+and means that nogo should be applied to all Go targets, including those in all external
+repositories.
""",
),
"excludes": attr.label_list(
@@ -158,11 +157,9 @@
_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
def _go_sdk_impl(ctx):
- nogo_tag = struct(
- nogo = DEFAULT_NOGO,
- includes = NOGO_DEFAULT_INCLUDES,
- excludes = NOGO_DEFAULT_EXCLUDES,
- )
+ nogo = DEFAULT_NOGO
+ nogo_includes = NOGO_DEFAULT_INCLUDES
+ nogo_excludes = NOGO_DEFAULT_EXCLUDES
for module in ctx.modules:
if not module.is_root or not module.tags.nogo:
continue
@@ -173,22 +170,25 @@
*[t for p in zip(module.tags.nogo, len(module.tags.nogo) * ["\n"]) for t in p]
)
nogo_tag = module.tags.nogo[0]
- for scope in nogo_tag.includes + nogo_tag.excludes:
- # Validate that the scope references a valid, visible repository.
- # buildifier: disable=no-effect
- scope.repo_name
- if scope.name != "__pkg__" and scope.name != "__subpackages__":
- fail(
- "go_sdk.nogo: all entries in includes and excludes must end with ':__pkg__' or ':__subpackages__', got '{}' in".format(scope.name),
- nogo_tag,
- )
+ nogo = nogo_tag.nogo
+ nogo_includes = nogo_tag.includes
+ nogo_excludes = nogo_tag.excludes
+
+ # "all" is still processed into a Label instance, so we just check its name.
+ if len(nogo_includes) == 1 and nogo_includes[0].name == "all":
+ nogo_includes = ["all"]
+ else:
+ for scope in nogo_includes:
+ _check_nogo_scope(scope, nogo_tag)
+ for scope in nogo_excludes:
+ _check_nogo_scope(scope, nogo_tag)
go_register_nogo(
name = "io_bazel_rules_nogo",
- nogo = str(nogo_tag.nogo),
+ nogo = str(nogo),
# Go through canonical label literals to avoid a dependency edge on the packages in the
# scope.
- includes = [str(l) for l in nogo_tag.includes],
- excludes = [str(l) for l in nogo_tag.excludes],
+ includes = [str(l) for l in nogo_includes],
+ excludes = [str(l) for l in nogo_excludes],
)
multi_version_module = {}
@@ -433,6 +433,16 @@
else:
return None
+def _check_nogo_scope(scope, nogo_tag):
+ # Validate that the scope references a valid, visible repository.
+ # buildifier: disable=no-effect
+ scope.repo_name
+ if scope.name != "__pkg__" and scope.name != "__subpackages__":
+ fail(
+ "go_sdk.nogo: all entries in includes and excludes must end with ':__pkg__' or ':__subpackages__', got '{}' in".format(scope.name),
+ nogo_tag,
+ )
+
def _default_go_sdk_name(*, module, multi_version, tag_type, index, goos = None, goarch = None):
# Keep the version and name of the root module out of the repository name if possible to
# prevent unnecessary rebuilds when it changes.