diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java index 27b5824cfaccf3..b87ce28152a703 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java @@ -51,7 +51,9 @@ import java.io.IOException; import java.util.Optional; import javax.annotation.Nullable; +import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Module; +import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkSemantics; import net.starlark.java.eval.StarlarkThread.CallStackEntry; import net.starlark.java.syntax.Location; @@ -185,6 +187,10 @@ private BzlmodRepoRuleValue createNativeRepoRule( rule = RuleFactory.createAndAddRule( pkg, ruleClass, attributeValues, env.getListener(), semantics, callStack.build()); + if (rule.containsErrors()) { + throw Starlark.errorf( + "failed to instantiate '%s' from this module extension", ruleClass.getName()); + } return new BzlmodRepoRuleValue(pkg.build(), rule.getName()); } catch (InvalidRuleException e) { throw new BzlmodRepoRuleFunctionException(e, Transience.PERSISTENT); @@ -193,6 +199,8 @@ private BzlmodRepoRuleValue createNativeRepoRule( } catch (NameConflictException e) { // This literally cannot happen -- we just created the package! throw new IllegalStateException(e); + } catch (EvalException e) { + throw new BzlmodRepoRuleFunctionException(e, Transience.PERSISTENT); } } @@ -310,5 +318,9 @@ private static final class BzlmodRepoRuleFunctionException extends SkyFunctionEx BzlmodRepoRuleFunctionException(IOException e, Transience transience) { super(e, transience); } + + BzlmodRepoRuleFunctionException(EvalException e, Transience transience) { + super(e, transience); + } } } diff --git a/src/test/py/bazel/bzlmod/bazel_module_test.py b/src/test/py/bazel/bzlmod/bazel_module_test.py index 0268f30710891f..522d085f1a7d3d 100644 --- a/src/test/py/bazel/bzlmod/bazel_module_test.py +++ b/src/test/py/bazel/bzlmod/bazel_module_test.py @@ -332,6 +332,35 @@ def testCheckDirectDependencies(self): 'ERROR: For repository \'B\', the root module requires module version B@1.0, but got B@1.1 in the resolved dependency graph.', stderr) + def testRepositoryRuleErrorInModuleExtensionFailsTheBuild(self): + self.ScratchFile('MODULE.bazel', [ + 'module_ext = use_extension("//pkg:extension.bzl", "module_ext")', + 'use_repo(module_ext, "foo")', + ]) + self.ScratchFile('pkg/BUILD.bazel') + self.ScratchFile('pkg/rules.bzl', [ + 'def _repo_rule_impl(ctx):', + ' ctx.file("WORKSPACE")', + 'repo_rule = repository_rule(implementation = _repo_rule_impl)', + ]) + self.ScratchFile('pkg/extension.bzl', [ + 'load(":rules.bzl", "repo_rule")', + 'def _module_ext_impl(ctx):', + ' repo_rule(name = "foo", invalid_attr = "value")', + 'module_ext = module_extension(implementation = _module_ext_impl)', + ]) + exit_code, _, stderr = self.RunBazel(['run', '@foo//...'], + allow_failure=True) + self.AssertExitCode(exit_code, 48, stderr) + self.assertIn( + "ERROR: : //pkg:@.module_ext.foo: no such attribute 'invalid_attr' in 'repo_rule' rule", + stderr) + self.assertTrue( + any([ + '/pkg/extension.bzl", line 3, column 14, in _module_ext_impl' + in line for line in stderr + ])) + if __name__ == '__main__': unittest.main()