Encode build configuration failures with FailureDetails

Eliminates the second-to-last remaining use of DetailedExitCode without
FailureDetails.

Cleans up an incorrect use of BUILD_CONFIGURATION_UNKNOWN, a default
protobuf enum value.

RELNOTES: None.
PiperOrigin-RevId: 332872475
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index 9534265..b0031a2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -1697,7 +1697,10 @@
     name = "config/invalid_configuration_exception",
     srcs = ["config/InvalidConfigurationException.java"],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib/skyframe:detailed_exceptions",
+        "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
         "//src/main/protobuf:failure_details_java_proto",
+        "//third_party:guava",
         "//third_party:jsr305",
     ],
 )
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
index e602252..7d1fbe2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
 import java.util.HashMap;
 
 /**
@@ -45,7 +46,7 @@
       BuildConfiguration old = cacheKeyConflictDetector.put(config.checksum(), config);
       if (old != null) {
         throw new InvalidConfigurationException(
-            "Conflicting configurations: " + config + " & " + old);
+            "Conflicting configurations: " + config + " & " + old, Code.CONFLICTING_CONFIGURATIONS);
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java b/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
index 7f2a7f4..25c08c7 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
@@ -13,39 +13,64 @@
 // limitations under the License.
 package com.google.devtools.build.lib.analysis.config;
 
+import com.google.common.base.Strings;
+import com.google.devtools.build.lib.server.FailureDetails;
 import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.skyframe.DetailedException;
+import com.google.devtools.build.lib.util.DetailedExitCode;
 import javax.annotation.Nullable;
 
 /**
  * Thrown if the configuration options lead to an invalid configuration, or if any of the
  * configuration labels cannot be loaded.
  */
-public class InvalidConfigurationException extends Exception {
+public class InvalidConfigurationException extends Exception implements DetailedException {
 
-  @Nullable private final Code detailedCode;
+  @Nullable private final DetailedExitCode detailedExitCode;
 
   public InvalidConfigurationException(String message) {
     super(message);
-    this.detailedCode = null;
+    this.detailedExitCode = null;
+  }
+
+  public InvalidConfigurationException(String message, Code code) {
+    super(message);
+    this.detailedExitCode = createDetailedExitCode(message, code);
   }
 
   public InvalidConfigurationException(String message, Throwable cause) {
     super(message, cause);
-    this.detailedCode = null;
+    this.detailedExitCode = null;
   }
 
   public InvalidConfigurationException(Throwable cause) {
     super(cause.getMessage(), cause);
-    this.detailedCode = null;
+    this.detailedExitCode = null;
   }
 
-  public InvalidConfigurationException(Code detailedCode, Exception cause) {
+  public InvalidConfigurationException(Code code, Throwable cause) {
     super(cause.getMessage(), cause);
-    this.detailedCode = detailedCode;
+    this.detailedExitCode = createDetailedExitCode(cause.getMessage(), code);
   }
 
-  @Nullable
-  public Code getDetailedCode() {
-    return detailedCode;
+  public InvalidConfigurationException(DetailedExitCode detailedExitCode, Throwable cause) {
+    super(cause.getMessage(), cause);
+    this.detailedExitCode = detailedExitCode;
+  }
+
+  @Override
+  public DetailedExitCode getDetailedExitCode() {
+    return detailedExitCode != null
+        ? detailedExitCode
+        : createDetailedExitCode(getMessage(), Code.INVALID_CONFIGURATION);
+  }
+
+  private static DetailedExitCode createDetailedExitCode(@Nullable String message, Code code) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setMessage(Strings.nullToEmpty(message))
+            .setBuildConfiguration(FailureDetails.BuildConfiguration.newBuilder().setCode(code))
+            .build());
   }
 }