Enrich FailAction's failure message a bit: always include the owning label, and in the last remaining "generic" case, be more specific in the error message.

Also do some minor clean-ups around FailAction: AutoCodec not needed, and include error message in cache key.

PiperOrigin-RevId: 333835998
diff --git a/src/main/java/com/google/devtools/build/lib/actions/FailAction.java b/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
index ab7628d..81c2084 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
@@ -21,7 +21,6 @@
 import com.google.devtools.build.lib.server.FailureDetails;
 import com.google.devtools.build.lib.server.FailureDetails.FailAction.Code;
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.Fingerprint;
 import javax.annotation.Nullable;
@@ -30,7 +29,6 @@
  * FailAction is an Action that always fails to execute. (Used as scaffolding for rules we haven't
  * yet implemented. Also useful for testing.)
  */
-@AutoCodec
 @Immutable
 public final class FailAction extends AbstractAction {
 
@@ -61,7 +59,11 @@
         false,
         DetailedExitCode.of(
             FailureDetail.newBuilder()
-                .setMessage("FailAction intentional failure: " + errorMessage)
+                .setMessage(
+                    "FailAction intentional failure: "
+                        + errorMessage
+                        + " caused by "
+                        + getOwner().getLabel())
                 .setFailAction(
                     FailureDetails.FailAction.newBuilder().setCode(Code.INTENTIONAL_FAILURE))
                 .build()));
@@ -73,6 +75,8 @@
       @Nullable ArtifactExpander artifactExpander,
       Fingerprint fp) {
     fp.addString(GUID);
+    // Should never be cached, but just be safe.
+    fp.addString(getErrorMessage());
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index 3d66fda..f61fd6a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -330,7 +330,7 @@
     }
 
     try {
-      boolean creatingFailActions = false;
+      Class<?> missingFragmentClass = null;
       for (Class<?> fragmentClass :
           configurationFragmentPolicy.getRequiredConfigurationFragments()) {
         if (!configuration.hasFragment(fragmentClass.asSubclass(Fragment.class))) {
@@ -344,12 +344,12 @@
               return null;
             }
             // Otherwise missingFragmentPolicy == MissingFragmentPolicy.CREATE_FAIL_ACTIONS:
-            creatingFailActions = true;
+            missingFragmentClass = fragmentClass;
           }
         }
       }
-      if (creatingFailActions) {
-        return createFailConfiguredTarget(ruleContext);
+      if (missingFragmentClass != null) {
+        return createFailConfiguredTargetForMissingFragmentClass(ruleContext, missingFragmentClass);
       }
       if (rule.getRuleClassObject().isStarlark()) {
         // TODO(bazel-team): maybe merge with RuleConfiguredTargetBuilder?
@@ -614,16 +614,24 @@
 
   /**
    * A pseudo-implementation for configured targets that creates fail actions for all declared
-   * outputs, both implicit and explicit.
+   * outputs, both implicit and explicit, due to a missing fragment class.
    */
-  private static ConfiguredTarget createFailConfiguredTarget(RuleContext ruleContext)
-      throws RuleErrorException, ActionConflictException {
+  private static ConfiguredTarget createFailConfiguredTargetForMissingFragmentClass(
+      RuleContext ruleContext, Class<?> missingFragmentClass) {
     RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext);
     if (!ruleContext.getOutputArtifacts().isEmpty()) {
-      ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
-          ruleContext.getOutputArtifacts(), "Can't build this"));
+      ruleContext.registerAction(
+          new FailAction(
+              ruleContext.getActionOwner(),
+              ruleContext.getOutputArtifacts(),
+              "Missing fragment class: " + missingFragmentClass.getName()));
     }
     builder.add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY));
-    return builder.build();
+    try {
+      return builder.build();
+    } catch (ActionConflictException e) {
+      throw new IllegalStateException(
+          "Can't have an action conflict with one action: " + ruleContext.getLabel(), e);
+    }
   }
 }