Add ExternalRepository failure detail category

Encodes the failure mode in which the user overrides an external
repository that has managed directories, which is not supported.

RELNOTES: None.
PiperOrigin-RevId: 302927927
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 1aab5af..47d2898 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -704,8 +704,8 @@
         ":bazel-repository",
         ":bazel-rules",
         ":build-base",
+        ":detailed_exit_code",
         ":events",
-        ":exitcode-external",
         ":runtime",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/cache",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/downloader",
@@ -716,6 +716,7 @@
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/common/options:options_internal",
+        "//src/main/protobuf:failure_details_java_proto",
         "//third_party:guava",
     ],
 )
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 8212e47..70e950b 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -64,13 +64,16 @@
 import com.google.devtools.build.lib.runtime.ServerBuilder;
 import com.google.devtools.build.lib.runtime.WorkspaceBuilder;
 import com.google.devtools.build.lib.runtime.commands.InfoItem;
+import com.google.devtools.build.lib.server.FailureDetails.ExternalRepository;
+import com.google.devtools.build.lib.server.FailureDetails.ExternalRepository.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.skyframe.MutableSupplier;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue.Injected;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
 import com.google.devtools.build.lib.skylarkbuildapi.repository.RepositoryBootstrap;
 import com.google.devtools.build.lib.util.AbruptExitException;
-import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -129,12 +132,21 @@
                     + " for the repositories with managed directories.\n"
                     + "The following overridden external repositories have managed directories: "
                     + String.join(", ", conflicting.toArray(new String[0]));
-            throw new AbruptExitException(message, ExitCode.COMMAND_LINE_ERROR);
+            throw new AbruptExitException(
+                detailedExitCode(message, Code.OVERRIDE_DISALLOWED_MANAGED_DIRECTORIES));
           }
         };
     managedDirectoriesKnowledge = new ManagedDirectoriesKnowledgeImpl(listener);
   }
 
+  private static DetailedExitCode detailedExitCode(String message, ExternalRepository.Code code) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setMessage(message)
+            .setExternalRepository(ExternalRepository.newBuilder().setCode(code))
+            .build());
+  }
+
   public static ImmutableMap<String, RepositoryFunction> repositoryRules() {
     return ImmutableMap.<String, RepositoryFunction>builder()
         .put(LocalRepositoryRule.NAME, new LocalRepositoryFunction())
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 5df8a58..8092155 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -88,6 +88,7 @@
 
   oneof category {
     Interrupted interrupted = 101;
+    ExternalRepository external_repository = 103;
   }
 
   reserved 102; // For internal use
@@ -103,3 +104,12 @@
 
   Code code = 1;
 }
+
+message ExternalRepository {
+  enum Code {
+    EXTERNAL_REPOSITORY_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+    OVERRIDE_DISALLOWED_MANAGED_DIRECTORIES = 1 [(metadata) = { exit_code: 2 }];
+  }
+  Code code = 1;
+  // Additional data could include external repository names.
+}
\ No newline at end of file