Skip to content

Commit

Permalink
Validate test dependencies
Browse files Browse the repository at this point in the history
(cherry picked from commit e10426b)
  • Loading branch information
Googler authored and mai93 committed Feb 26, 2024
1 parent bbbaf27 commit 612f947
Showing 1 changed file with 109 additions and 0 deletions.
109 changes: 109 additions & 0 deletions build_defs/restrictions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ a different context (IntelliJ and not google3)
_project = [
]

_tests = [
]

# Targets from the project scope that should be reported as external targets.
_not_project_for_tests = [
]

# A set of external dependencies that can be built outside of google3
_valid = [
]
Expand All @@ -32,6 +39,48 @@ EXISTING_EXTERNAL_VIOLATIONS = [
EXISTING_UNCHECKED = [
]

# A temporary list of external targets that plugins are depending on. DO NOT ADD TO THIS
ALLOWED_EXTERNAL_TEST_DEPENDENCIES = [
"//dart/build_defs/dart_library:dartinfo",
"//devtools/blaze/integration:android_tools",
"//devtools/blaze/integration:mobile_install",
"//devtools/blaze/integration:mock_tools",
"//devtools/blaze/main:blaze",
"//devtools/citc/proto:citc_filesystem_manifest_java_proto",
"//devtools/citc/proto:java_proto",
"//devtools/deps/depserver/proto:dependency_service_java_proto",
"//devtools/ide/intellij/filewatcher:regurgitator_client_mock_bin",
"//devtools/ide/intellij/filewatcher:regurgitator_java_proto",
"//devtools/srcfs/client/proto:delta_java_proto",
"//google/corp/devtools/intellij/services/v1:dependency_service_java_grpc",
"//java/com/google/common/flags:flags",
"//java/com/google/common/hash:hash",
"//java/com/google/experiments/framework/options:exempt_existing_client_java",
"//java/com/google/testing/junit/junit4:api",
"//java/com/google/testing/junit/runner:Runner_deploy.jar",
"//java/com/google/testing/testsize:annotations",
"//javascript/typescript:providers",
"//third_party/java/apache_bcel:apache_bcel",
"//third_party/java/flogger:flogger",
"//third_party/java/truth/extensions:proto",
"//tools/build_defs/js/providers:providers",
"//tools/build_defs/js/providers:utils",
"//tools/jdk:singlejar",
]

# A list of targets currently with not allowed dependencies
EXISTING_EXTERNAL_TEST_VIOLATIONS = [
"//javatests/com/google/devtools/intellij/blaze/plugin/aswb:blaze_integration_tests",
"//javatests/com/google/devtools/intellij/blaze/plugin/aswb:integration_tests",
"//javatests/com/google/devtools/intellij/blaze/plugin/aswb:unit_tests",
"//javatests/com/google/devtools/intellij/blaze/plugin/base:utils",
"//javatests/com/google/devtools/intellij/blaze/plugin/shell:blaze_integration_test_wrapper",
"//javatests/com/google/devtools/intellij/g3plugins/citc/filewatcher:regurgitator_filewatcher_tests",
"//javatests/com/google/devtools/intellij/g3plugins/integrity:integritycheck",
"//javatests/com/google/devtools/intellij/g3plugins/services/depserver:unit_tests",
"//javatests/com/google/devtools/intellij/g3plugins/services/linter:unit_tests",
]

RestrictedInfo = provider(
doc = "The dependencies, per target, outside the project",
fields = {
Expand All @@ -54,6 +103,10 @@ def _in_set(target, set):
def _in_project(target):
return _in_set(target, _project)

def _in_tests(target):
lbl = str(target.label)
return (lbl.endswith("_test") or lbl.endswith("_tests") or lbl.endswith(":tests")) and _in_project(target) or _in_set(target, _tests)

def _get_deps(ctx):
deps = []
if hasattr(ctx.rule.attr, "deps"):
Expand All @@ -62,6 +115,10 @@ def _get_deps(ctx):
deps.extend(ctx.rule.attr.exports)
if hasattr(ctx.rule.attr, "runtime_deps"):
deps.extend(ctx.rule.attr.runtime_deps)
if hasattr(ctx.rule.attr, "data"):
deps.extend(ctx.rule.attr.data)
if hasattr(ctx.rule.attr, "tests"):
deps.extend(ctx.rule.attr.tests)
return deps

def _restricted_deps_aspect_impl(target, ctx):
Expand Down Expand Up @@ -117,6 +174,25 @@ def validate_unchecked_internal(unchecked, existing_unchecked):
if error:
fail(error)

def _restricted_test_deps_aspect_impl(target, ctx):
if not _in_tests(target):
return []

dependencies = {}
outside_project = []
for d in _get_deps(ctx):
if not _in_tests(d) and not _in_set(d, _valid) and (not _in_project(d) or _in_set(d, _not_project_for_tests)):
outside_project.append(d)
if RestrictedInfo in d:
dependencies.update(d[RestrictedInfo].dependencies)

if outside_project:
dependencies[target] = outside_project

return [
RestrictedInfo(dependencies = dependencies),
]

# buildifier: disable=function-docstring
def validate_restrictions(dependencies, allowed_external, existing_violations):
violations = sorted([str(d.label) for d in dependencies.keys()])
Expand Down Expand Up @@ -156,3 +232,36 @@ restricted_deps_aspect = aspect(
implementation = _restricted_deps_aspect_impl,
attr_aspects = ["*"],
)

restricted_test_deps_aspect = aspect(
implementation = _restricted_test_deps_aspect_impl,
attr_aspects = ["*"],
)

def _validate_test_dependencies(ctx):
dependencies = {}
for k in ctx.attr.deps:
if not str(k.label).endswith("_tests") and not _in_tests(k):
fail("Undeclared test location: " + str(k))
if RestrictedInfo in k:
dependencies.update(k[RestrictedInfo].dependencies)
validate_restrictions(dependencies, ctx.attr.allowed_external_dependencies, ctx.attr.existing_external_violations)
fake_file = ctx.actions.declare_file("fake_file.txt")
ctx.actions.write(
fake_file,
"""#!/bin/sh
true
""",
)
return [DefaultInfo(executable = fake_file)]

validate_test_dependencies_test = rule(
implementation = _validate_test_dependencies,
attrs = {
"allowed_external_dependencies": attr.string_list(),
"existing_external_violations": attr.string_list(),
"deps": attr.label_list(aspects = [restricted_test_deps_aspect]),
},
test = True,
)

0 comments on commit 612f947

Please sign in to comment.