diff --git a/examples/demoapp/BUILD b/examples/demoapp/BUILD index fc7063d..1dfede7 100644 --- a/examples/demoapp/BUILD +++ b/examples/demoapp/BUILD @@ -180,6 +180,13 @@ java_test( deps = [":demoapp_lib"] + test_deps + springboottest_deps, ) +java_test( + name = "PackagingTest", + srcs = ["src/test/java/com/salesforce/rules_spring/PackagingTest.java"], + data = [":demoapp"], + deps = [":demoapp_lib"] + test_deps, +) + licenses_used( name = "demoapp_licenses", out = "demoapp_licenses.json", diff --git a/examples/demoapp/src/test/java/com/salesforce/rules_spring/PackagingTest.java b/examples/demoapp/src/test/java/com/salesforce/rules_spring/PackagingTest.java new file mode 100644 index 0000000..c75b43a --- /dev/null +++ b/examples/demoapp/src/test/java/com/salesforce/rules_spring/PackagingTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause +*/ +package com.salesforce.rules_spring; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static org.junit.Assert.*; + +/** + */ +public class PackagingTest { + + File springbootJarFile = null; + + // file contents + String gitPropertiesContents = null; + String buildPropertiesContents = null; + String applicationPropertiesContents = null; + + // file existence + boolean exists_lib1 = false; + boolean exists_lib2 = false; + boolean exists_lib3_neverlink = false; + + @Before + public void setup() throws Exception { + springbootJarFile = new File("./examples/demoapp/demoapp.jar"); + if (!springbootJarFile.exists()) { + throw new IllegalStateException("Missing demoapp springboot jar; looked in path: " + + springbootJarFile.getAbsolutePath()); + } + extractFilesFromSpringBootJar(); + } + + @Test + public void gitPropertiesFileTest() { + assertNotNull(gitPropertiesContents); + assertTrue(gitPropertiesContents.contains("git.commit")); + } + + @Test + public void buildPropertiesFileTest() { + assertNotNull(buildPropertiesContents); + assertTrue(buildPropertiesContents.contains("build.number")); + } + + @Test + public void applicationPropertiesFileTest() { + assertNotNull(applicationPropertiesContents); + assertTrue(applicationPropertiesContents.contains("demoapp.config.internal")); + } + + @Test + public void internalLibsAreIncludedTest() { + assertTrue(this.exists_lib1); + assertTrue(this.exists_lib2); + } + + @Test + public void neverlinkLibsAreExcludedTest() { + assertFalse(this.exists_lib3_neverlink); + } + + private void extractFilesFromSpringBootJar() throws Exception { + try (ZipFile sbZip = new ZipFile(springbootJarFile)) { + Enumeration entries = sbZip.entries(); + for (Iterator it = entries.asIterator(); it.hasNext(); ) { + ZipEntry entry = it.next(); + String name = entry.getName(); + System.out.println(" zipentry: "+name); + if (name.equals("BOOT-INF/classes/git.properties")) { + InputStream is = sbZip.getInputStream(entry); + gitPropertiesContents = new String(is.readAllBytes(), StandardCharsets.UTF_8); + } else if (name.equals("BOOT-INF/classes/META-INF/build-info.properties")) { + InputStream is = sbZip.getInputStream(entry); + buildPropertiesContents = new String(is.readAllBytes(), StandardCharsets.UTF_8); + } else if (name.equals("BOOT-INF/classes/application.properties")) { + InputStream is = sbZip.getInputStream(entry); + applicationPropertiesContents = new String(is.readAllBytes(), StandardCharsets.UTF_8); + } else if (name.equals("BOOT-INF/lib/examples/demoapp/libs/lib1/liblib1.jar")) { + exists_lib1 = true; + } else if (name.equals("BOOT-INF/lib/examples/demoapp/libs/lib2/liblib2.jar")) { + exists_lib2 = true; + } else if (name.contains("neverlink")) { + // we have a lib named lib3_neverlink that has neverlink = True, which means it should NOT be + // included in the springboot jar + exists_lib3_neverlink = true; + } + } + } + } +} diff --git a/springboot/springboot.bzl b/springboot/springboot.bzl index 180d62a..a23ff66 100644 --- a/springboot/springboot.bzl +++ b/springboot/springboot.bzl @@ -222,9 +222,9 @@ def _banneddeps_rule_impl(ctx): if found_banned: ctx.actions.write(output, "FAIL", is_executable = False) - fail("Found banned jars in the springboot rule [" + ctx.label.name - + "] dependency list. Filenames:\n" + banned_filenames - + "\nYou can ignore these by setting deps_banned = [] on the springboot() rule.\n") + fail("Found banned jars in the springboot rule [" + ctx.label.name + + "] dependency list. Filenames:\n" + banned_filenames + + "\nYou can ignore these by setting deps_banned = [] on the springboot() rule.\n") else: ctx.actions.write(output, "SUCCESS", is_executable = False) return [DefaultInfo(files = depset(outputs))] @@ -237,11 +237,9 @@ _banneddeps_rule = rule( "deps_banned": attr.string_list(), "deps": attr.label_list(), "out": attr.string(), - } + }, ) - - # *************************************************************** # Outer launcher script for "bazel run" @@ -297,21 +295,21 @@ def _springboot_rule_impl(ctx): # into the _bazelrun_script_template text defined above outer_bazelrun_script_contents = _bazelrun_script_template \ .replace("%bazelrun_script%", ctx.attr.bazelrun_script.files.to_list()[0].short_path) \ - .replace("%name%", ctx.attr.name) + .replace("%name%", ctx.attr.name) # the bazelrun_java_toolchain optional, if set, we use it as the jvm for bazel run if ctx.attr.bazelrun_java_toolchain != None: - # lookup the path to selected java toolchain, and string sub it into the bazel run script - # text _bazelrun_script_template defined above - java_runtime = ctx.attr.bazelrun_java_toolchain[java_common.JavaToolchainInfo].java_runtime - java_bin = [f for f in java_runtime.files.to_list() if f.path.endswith("bin/java") or f.path.endswith("bin/java.exe")][0] - outer_bazelrun_script_contents = outer_bazelrun_script_contents \ - .replace("%java_toolchain_attr%", java_bin.path) - outer_bazelrun_script_contents = outer_bazelrun_script_contents \ - .replace("%java_toolchain_name_attr%", ctx.attr.bazelrun_java_toolchain.label.name) + # lookup the path to selected java toolchain, and string sub it into the bazel run script + # text _bazelrun_script_template defined above + java_runtime = ctx.attr.bazelrun_java_toolchain[java_common.JavaToolchainInfo].java_runtime + java_bin = [f for f in java_runtime.files.to_list() if f.path.endswith("bin/java") or f.path.endswith("bin/java.exe")][0] + outer_bazelrun_script_contents = outer_bazelrun_script_contents \ + .replace("%java_toolchain_attr%", java_bin.path) + outer_bazelrun_script_contents = outer_bazelrun_script_contents \ + .replace("%java_toolchain_name_attr%", ctx.attr.bazelrun_java_toolchain.label.name) else: - outer_bazelrun_script_contents = outer_bazelrun_script_contents \ - .replace("%java_toolchain_attr%", "") + outer_bazelrun_script_contents = outer_bazelrun_script_contents \ + .replace("%java_toolchain_attr%", "") outer_bazelrun_script_file = ctx.actions.declare_file("%s" % ctx.label.name) ctx.actions.write(outer_bazelrun_script_file, outer_bazelrun_script_contents, is_executable = True) @@ -323,9 +321,9 @@ def _springboot_rule_impl(ctx): # and add any data files to runfiles if ctx.attr.bazelrun_data != None: - for data_target in ctx.attr.bazelrun_data: - for data_target in data_target.files.to_list(): - runfiles_list.append(data_target) + for data_target in ctx.attr.bazelrun_data: + for data_target in data_target.files.to_list(): + runfiles_list.append(data_target) return [DefaultInfo( files = outs, @@ -347,10 +345,8 @@ _springboot_rule = rule( "javaxdetect_rule": attr.label(), "banneddeps_rule": attr.label(), "apprun_rule": attr.label(), - - "bazelrun_script": attr.label(allow_files=True), - "bazelrun_data": attr.label_list(allow_files=True), - + "bazelrun_script": attr.label(allow_files = True), + "bazelrun_data": attr.label_list(allow_files = True), "bazelrun_java_toolchain": attr.label( mandatory = False, default = "@bazel_tools//tools/jdk:current_java_toolchain", @@ -368,7 +364,7 @@ def springboot( boot_app_class, boot_launcher_class = "org.springframework.boot.loader.JarLauncher", deps = None, - deps_banned = [ "junit", "mockito", ], # detects common mistake of test dep pollution + deps_banned = ["junit", "mockito"], # detects common mistake of test dep pollution deps_exclude = None, deps_exclude_paths = None, deps_index_file = None, @@ -377,7 +373,7 @@ def springboot( dupeclassescheck_ignorelist = None, javaxdetect_enable = None, javaxdetect_ignorelist = None, - include_git_properties_file=True, + include_git_properties_file = True, bazelrun_java_toolchain = None, bazelrun_script = None, bazelrun_jvm_flags = None, @@ -391,17 +387,16 @@ def springboot( visibility = None, bazelrun_addopens = [], bazelrun_addexports = [], - jartools_toolchains = ["@bazel_tools//tools/jdk:current_host_java_runtime"], # Issue 250 - exclude = [], # deprecated - classpath_index = "@rules_spring//springboot:empty.txt", # deprecated - use_build_dependency_order = True, # deprecated - fail_on_duplicate_classes = False, # deprecated - duplicate_class_allowlist = None, # deprecated - jvm_flags = "", # deprecated - data = [], # deprecated + jartools_toolchains = ["@bazel_tools//tools/jdk:current_host_java_runtime"], # Issue 250 + exclude = [], # deprecated + classpath_index = "@rules_spring//springboot:empty.txt", # deprecated + use_build_dependency_order = True, # deprecated + fail_on_duplicate_classes = False, # deprecated + duplicate_class_allowlist = None, # deprecated + jvm_flags = "", # deprecated + data = [], # deprecated restricted_to = None, - target_compatible_with = [], - ): + target_compatible_with = []): """Bazel rule for packaging an executable Spring Boot application. Note that the rule README has more detailed usage instructions for each attribute. @@ -610,22 +605,20 @@ def springboot( visibility = visibility, ) - - # SUBRULE 3B: GENERATE THE ENV VARIABLES USED BY THE BAZELRUN LAUNCHER SCRIPT genbazelrunenv_out = name + "_bazelrun_env.sh" native.genrule( name = genbazelrunenv_rule, srcs = bazelrun_data, - cmd = "$(location @rules_spring//springboot:write_bazelrun_env.sh) " + name + " " + _get_springboot_jar_file_name(name) - + " " + _get_relative_package_path() + " $@ " + _convert_starlarkbool_to_bashbool(bazelrun_background) - + " $(SRCS)" - + " start_flags" - + " " + " ".join(["--add-exports=" + element for element in bazelrun_addexports]) - + " " + " ".join(["--add-opens=" + element for element in bazelrun_addopens]) - + " " + bazelrun_jvm_flags - + " start_envs" - + " " + bazelrun_env_flags, + cmd = "$(location @rules_spring//springboot:write_bazelrun_env.sh) " + name + " " + _get_springboot_jar_file_name(name) + + " " + _get_relative_package_path() + " $@ " + _convert_starlarkbool_to_bashbool(bazelrun_background) + + " $(SRCS)" + + " start_flags" + + " " + " ".join(["--add-exports=" + element for element in bazelrun_addexports]) + + " " + " ".join(["--add-opens=" + element for element in bazelrun_addopens]) + + " " + bazelrun_jvm_flags + + " start_envs" + + " " + bazelrun_env_flags, # message = "SpringBoot rule is writing the bazel run launcher env...", tools = ["@rules_spring//springboot:write_bazelrun_env.sh"], outs = [genbazelrunenv_out], @@ -727,10 +720,8 @@ def springboot( dupecheck_rule = dupecheck_rule_label, javaxdetect_rule = javaxdetect_rule_label, apprun_rule = ":" + apprun_rule, - bazelrun_script = bazelrun_script, bazelrun_data = bazelrun_data, - tags = tags, testonly = testonly, restricted_to = restricted_to, @@ -747,7 +738,7 @@ def _get_springboot_jar_file_name(name): def _convert_starlarkbool_to_bashbool(starlarkbool): if starlarkbool: - return "true" + return "true" return "false" def _get_relative_package_path(): diff --git a/springboot/springboot_pkg.sh b/springboot/springboot_pkg.sh index a4f8b7a..bed14ef 100755 --- a/springboot/springboot_pkg.sh +++ b/springboot/springboot_pkg.sh @@ -245,7 +245,7 @@ echo "DEBUG: finished copying transitives into BOOT-INF/lib, elapsed time (secon if [[ "$include_git_properties_file" == true ]]; then echo "DEBUG: adding git.properties" >> $debugfile cat $ruledir/$gitpropsfile >> $debugfile - cp -f $ruledir/$gitpropsfile $working_dir/BOOT-INF/classes + cp -f $ruledir/$gitpropsfile $working_dir/BOOT-INF/classes/git.properties fi # Inject the classpath index (unless it is the default empty.txt file). Requires Spring Boot version 2.3+