Fix `java_single_jar` to propagate full transitive classpath and use shell param file format

`java_single_jar` previously set `runtime_classpath = inputs` in `JavaRuntimeClasspathInfo`, which only included the filtered outputs rather than the full transitive runtime dependencies (`all_inputs`). When `java_single_jar` targets were used in `deploy_env` of other deploy JAR rules, dependencies excluded from the inner JAR were not properly excluded from the outer JAR.

Also configure `args.set_param_file_format("shell")` (matching `java_binary_deploy_jar.bzl`) so arguments in `deploy_manifest_lines` containing whitespace or embedded newlines are properly quoted in param files.

Add unit tests for `deploy_manifest_lines`, transitive `deploy_env` exclusion, and `java_binary` consuming `java_single_jar` via `deploy_env`.

PiperOrigin-RevId: 971365057
Change-Id: I47df6dbe444d1e5d29fabc730ee4d68555332a25
diff --git a/java/common/rules/java_single_jar.bzl b/java/common/rules/java_single_jar.bzl
index ca76887..54e9f28 100644
--- a/java/common/rules/java_single_jar.bzl
+++ b/java/common/rules/java_single_jar.bzl
@@ -37,7 +37,8 @@
                     fail("unexpected file type in java_single_jar.deps: %s" % f.path)
                 files.append(f)
             transitive_inputs.append(depset(files))
-    inputs = depset(transitive = transitive_inputs)
+    all_inputs = depset(transitive = transitive_inputs)
+    inputs = all_inputs
 
     if hasattr(java_common, "JavaRuntimeClasspathInfo"):
         deploy_env_jars = depset(transitive = [
@@ -47,15 +48,15 @@
         excluded_jars = {jar: None for jar in deploy_env_jars.to_list()}
         if excluded_jars:
             inputs = depset([jar for jar in inputs.to_list() if jar not in excluded_jars])
-    return inputs
+    return inputs, all_inputs
 
 def _bazel_java_single_jar_impl(ctx):
-    inputs = _single_jar_inputs(ctx.attr.deps, ctx.attr.deploy_env)
+    inputs, all_inputs = _single_jar_inputs(ctx.attr.deps, ctx.attr.deploy_env)
 
     args = ctx.actions.args()
     args.add_all("--sources", inputs)
     args.use_param_file("@%s")
-    args.set_param_file_format("multiline")
+    args.set_param_file_format("shell")
     args.add_all("--deploy_manifest_lines", ctx.attr.deploy_manifest_lines)
     args.add("--output", ctx.outputs.output)
     args.add("--normalize")
@@ -102,7 +103,7 @@
         runfiles = ctx.runfiles(transitive_files = files),
     )]
     if hasattr(java_common, "JavaRuntimeClasspathInfo"):
-        providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = inputs))
+        providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = all_inputs))
     return providers
 
 bazel_java_single_jar = rule(
diff --git a/test/java/common/rules/java_single_jar_tests.bzl b/test/java/common/rules/java_single_jar_tests.bzl
index 488aab3..7d0796a 100644
--- a/test/java/common/rules/java_single_jar_tests.bzl
+++ b/test/java/common/rules/java_single_jar_tests.bzl
@@ -3,6 +3,8 @@
 load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
 load("@rules_testing//lib:truth.bzl", "matching")
 load("@rules_testing//lib:util.bzl", "util")
+load("//java:java_binary.bzl", "java_binary")
+load("//java:java_library.bzl", "java_library")
 load("//java:java_single_jar.bzl", "java_single_jar")
 load("//java/common:java_semantics.bzl", "semantics")
 
@@ -155,15 +157,131 @@
         for f in targets.build_info[OutputGroupInfo].redacted_build_info_files.to_list()
     ])
 
+def _test_java_single_jar_deploy_manifest_lines(name):
+    util.helper_target(
+        java_single_jar,
+        name = name + "/jar",
+        deps = ["1.jar"],
+        deploy_manifest_lines = [
+            "Manifest-Entry-A: valueA",
+            "Manifest-Entry-B: line1,\n line2",
+        ],
+    )
+
+    analysis_test(
+        name = name,
+        impl = _test_java_single_jar_deploy_manifest_lines_impl,
+        target = name + "/jar",
+    )
+
+def _test_java_single_jar_deploy_manifest_lines_impl(env, target):
+    assert_that_action = env.expect.that_target(target).action_named("JavaSingleJar")
+    assert_that_action.argv().contains_at_least([
+        "--deploy_manifest_lines",
+        "Manifest-Entry-A: valueA",
+        "Manifest-Entry-B: line1,\n line2",
+    ])
+
+def _test_java_single_jar_transitive_deploy_env(name):
+    util.helper_target(
+        java_library,
+        name = name + "_lib_a",
+        srcs = ["A.java"],
+    )
+    util.helper_target(
+        java_library,
+        name = name + "_lib_b",
+        srcs = ["B.java"],
+    )
+    util.helper_target(
+        java_library,
+        name = name + "_lib_c",
+        srcs = ["C.java"],
+    )
+    util.helper_target(
+        java_single_jar,
+        name = name + "_env1",
+        deps = [name + "_lib_a"],
+    )
+    util.helper_target(
+        java_single_jar,
+        name = name + "_inner",
+        deps = [name + "_lib_a", name + "_lib_b"],
+        deploy_env = [name + "_env1"],
+    )
+    util.helper_target(
+        java_single_jar,
+        name = name + "_outer",
+        deps = [name + "_lib_a", name + "_lib_b", name + "_lib_c"],
+        deploy_env = [name + "_inner"],
+    )
+
+    analysis_test(
+        name = name,
+        impl = _test_java_single_jar_transitive_deploy_env_impl,
+        target = name + "_outer",
+    )
+
+def _test_java_single_jar_transitive_deploy_env_impl(env, target):
+    assert_that_action = env.expect.that_target(target).action_named("JavaSingleJar")
+    assert_that_action.argv().contains_at_least([
+        "--sources",
+        "{bindir}/{package}/lib{test_name}_lib_c.jar",
+        "--output",
+    ])
+    assert_that_action.argv().not_contains("{bindir}/{package}/lib{test_name}_lib_a.jar")
+    assert_that_action.argv().not_contains("{bindir}/{package}/lib{test_name}_lib_b.jar")
+
+def _test_java_binary_deploy_env_with_java_single_jar(name):
+    util.helper_target(
+        java_library,
+        name = name + "_lib_a",
+        srcs = ["A.java"],
+    )
+    util.helper_target(
+        java_library,
+        name = name + "_lib_b",
+        srcs = ["B.java"],
+    )
+    util.helper_target(
+        java_single_jar,
+        name = name + "_single_jar",
+        deps = [name + "_lib_a"],
+    )
+    util.helper_target(
+        java_binary,
+        name = name + "_bin",
+        main_class = "Main",
+        runtime_deps = [name + "_lib_a", name + "_lib_b"],
+        deploy_env = [name + "_single_jar"],
+    )
+
+    analysis_test(
+        name = name,
+        attr_values = {"tags": ["min_bazel_8"]},  # the deploy jar was created by a separate rule in Bazel 7
+        impl = _test_java_binary_deploy_env_with_java_single_jar_impl,
+        target = name + "_bin",
+    )
+
+def _test_java_binary_deploy_env_with_java_single_jar_impl(env, target):
+    assert_that_action = env.expect.that_target(target).action_named("JavaDeployJar")
+    assert_that_action.inputs().contains_at_least([
+        "{package}/lib{test_name}_lib_b.jar",
+    ])
+    assert_that_action.inputs().not_contains("{package}/lib{test_name}_lib_a.jar")
+
 def java_single_jar_tests(name):
     test_suite(
         name = name,
         tests = [
             _test_java_single_jar_basic,
+            _test_java_single_jar_deploy_manifest_lines,
             _test_java_single_jar_force_enable_stamping,
             _test_java_single_jar_force_disable_stamping,
             _test_java_single_jar_stamping_enabled_build_data_excluded_fails,
             _test_java_single_jar_stamp_attr_auto_stamp_flag_enabled,
             _test_java_single_jar_stamp_attr_auto_stamp_flag_disabled,
+            _test_java_single_jar_transitive_deploy_env,
+            _test_java_binary_deploy_env_with_java_single_jar,
         ],
     )