Tags propagation for java rules

Part of #8830

RELNOTES[NEW]: tags: use --experimental_allow_tags_propagation flag to propagate tags to the action's execution requirements from java targets. Such tags should start with: no-, requires-, supports-, block-, disable-, cpu:. See #8830 for details.

Closes #9274.

PiperOrigin-RevId: 266772736
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
index cfc20bc..0c69af3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
@@ -38,6 +38,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaClasspathMode;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -189,7 +190,8 @@
       Artifact outputJar,
       Artifact manifestProtoOutput,
       @Nullable Artifact gensrcOutputJar,
-      @Nullable Artifact nativeHeaderOutput) {
+      @Nullable Artifact nativeHeaderOutput)
+      throws InterruptedException {
 
     JavaTargetAttributes attributes = getAttributes();
 
@@ -252,13 +254,19 @@
     return builder.build(ruleContext, semantics);
   }
 
-  private ImmutableMap<String, String> getExecutionInfo() {
-    return getConfiguration()
-        .modifiedExecutionInfo(
-            javaToolchain.getJavacSupportsWorkers()
-                ? ExecutionRequirements.WORKER_MODE_ENABLED
-                : ImmutableMap.of(),
-            JavaCompileActionBuilder.MNEMONIC);
+  private ImmutableMap<String, String> getExecutionInfo() throws InterruptedException {
+    ImmutableMap.Builder<String, String> executionInfo = ImmutableMap.builder();
+    executionInfo.putAll(
+        getConfiguration()
+            .modifiedExecutionInfo(
+                javaToolchain.getJavacSupportsWorkers()
+                    ? ExecutionRequirements.WORKER_MODE_ENABLED
+                    : ImmutableMap.of(),
+                JavaCompileActionBuilder.MNEMONIC));
+    executionInfo.putAll(
+        TargetUtils.getExecutionInfo(ruleContext.getRule(), ruleContext.isAllowTagsPropagation()));
+
+    return executionInfo.build();
   }
 
   /** Returns the bootclasspath explicit set in attributes if present, or else the default. */
@@ -352,7 +360,8 @@
    *     for new artifacts.
    */
   private Artifact createHeaderCompilationAction(
-      Artifact runtimeJar, JavaCompilationArtifacts.Builder artifactBuilder) {
+      Artifact runtimeJar, JavaCompilationArtifacts.Builder artifactBuilder)
+      throws InterruptedException {
 
     Artifact headerJar =
         getAnalysisEnvironment()
@@ -628,7 +637,7 @@
    * @return the header jar (if requested), or ijar (if requested), or else the class jar
    */
   public Artifact createCompileTimeJarAction(
-      Artifact runtimeJar, JavaCompilationArtifacts.Builder builder) {
+      Artifact runtimeJar, JavaCompilationArtifacts.Builder builder) throws InterruptedException {
     Artifact jar;
     boolean isFullJar = false;
     if (shouldUseHeaderCompilation()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
index 06e0187..8b0e08d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
@@ -44,6 +44,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.rules.java.JavaCompileAction.ProgressMessage;
 import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaClasspathMode;
 import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider.JavaPluginInfo;
@@ -215,7 +216,8 @@
   }
 
   /** Builds and registers the action for a header compilation. */
-  public void build(JavaToolchainProvider javaToolchain, JavaRuntimeInfo hostJavabase) {
+  public void build(JavaToolchainProvider javaToolchain, JavaRuntimeInfo hostJavabase)
+      throws InterruptedException {
     checkNotNull(outputDepsProto, "outputDepsProto must not be null");
     checkNotNull(sourceFiles, "sourceFiles must not be null");
     checkNotNull(sourceJars, "sourceJars must not be null");
@@ -329,7 +331,8 @@
 
     JavaConfiguration javaConfiguration =
         ruleContext.getConfiguration().getFragment(JavaConfiguration.class);
-    ImmutableMap<String, String> executionInfo = ImmutableMap.of();
+    ImmutableMap<String, String> executionInfo =
+        TargetUtils.getExecutionInfo(ruleContext.getRule(), ruleContext.isAllowTagsPropagation());
     Consumer<Pair<ActionExecutionContext, List<SpawnResult>>> resultConsumer = null;
     JavaClasspathMode classpathMode = javaConfiguration.getReduceJavaClasspath();
     if (classpathMode == JavaClasspathMode.BAZEL) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java
index d5184b7..30e377e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java
@@ -292,7 +292,7 @@
       JavaSemantics javaSemantics,
       Location location,
       Environment environment)
-      throws EvalException {
+      throws EvalException, InterruptedException {
 
     if (sourceJars.isEmpty()
         && sourceFiles.isEmpty()
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java
index ece3c58..341abf9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibraryHelper.java
@@ -182,7 +182,8 @@
       JavaRuntimeInfo hostJavabase,
       JavaRuleOutputJarsProvider.Builder outputJarsBuilder,
       boolean createOutputSourceJar,
-      @Nullable Artifact outputSourceJar) {
+      @Nullable Artifact outputSourceJar)
+      throws InterruptedException {
     return build(
         semantics,
         javaToolchainProvider,
@@ -204,7 +205,8 @@
       @Nullable Artifact outputSourceJar,
       @Nullable JavaInfo.Builder javaInfoBuilder,
       Iterable<JavaGenJarsProvider> transitiveJavaGenJars,
-      ImmutableList<Artifact> additionalJavaBaseInputs) {
+      ImmutableList<Artifact> additionalJavaBaseInputs)
+      throws InterruptedException {
 
     Preconditions.checkState(output != null, "must have an output file; use setOutput()");
     Preconditions.checkState(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoAspect.java
index da89907..f4f4ae5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoAspect.java
@@ -172,7 +172,7 @@
                   "exports", RuleConfiguredTarget.Mode.TARGET, JavaCompilationArgsProvider.class));
     }
 
-    void addProviders(ConfiguredAspect.Builder aspect) {
+    void addProviders(ConfiguredAspect.Builder aspect) throws InterruptedException {
       JavaInfo.Builder javaInfo = JavaInfo.Builder.create();
       // Represents the result of compiling the code generated for this proto, including all of its
       // dependencies.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
index 93ac592..98df054 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspect.java
@@ -192,7 +192,7 @@
                     JavaCompilationArgsProvider.class));
     }
 
-    void addProviders(ConfiguredAspect.Builder aspect) {
+    void addProviders(ConfiguredAspect.Builder aspect) throws InterruptedException {
       // Represents the result of compiling the code generated for this proto, including all of its
       // dependencies.
       JavaInfo.Builder javaInfo = JavaInfo.Builder.create();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspectCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspectCommon.java
index 422ce7b..08f6b44 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspectCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoAspectCommon.java
@@ -108,7 +108,8 @@
       String injectingRuleKind,
       Artifact sourceJar,
       Artifact outputJar,
-      JavaCompilationArgsProvider dep) {
+      JavaCompilationArgsProvider dep)
+      throws InterruptedException {
     JavaLibraryHelper helper =
         new JavaLibraryHelper(ruleContext)
             .setInjectingRuleKind(injectingRuleKind)
diff --git a/src/test/shell/bazel/tags_propagation_native_test.sh b/src/test/shell/bazel/tags_propagation_native_test.sh
index 7ffee2f..969f3fb 100755
--- a/src/test/shell/bazel/tags_propagation_native_test.sh
+++ b/src/test/shell/bazel/tags_propagation_native_test.sh
@@ -98,6 +98,119 @@
   assert_contains "no-remote:" output1
 }
 
+function test_java_library_tags_propagated() {
+  mkdir -p test
+  cat > test/BUILD <<EOF
+package(default_visibility = ["//visibility:public"])
+java_library(
+  name = 'test',
+  srcs = [ 'Hello.java' ],
+  tags = ["no-cache", "no-remote", "local"]
+)
+EOF
+
+	cat > test/Hello.java <<EOF
+public class Main {
+  public static void main(String[] args) {
+    System.out.println("Hello there");
+  }
+}
+EOF
+
+  bazel aquery --experimental_allow_tags_propagation '//test:test' > output1 2> $TEST_log \
+      || fail "should have generated output successfully"
+
+  assert_contains "ExecutionInfo: {" output1
+  assert_contains "local:" output1
+  assert_contains "no-cache:" output1
+  assert_contains "no-remote:" output1
+}
+
+function test_java_binary_tags_propagated() {
+  mkdir -p test
+  cat > test/BUILD <<EOF
+package(default_visibility = ["//visibility:public"])
+java_binary(
+  name = 'test',
+  srcs = [ 'Hello.java' ],
+  main_class = 'main.Hello',
+  tags = ["no-cache", "no-remote", "local"]
+)
+EOF
+
+	cat > test/Hello.java <<EOF
+public class Main {
+  public static void main(String[] args) {
+    System.out.println("Hello there");
+  }
+}
+EOF
+
+  bazel aquery --experimental_allow_tags_propagation '//test:test' > output1 2> $TEST_log \
+      || fail "should have generated output successfully"
+
+  assert_contains "ExecutionInfo: {" output1
+  assert_contains "local:" output1
+  assert_contains "no-cache:" output1
+  assert_contains "no-remote:" output1
+}
+
+function write_hello_library_files() {
+  local -r pkg="$1"
+  mkdir -p $pkg/java/main || fail "mkdir"
+  cat >$pkg/java/main/BUILD <<EOF
+java_binary(
+    name = 'main',
+    deps = ['//$pkg/java/hello_library'],
+    srcs = ['Main.java'],
+    main_class = 'main.Main',
+    tags = ["no-cache", "no-remote", "local"],
+    deploy_manifest_lines = ['k1: v1', 'k2: v2'])
+EOF
+
+  cat >$pkg/java/main/Main.java <<EOF
+package main;
+import hello_library.HelloLibrary;
+public class Main {
+  public static void main(String[] args) {
+    HelloLibrary.funcHelloLibrary();
+    System.out.println("Hello, World!");
+  }
+}
+EOF
+
+  mkdir -p $pkg/java/hello_library || fail "mkdir"
+  cat >$pkg/java/hello_library/BUILD <<EOF
+package(default_visibility=['//visibility:public'])
+java_library(name = 'hello_library',
+             srcs = ['HelloLibrary.java']);
+EOF
+
+  cat >$pkg/java/hello_library/HelloLibrary.java <<EOF
+package hello_library;
+public class HelloLibrary {
+  public static void funcHelloLibrary() {
+    System.out.print("Hello, Library!;");
+  }
+}
+EOF
+}
+
+function test_java_header_tags_propagated() {
+  local -r pkg="${FUNCNAME[0]}"
+  mkdir "$pkg" || fail "mkdir $pkg"
+  write_hello_library_files "$pkg"
+
+  bazel aquery --experimental_allow_tags_propagation --java_header_compilation=true //$pkg/java/main:main > output1 2> $TEST_log \
+      || fail "should have generated output successfully"
+
+  assert_contains "ExecutionInfo: {" output1
+  assert_contains "local:" output1
+  assert_contains "no-cache:" output1
+  assert_contains "no-remote:" output1
+
+}
+
 function test_genrule_tags_propagated() {
   mkdir -p test
   cat > test/BUILD <<EOF
@@ -193,4 +306,31 @@
   assert_not_contains "no-remote:" output1
 }
 
-run_suite "tags propagation: skylark rule tests"
+function test_java_tags_not_propagated_when_incompatible_flag_off() {
+  mkdir -p test
+  cat > test/BUILD <<EOF
+package(default_visibility = ["//visibility:public"])
+java_library(
+  name = 'test',
+  srcs = [ 'Hello.java' ],
+  tags = ["no-cache", "no-remote", "local"]
+)
+EOF
+
+	cat > test/Hello.java <<EOF
+public class Main {
+  public static void main(String[] args) {
+    System.out.println("Hello there");
+  }
+}
+EOF
+
+  bazel aquery --experimental_allow_tags_propagation=false '//test:test' > output1 2> $TEST_log \
+      || fail "should have generated output successfully"
+
+  assert_not_contains "local:" output1
+  assert_not_contains "no-cache:" output1
+  assert_not_contains "no-remote:" output1
+}
+
+run_suite "tags propagation: native rule tests"