Actions now have the option of returning an ActionResult, containing a (possibly empty) set of SpawnResults created during execution of the Action.

RELNOTES: None.
PiperOrigin-RevId: 172529328
diff --git a/src/test/java/com/google/devtools/build/lib/actions/ExecutableSymlinkActionTest.java b/src/test/java/com/google/devtools/build/lib/actions/ExecutableSymlinkActionTest.java
index 1458fdf..1849284 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/ExecutableSymlinkActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/ExecutableSymlinkActionTest.java
@@ -67,7 +67,8 @@
     Artifact input = new Artifact(inputFile, inputRoot);
     Artifact output = new Artifact(outputFile, outputRoot);
     ExecutableSymlinkAction action = new ExecutableSymlinkAction(NULL_ACTION_OWNER, input, output);
-    action.execute(createContext());
+    ActionResult actionResult = action.execute(createContext());
+    assertThat(actionResult.spawnResults()).isEmpty();
     assertThat(outputFile.resolveSymbolicLinks()).isEqualTo(inputFile);
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
index 9e7f9b7..4a58eae 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
@@ -34,6 +34,7 @@
 import com.google.devtools.build.lib.actions.ActionInputHelper;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
 import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
@@ -266,8 +267,8 @@
     }
 
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext) {
-
+    public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+      return ActionResult.EMPTY;
     }
 
     @Override protected String computeKey() {
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java b/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
index f5c1a96..5f7a680 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.actions.AbstractAction;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.util.Fingerprint;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -90,7 +91,7 @@
   }
 
   @Override
-  public void execute(ActionExecutionContext actionExecutionContext)
+  public ActionResult execute(ActionExecutionContext actionExecutionContext)
       throws ActionExecutionException {
     for (Artifact artifact : getInputs()) {
       // Do not check *.optional artifacts - artifacts with such extension are
@@ -120,6 +121,8 @@
     } catch (IOException e) {
       throw new AssertionError(e);
     }
+
+    return ActionResult.EMPTY;
   }
 
   @Override
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java
index d12b512..1d07a72 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionTestCase.java
@@ -23,6 +23,7 @@
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
 import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.analysis.util.ActionTester;
@@ -73,7 +74,8 @@
   }
 
   protected void checkCanWriteNonExecutableFile() throws Exception {
-    action.execute(context);
+    ActionResult actionResult = action.execute(context);
+    assertThat(actionResult.spawnResults()).isEmpty();
     String content = new String(FileSystemUtils.readContentAsLatin1(output));
     assertThat(content).isEqualTo("Hello World");
     assertThat(output.isExecutable()).isFalse();
@@ -83,7 +85,8 @@
     Artifact outputArtifact = getBinArtifactWithNoOwner("hello");
     Path output = outputArtifact.getPath();
     Action action = createAction(NULL_ACTION_OWNER, outputArtifact, "echo 'Hello World'", true);
-    action.execute(context);
+    ActionResult actionResult = action.execute(context);
+    assertThat(actionResult.spawnResults()).isEmpty();
     String content = new String(FileSystemUtils.readContentAsLatin1(output));
     assertThat(content).isEqualTo("echo 'Hello World'");
     assertThat(output.isExecutable()).isTrue();
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java
index dce0ce3..81ac13a 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java
@@ -21,6 +21,7 @@
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionInputHelper;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
@@ -83,7 +84,8 @@
     Action action = createParameterFileWriteAction(
         ImmutableList.<Artifact>of(), createNormalCommandLine());
     ActionExecutionContext context = actionExecutionContext();
-    action.execute(context);
+    ActionResult actionResult = action.execute(context);
+    assertThat(actionResult.spawnResults()).isEmpty();
     String content = new String(FileSystemUtils.readContentAsLatin1(outputArtifact.getPath()));
     assertThat(content.trim()).isEqualTo("--flag1\n--flag2\n--flag3\nvalue1\nvalue2");
   }
@@ -94,7 +96,8 @@
         ImmutableList.of(treeArtifact),
         createTreeArtifactExpansionCommandLine());
     ActionExecutionContext context = actionExecutionContext();
-    action.execute(context);
+    ActionResult actionResult = action.execute(context);
+    assertThat(actionResult.spawnResults()).isEmpty();
     String content = new String(FileSystemUtils.readContentAsLatin1(outputArtifact.getPath()));
     assertThat(content.trim())
         .isEqualTo(
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/PopulateTreeArtifactActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/PopulateTreeArtifactActionTest.java
index f12f380..1fb182a 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/PopulateTreeArtifactActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/PopulateTreeArtifactActionTest.java
@@ -25,6 +25,7 @@
 import com.google.devtools.build.lib.actions.ActionExecutionException;
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
@@ -166,7 +167,9 @@
     ArrayList<Artifact> treefileArtifacts = new ArrayList<Artifact>();
     PopulateTreeArtifactAction action = createPopulateTreeArtifactAction();
     ActionExecutionContext executionContext = actionExecutionContext(treefileArtifacts);
-    action.execute(executionContext);
+    ActionResult actionResult = action.execute(executionContext);
+
+    assertThat(actionResult.spawnResults()).isEmpty();
 
     assertThat(Artifact.toExecPaths(treefileArtifacts)).containsExactly(
         "test/archive_member/archive_members/1.class",
@@ -216,8 +219,9 @@
     ArrayList<Artifact> treeFileArtifacts = new ArrayList<Artifact>();
     ActionExecutionContext executionContext = actionExecutionContext(treeFileArtifacts);
 
-    action.execute(executionContext);
+    ActionResult actionResult = action.execute(executionContext);
 
+    assertThat(actionResult.spawnResults()).isEmpty();
     assertThat(treeFileArtifacts).isEmpty();
   }
 
@@ -231,7 +235,9 @@
 
     ArrayList<Artifact> treeFileArtifacts = new ArrayList<Artifact>();
     ActionExecutionContext executionContext = actionExecutionContext(treeFileArtifacts);
-    action.execute(executionContext);
+    ActionResult actionResult = action.execute(executionContext);
+
+    assertThat(actionResult.spawnResults()).isEmpty();
 
     // We check whether the parent directory structures of output TreeFileArtifacts exist even
     // though the spawn is not executed (the SpawnActionContext is mocked out).
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
index e0ae530..532615b 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
@@ -73,8 +74,17 @@
   @Test
   public void testSymlink() throws Exception {
     Executor executor = new TestExecutorBuilder(directories, null).build();
-    action.execute(new ActionExecutionContext(executor, null, ActionInputPrefetcher.NONE, null,
-        null, ImmutableMap.<String, String>of(), null));
+    ActionResult actionResult =
+        action.execute(
+            new ActionExecutionContext(
+                executor,
+                null,
+                ActionInputPrefetcher.NONE,
+                null,
+                null,
+                ImmutableMap.<String, String>of(),
+                null));
+    assertThat(actionResult.spawnResults()).isEmpty();
     assertThat(output.isSymbolicLink()).isTrue();
     assertThat(output.resolveSymbolicLinks()).isEqualTo(input);
     assertThat(action.getPrimaryInput()).isEqualTo(inputArtifact);
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
index f065cfd..b36f924 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
 import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactFactory;
 import com.google.devtools.build.lib.actions.ArtifactOwner;
@@ -209,7 +210,7 @@
     }
 
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
         throws ActionExecutionException {
       try {
         FileSystemUtils.writeContent(stableStatus.getPath(), new byte[] {});
@@ -217,6 +218,7 @@
       } catch (IOException e) {
         throw new ActionExecutionException(e, this, true);
       }
+      return ActionResult.EMPTY;
     }
 
     @Override
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
index 808b55f..e271d90 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
@@ -29,6 +29,7 @@
 import com.google.devtools.build.lib.actions.ActionExecutedEvent;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.BuildFailedException;
 import com.google.devtools.build.lib.actions.cache.ActionCache;
@@ -679,30 +680,33 @@
           ? ImmutableList.of(artifacts[0])
           : Artifact.NO_ARTIFACTS;
       final int iCopy = ii;
-      registerAction(new TestAction(new Callable<Void>() {
-          @Override
-          public Void call() throws Exception {
-            Thread.sleep(100); // 100ms
-            completedTasks.getAndIncrement();
-            throw new IOException("task failed");
-          }
-        },
-          inputs, ImmutableList.of(out)) {
-        @Override
-        public void execute(ActionExecutionContext actionExecutionContext)
-        throws ActionExecutionException {
-          if (catastrophe && iCopy == 0) {
-            try {
-              Thread.sleep(300); // 300ms
-            } catch (InterruptedException e) {
-              throw new RuntimeException(e);
+      registerAction(
+          new TestAction(
+              new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                  Thread.sleep(100); // 100ms
+                  completedTasks.getAndIncrement();
+                  throw new IOException("task failed");
+                }
+              },
+              inputs,
+              ImmutableList.of(out)) {
+            @Override
+            public ActionResult execute(ActionExecutionContext actionExecutionContext)
+                throws ActionExecutionException {
+              if (catastrophe && iCopy == 0) {
+                try {
+                  Thread.sleep(300); // 300ms
+                } catch (InterruptedException e) {
+                  throw new RuntimeException(e);
+                }
+                completedTasks.getAndIncrement();
+                throw new ActionExecutionException("This is a catastrophe", this, true);
+              }
+              return super.execute(actionExecutionContext);
             }
-            completedTasks.getAndIncrement();
-            throw new ActionExecutionException("This is a catastrophe", this, true);
-          }
-          super.execute(actionExecutionContext);
-        }
-      });
+          });
       artifacts[ii] = out;
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
index c6ac94a..6af5623 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeAwareActionTest.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
 import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
@@ -175,7 +176,7 @@
     }
 
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
         throws ActionExecutionException, InterruptedException {
       executionCounter.incrementAndGet();
 
@@ -197,6 +198,7 @@
       } catch (IOException e) {
         throw new ActionExecutionException(e, this, false);
       }
+      return ActionResult.EMPTY;
     }
 
     @Override
@@ -756,9 +758,10 @@
     registerAction(
         new SingleOutputAction(null, genFile1) {
           @Override
-          public void execute(ActionExecutionContext actionExecutionContext)
+          public ActionResult execute(ActionExecutionContext actionExecutionContext)
               throws ActionExecutionException, InterruptedException {
             writeOutput(null, "gen1");
+            return ActionResult.EMPTY;
           }
         });
 
@@ -770,9 +773,10 @@
           }
 
           @Override
-          public void execute(ActionExecutionContext actionExecutionContext)
+          public ActionResult execute(ActionExecutionContext actionExecutionContext)
               throws ActionExecutionException, InterruptedException {
             writeOutput(readInput(), "gen2");
+            return ActionResult.EMPTY;
           }
         });
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index 3ecc85b..de8a0be 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -36,6 +36,7 @@
 import com.google.devtools.build.lib.actions.ActionLogBufferPathGenerator;
 import com.google.devtools.build.lib.actions.ActionLookupData;
 import com.google.devtools.build.lib.actions.ActionLookupValue;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.BuildFailedException;
 import com.google.devtools.build.lib.actions.Executor;
@@ -410,9 +411,9 @@
     }
 
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
         throws ActionExecutionException {
-      super.execute(actionExecutionContext);
+      ActionResult actionResult = super.execute(actionExecutionContext);
       try {
         FileSystemUtils.copyFile(
             Iterables.getOnlyElement(getInputs()).getPath(),
@@ -420,6 +421,7 @@
       } catch (IOException e) {
         throw new IllegalStateException(e);
       }
+      return actionResult;
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
index a6057bc..fac36eb 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
@@ -34,6 +34,7 @@
 import com.google.devtools.build.lib.actions.ActionInput;
 import com.google.devtools.build.lib.actions.ActionInputFileCache;
 import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
@@ -148,23 +149,25 @@
     registerAction(actionOne);
 
     final Artifact normalOutput = createDerivedArtifact("normal/out");
-    Action testAction = new TestAction(
-        TestAction.NO_EFFECT, ImmutableList.of(outOne), ImmutableList.of(normalOutput)) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          // Check the file cache for input TreeFileArtifacts.
-          ActionInputFileCache fileCache = actionExecutionContext.getActionInputFileCache();
-          assertThat(fileCache.getMetadata(outOneFileOne).isFile()).isTrue();
-          assertThat(fileCache.getMetadata(outOneFileTwo).isFile()).isTrue();
+    Action testAction =
+        new TestAction(
+            TestAction.NO_EFFECT, ImmutableList.of(outOne), ImmutableList.of(normalOutput)) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              // Check the file cache for input TreeFileArtifacts.
+              ActionInputFileCache fileCache = actionExecutionContext.getActionInputFileCache();
+              assertThat(fileCache.getMetadata(outOneFileOne).isFile()).isTrue();
+              assertThat(fileCache.getMetadata(outOneFileTwo).isFile()).isTrue();
 
-          // Touch the action output.
-          touchFile(normalOutput);
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+              // Touch the action output.
+              touchFile(normalOutput);
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(testAction);
     buildArtifact(normalOutput);
@@ -470,21 +473,23 @@
   public void testOutputsAreReadOnlyAndExecutable() throws Exception {
     final Artifact out = createTreeArtifact("output");
 
-    TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          writeFile(out.getPath().getChild("one"), "one");
-          writeFile(out.getPath().getChild("two"), "two");
-          writeFile(out.getPath().getChild("three").getChild("four"), "three/four");
-          registerOutput(actionExecutionContext, "one");
-          registerOutput(actionExecutionContext, "two");
-          registerOutput(actionExecutionContext, "three/four");
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(out) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              writeFile(out.getPath().getChild("one"), "one");
+              writeFile(out.getPath().getChild("two"), "two");
+              writeFile(out.getPath().getChild("three").getChild("four"), "three/four");
+              registerOutput(actionExecutionContext, "one");
+              registerOutput(actionExecutionContext, "two");
+              registerOutput(actionExecutionContext, "three/four");
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
 
@@ -501,20 +506,21 @@
   public void testValidRelativeSymlinkAccepted() throws Exception {
     final Artifact out = createTreeArtifact("output");
 
-    TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          writeFile(out.getPath().getChild("one"), "one");
-          writeFile(out.getPath().getChild("two"), "two");
-          FileSystemUtils.ensureSymbolicLink(
-              out.getPath().getChild("links").getChild("link"),
-              "../one");
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(out) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              writeFile(out.getPath().getChild("one"), "one");
+              writeFile(out.getPath().getChild("two"), "two");
+              FileSystemUtils.ensureSymbolicLink(
+                  out.getPath().getChild("links").getChild("link"), "../one");
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
 
@@ -530,20 +536,21 @@
 
     final Artifact out = createTreeArtifact("output");
 
-    TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          writeFile(out.getPath().getChild("one"), "one");
-          writeFile(out.getPath().getChild("two"), "two");
-          FileSystemUtils.ensureSymbolicLink(
-              out.getPath().getChild("links").getChild("link"),
-              "../invalid");
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(out) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              writeFile(out.getPath().getChild("one"), "one");
+              writeFile(out.getPath().getChild("two"), "two");
+              FileSystemUtils.ensureSymbolicLink(
+                  out.getPath().getChild("links").getChild("link"), "../invalid");
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
 
@@ -569,20 +576,21 @@
 
     final Artifact out = createTreeArtifact("output");
 
-    TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          writeFile(out.getPath().getChild("one"), "one");
-          writeFile(out.getPath().getChild("two"), "two");
-          FileSystemUtils.ensureSymbolicLink(
-              out.getPath().getChild("links").getChild("link"),
-              "/random/pointer");
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(out) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              writeFile(out.getPath().getChild("one"), "one");
+              writeFile(out.getPath().getChild("two"), "two");
+              FileSystemUtils.ensureSymbolicLink(
+                  out.getPath().getChild("links").getChild("link"), "/random/pointer");
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
 
@@ -607,7 +615,7 @@
     TreeArtifactTestAction action =
         new TreeArtifactTestAction(out) {
           @Override
-          public void execute(ActionExecutionContext actionExecutionContext) {
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
             try {
               writeFile(out.getPath().getChild("one"), "one");
               writeFile(out.getPath().getChild("two"), "two");
@@ -616,6 +624,7 @@
             } catch (Exception e) {
               throw new RuntimeException(e);
             }
+            return ActionResult.EMPTY;
           }
         };
 
@@ -633,20 +642,21 @@
 
     final Artifact out = createTreeArtifact("output");
 
-    TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext) {
-        try {
-          writeFile(out.getPath().getChild("one"), "one");
-          writeFile(out.getPath().getChild("two"), "two");
-          FileSystemUtils.ensureSymbolicLink(
-              out.getPath().getChild("links").getChild("link"),
-              "../../output/random/pointer");
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(out) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext) {
+            try {
+              writeFile(out.getPath().getChild("one"), "one");
+              writeFile(out.getPath().getChild("two"), "two");
+              FileSystemUtils.ensureSymbolicLink(
+                  out.getPath().getChild("links").getChild("link"), "../../output/random/pointer");
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
 
@@ -673,27 +683,33 @@
   // TODO(bazel-team): write real tests for injectDigest, here and elsewhere.
   @Test
   public void testDigestInjection() throws Exception {
-    TreeArtifactTestAction action = new TreeArtifactTestAction(outOne) {
-      @Override
-      public void execute(ActionExecutionContext actionExecutionContext)
-          throws ActionExecutionException {
-        try {
-          writeFile(outOneFileOne, "one");
-          writeFile(outOneFileTwo, "two");
+    TreeArtifactTestAction action =
+        new TreeArtifactTestAction(outOne) {
+          @Override
+          public ActionResult execute(ActionExecutionContext actionExecutionContext)
+              throws ActionExecutionException {
+            try {
+              writeFile(outOneFileOne, "one");
+              writeFile(outOneFileTwo, "two");
 
-          MetadataHandler md = actionExecutionContext.getMetadataHandler();
-          FileStatus stat = outOneFileOne.getPath().stat(Symlinks.NOFOLLOW);
-          md.injectDigest(outOneFileOne,
-              stat, Hashing.md5().hashString("one", Charset.forName("UTF-8")).asBytes());
+              MetadataHandler md = actionExecutionContext.getMetadataHandler();
+              FileStatus stat = outOneFileOne.getPath().stat(Symlinks.NOFOLLOW);
+              md.injectDigest(
+                  outOneFileOne,
+                  stat,
+                  Hashing.md5().hashString("one", Charset.forName("UTF-8")).asBytes());
 
-          stat = outOneFileTwo.getPath().stat(Symlinks.NOFOLLOW);
-          md.injectDigest(outOneFileTwo,
-              stat, Hashing.md5().hashString("two", Charset.forName("UTF-8")).asBytes());
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
+              stat = outOneFileTwo.getPath().stat(Symlinks.NOFOLLOW);
+              md.injectDigest(
+                  outOneFileTwo,
+                  stat,
+                  Hashing.md5().hashString("two", Charset.forName("UTF-8")).asBytes());
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+            return ActionResult.EMPTY;
+          }
+        };
 
     registerAction(action);
     buildArtifact(action.getSoleOutput());
@@ -980,7 +996,7 @@
     }
 
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
         throws ActionExecutionException {
       if (getInputs().iterator().hasNext()) {
         // Sanity check--verify all inputs exist.
@@ -1010,6 +1026,7 @@
         throw new ActionExecutionException("TestAction failed due to exception",
             e, this, false);
       }
+      return ActionResult.EMPTY;
     }
 
     void executeTestBehavior(ActionExecutionContext c) throws ActionExecutionException {
@@ -1229,8 +1246,10 @@
 
     /** Do nothing */
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
-        throws ActionExecutionException {}
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
+        throws ActionExecutionException {
+      return ActionResult.EMPTY;
+    }
   }
 
   /** No-op action that throws when executed */
@@ -1241,7 +1260,7 @@
 
     /** Throws */
     @Override
-    public void execute(ActionExecutionContext actionExecutionContext)
+    public ActionResult execute(ActionExecutionContext actionExecutionContext)
         throws ActionExecutionException {
       throw new ActionExecutionException("Throwing dummy action", this, true);
     }