Repository: bazelbuild/bazel
Issue: experimental_action_listener config variable is set to "null" instead of "[]" in exec configuration
Labels: type: bug
team-Configurability
untriaged

### Description of the bug:


In the configuration associated with `CoreOptions` there is a configuration value `experimental_action_listener: []` associated with the (deprecated) command-line flag `--experimental_action_listener`. We do not use this functionality, and have no desire to do so.

Unfortunately, after any transition to `exec` configuration, this value appears to change from `[]` to `null`, and there is no way to transition it _back_ from Starlark code.

The reason this is a problem is related to our desire to perform "unifying transitions" as discussed in #14023 and #14236. All of the other config set by "exec" can be controlled manually from a Starlark transition, but because this particular flag is "experimental" we can't reset it to `[]`, so we end up with two different configuration hashes for the same configuration, and Bazel ends up building those targets and everything they depend on twice without reason.

This should be a small one-line fix, and is a blocker for many of the benefits of `--experimental_output_directory_naming_scheme=diff_against_baseline`, and possibly for moving to Bazel 6.x entirely, so it would be nice to get this fix backported as well.

I believe the simplest fix is a one-line change here to construct an empty list, although more complicated solutions are possible: https://github.com/bazelbuild/bazel/blob/release-6.0.0rc4/src/main/java/com/google/devtools/build/lib/analysis/config/ExecutionTransitionFactory.java#L131-L132

### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.


```
genrule(
    name = "rule1",
    srcs = [],
    outs = ["file1.bin"],
    cmd = "echo 'echo hi' > $@",
    executable = True,
)

genrule(
    name = "rule2",
    srcs = [],
    outs = ["file2.txt"],
    cmd = 'echo "file2" > $@',
    exec_tools = [":rule1"],
)
```

`bazel cquery "filter(rule1, deps(:all))"`
This returns two different config hashes, use `diff` on `bazel config` to show the issue
```diff
<   experimental_action_listener: []
---
>   experimental_action_listener: null
```

Note that we're _not_ concerned with any of the other changes in this list since they are all controllable by Starlark

### Which operating system are you running Bazel on?


Ubuntu 18.04

### What is the output of `bazel info release`?


release 6.0.0rc4

### 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_

### Have you found anything relevant by searching the web?

_No response_

### Any other information, logs, or outputs that you want to share?

Tagging @gregestren @sdtwigg and the Configurability team

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
index 19597cc44c23d8..a39d84f01f27f1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
@@ -17,7 +17,6 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedMap;
@@ -732,7 +731,7 @@ public int analysisTestingDepsLimit() {
   }
 
   public List<Label> getActionListeners() {
-    return options.actionListeners == null ? ImmutableList.of() : options.actionListeners;
+    return options.actionListeners;
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ExecutionTransitionFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ExecutionTransitionFactory.java
index 0ff96d0a655b1f..a4559c333d53c0 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ExecutionTransitionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ExecutionTransitionFactory.java
@@ -129,7 +129,7 @@ private static BuildOptions transitionImpl(BuildOptionsView options, Label execu
       coreOptions.isHost = false;
       coreOptions.isExec = true;
       // Disable extra actions
-      coreOptions.actionListeners = null;
+      coreOptions.actionListeners = ImmutableList.of();
 
       // Then set the target to the saved execution platform if there is one.
       PlatformOptions platformOptions = execOptions.get(PlatformOptions.class);


Test patch: