Repository: bazelbuild/bazel
Issue: cquery's config function doesn't work with Bzlmod
Labels: type: bug
P1
team-Configurability

### Description of the bug:


When Bzlmod is enabled, `//src/test/shell/integration:configured_query_test` fails with

```
** test_config_function ********************************************************
-- Test log: -----------------------------------------------------------
$TEST_TMPDIR defined: output root default is '/b/f/w/_tmp/7db115b6dfb285ceb10442ec6acaf9d3' and max_idle_secs default is '15'.
Computing main repo mapping: 
Loading: 
Loading: 0 packages loaded
Analyzing: target //test_config_function:tool (0 packages loaded, 0 targets configured)
INFO: Analyzed target //test_config_function:tool (0 packages loaded, 1 target configured).
INFO: Found 1 target...
ERROR: Error doing post analysis query: Evaluation failed: No target (in) //test_config_function:tool could be found in the configuration with checksum '50265a7'
INFO: Elapsed time: 0.333s, Critical Path: 0.00s
INFO: 0 processes.
ERROR: Build did NOT complete successfully
```

 see https://github.com/bazelbuild/bazel/pull/19785#issuecomment-1761368842

### Which category does this issue belong to?


Configurability

### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.


To reproduce:

- Remove `disable_bzlmod` from `src/test/shell/integration/configured_query_test.sh`
- `bazel test //src/test/shell/integration:configured_query_test --test_filter test_config_function`

### Which operating system are you running Bazel on?


_No response_

### What is the output of `bazel info release`?


_No response_

### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.


_No response_

### What's the output of `git remote get-url origin; git rev-parse master; git rev-parse HEAD` ?


_No response_

### Is this a regression? If yes, please try to identify the Bazel commit where the bug was introduced.


_No response_

### Have you found anything relevant by searching the web?

_No response_

### Any other information, logs, or outputs that you want to share?

It's very likely `//src/test/java/com/google/devtools/build/lib/runtime:ConfigCommandTest` is failing with the same reason when enabling Bzlmod.

Issue comments:
/cc @gregestren 
/cc @katre 
As @fmeum mentioned at https://github.com/bazelbuild/bazel/pull/19785#issuecomment-1761368842, you can also demonstrate this with `$ bazel config`. But this specific error is about cquery's `config()` function, which is technically different. Updated the title accordingly.
@fmeum I'm not recreating the failure you described in https://github.com/bazelbuild/bazel/pull/19785#issuecomment-1761368842 at the command line.

I can reproduce the test failure.

But a direct i cquery / config invocation with bazel@head with `--enable_bzlmod` works for me. What are you doing differently?

```
$ b/bazel cquery "deps(//$pkg:demo)" --enable_bzlmod
<results snipped>

$ b/bazel config  --enable_bzlmod
Available configurations:
0c35974bbc4114fb6b2aaa97afc0fa05325df6498995fc5ab8048c6e904ce99c k8-fastbuild
f3e09891a52a118ada4747b9fed7d209ab6049a7786710934f5f50e1d0f82f2a fastbuild-noconfig
f60fa7f4f050ef3d0bbd3e9a847759d104c0983e4613406726e82cfac3fc0db1 k8-opt-exec-ST-fad1763555eb (exec)
fb7cccd5d9f2742c9ccf42571051eb647e8f01b2cf7be93309af5916222f86e2 k8-fastbuild
```
With this setup:

```starlark
# MODULE.bazel (empty)
# WORKSPACE (empty)
# pkg/BUILD
load("//pkg:rule.bzl", "demo_rule")

sh_binary(name = "tool", srcs = ["tool.sh"])

demo_rule(
    name = 'demo',
    binary = ":tool",
)
# pkg/rule.bzl
def _impl(ctx):
    pass

demo_rule = rule(
    implementation = _impl,
    attrs = {
        "binary": attr.label(cfg = "exec"),
    },
)
# pkg/tool.sh
echo "Hello"
exit 0
```

I get:
```shell
$ USE_BAZEL_VERSION=2ddacab80af1dca3c04e74809827c47ec4bc8498 bazel --nohome_rc --nosystem_rc cquery "deps(//pkg:demo)"
//pkg:demo (cb4f3cc)
@local_config_platform//:host (f3e0989)
//pkg:tool (bac8967)
...
$ USE_BAZEL_VERSION=2ddacab80af1dca3c04e74809827c47ec4bc8498 bazel --nohome_rc --nosystem_rc config
Available configurations:
$ USE_BAZEL_VERSION=2ddacab80af1dca3c04e74809827c47ec4bc8498 bazel --nohome_rc --nosystem_rc cquery "deps(//pkg:demo)" --noenable_bzlmod
//pkg:demo (cb4f3cc)
@local_config_platform//:host (f3e0989)
//pkg:tool (bac8967)
...
$ USE_BAZEL_VERSION=2ddacab80af1dca3c04e74809827c47ec4bc8498 bazel --nohome_rc --nosystem_rc config --noenable_bzlmod
Available configurations:
bac89673cb6a316d6814d09db69e2300dd9796229313c36bc7c06680a1c4d8ec k8-opt-exec-ST-e846b08c7501 (exec)
cb4f3ccb516213afb57b51cb2aba480bc44b184b701bcc30e6dd090e8540af2b k8-fastbuild
f3e09891a52a118ada4747b9fed7d209ab6049a7786710934f5f50e1d0f82f2a fastbuild-noconfig
```
It seems likely that this is also the cause of https://github.com/bazelbuild/rules_go/issues/3597#issuecomment-1765905567.
I will submit a fix shortly.
@bazel-io flag
I submitted https://github.com/bazelbuild/bazel/pull/19842.
@bazel-io fork 6.4.0
A fix for this issue has been included in [Bazel 6.4.0 RC5](https://releases.bazel.build/6.4.0/rc5/index.html). Please test out the release candidate and report any issues as soon as possible. Thanks!
@bazel-io fork 7.0.0

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
index a664ae3437b5c2..4036eb3b994f42 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileModule.java
@@ -106,8 +106,13 @@ public void afterCommand() throws AbruptExitException {
                 combineModuleExtensions(lockfile.getModuleExtensions(), oldExtensionUsages))
             .build();
 
-    // Write the new value to the file
-    updateLockfile(lockfilePath, lockfile);
+    // Write the new value to the file, but only if needed. This is not just a performance
+    // optimization: whenever the lockfile is updated, most Skyframe nodes will be marked as dirty
+    // on the next build, which breaks commands such as `bazel config` that rely on
+    // com.google.devtools.build.skyframe.MemoizingEvaluator#getDoneValues.
+    if (!lockfile.equals(oldLockfile)) {
+      updateLockfile(lockfilePath, lockfile);
+    }
     this.moduleResolutionEvent = null;
     this.extensionResolutionEventsMap.clear();
   }


Test patch: