[7.0.2] Disregard WORKSPACE while verifying lockfile repo mapping entries in extension eval (#21003)
See code comment and linked issue for more information.
Fixes #20942.
Closes #20982.
Commit
https://github.com/bazelbuild/bazel/commit/21508b1446b776635b64f53f0ed4770153741e4b
PiperOrigin-RevId: 600856392
Change-Id: I5b8a0ed3a38e37ab51ffb49b19a59f2e161b9a33
---------
Co-authored-by: Xdng Yng <wyverald@gmail.com>
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java
index 753a8cc..fcdbcab 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/SingleExtensionEvalFunction.java
@@ -342,10 +342,19 @@
private static boolean didRepoMappingsChange(
Environment env, ImmutableTable<RepositoryName, String, RepositoryName> recordedRepoMappings)
throws InterruptedException, NeedsSkyframeRestartException {
+ // Request repo mappings for any 'source repos' in the recorded mapping entries.
+ // Note specially that the main repo needs to be treated differently: if any .bzl file from the
+ // main repo was used for module extension eval, it _has_ to be before WORKSPACE is evaluated
+ // (see relevant code in BzlLoadFunction#getRepositoryMapping), so we only request the main repo
+ // mapping _without_ WORKSPACE repos. See #20942 for more information.
SkyframeLookupResult result =
env.getValuesAndExceptions(
recordedRepoMappings.rowKeySet().stream()
- .map(RepositoryMappingValue::key)
+ .map(
+ repoName ->
+ repoName.isMain()
+ ? RepositoryMappingValue.KEY_FOR_ROOT_MODULE_WITHOUT_WORKSPACE_REPOS
+ : RepositoryMappingValue.key(repoName))
.collect(toImmutableSet()));
if (env.valuesMissing()) {
// This likely means that one of the 'source repos' in the recorded mapping entries is no
@@ -354,7 +363,11 @@
}
for (Table.Cell<RepositoryName, String, RepositoryName> cell : recordedRepoMappings.cellSet()) {
RepositoryMappingValue repoMappingValue =
- (RepositoryMappingValue) result.get(RepositoryMappingValue.key(cell.getRowKey()));
+ (RepositoryMappingValue)
+ result.get(
+ cell.getRowKey().isMain()
+ ? RepositoryMappingValue.KEY_FOR_ROOT_MODULE_WITHOUT_WORKSPACE_REPOS
+ : RepositoryMappingValue.key(cell.getRowKey()));
if (repoMappingValue == null) {
throw new NeedsSkyframeRestartException();
}
diff --git a/src/test/py/bazel/bzlmod/bazel_lockfile_test.py b/src/test/py/bazel/bzlmod/bazel_lockfile_test.py
index f09ca3b..9bff260 100644
--- a/src/test/py/bazel/bzlmod/bazel_lockfile_test.py
+++ b/src/test/py/bazel/bzlmod/bazel_lockfile_test.py
@@ -1863,6 +1863,50 @@
self.assertIn('ran the extension!', '\n'.join(stderr))
self.assertIn('STR=@@quux~1.0//:quux.h', '\n'.join(stderr))
+ def testExtensionRepoMappingChange_mainRepoEvalCycleWithWorkspace(self):
+ # Regression test for #20942
+ self.main_registry.createCcModule('foo', '1.0')
+ self.ScratchFile(
+ 'MODULE.bazel',
+ [
+ 'bazel_dep(name="foo",version="1.0")',
+ 'ext = use_extension(":ext.bzl", "ext")',
+ 'use_repo(ext, "repo")',
+ ],
+ )
+ self.ScratchFile(
+ 'BUILD.bazel',
+ [
+ 'load("@repo//:defs.bzl", "STR")',
+ 'print("STR="+STR)',
+ 'filegroup(name="lol")',
+ ],
+ )
+ self.ScratchFile(
+ 'ext.bzl',
+ [
+ 'def _repo_impl(rctx):',
+ ' rctx.file("BUILD")',
+ ' rctx.file("defs.bzl", "STR = " + repr(str(rctx.attr.value)))',
+ 'repo = repository_rule(_repo_impl,attrs={"value":attr.label()})',
+ 'def _ext_impl(mctx):',
+ ' print("ran the extension!")',
+ ' repo(name = "repo", value = Label("@foo//:lib_foo"))',
+ 'ext = module_extension(_ext_impl)',
+ ],
+ )
+ # any `load` in WORKSPACE should trigger the bug
+ self.ScratchFile('WORKSPACE.bzlmod', ['load("@repo//:defs.bzl","STR")'])
+
+ _, _, stderr = self.RunBazel(['build', ':lol'])
+ self.assertIn('STR=@@foo~1.0//:lib_foo', '\n'.join(stderr))
+
+ # Shutdown bazel to make sure we rely on the lockfile and not skyframe
+ self.RunBazel(['shutdown'])
+ # Build again. This should _NOT_ trigger a failure!
+ _, _, stderr = self.RunBazel(['build', ':lol'])
+ self.assertNotIn('ran the extension!', '\n'.join(stderr))
+
if __name__ == '__main__':
absltest.main()