diff --git a/.bazelrc b/.bazelrc index ecd54a58a52..e02e83d0858 100644 --- a/.bazelrc +++ b/.bazelrc @@ -6,3 +6,27 @@ build --host_javacopt=-g # TODO(ronshapiro): explore how much work it would be to reenable this build --javacopt="-Xep:BetaApi:OFF" build --host_javacopt="-Xep:BetaApi:OFF" + +# Note: This flag is required to prevent actions from clashing with each other +# when reading/writing tmp files. Without this flag we get errors like: +# +# Error: Cannot use file /tmp/hsperfdata_runner/12 because it is locked by +# another process +# +# This flag will be enabled by default in Bazel 7.0.0, but for now we enable it +# manually. For more details: https://github.com/bazelbuild/bazel/issues/3236. +build --incompatible_sandbox_hermetic_tmp + +# Sets the JDK for compiling sources and executing tests. +build --java_language_version=18 +build --tool_java_language_version=18 +build --java_runtime_version=remotejdk_18 +build --tool_java_runtime_version=remotejdk_18 + +# Default source/target versions. +build --javacopt="-source 8 -target 8" + +# Workaround for https://openjdk.java.net/jeps/411. +# See https://github.com/bazelbuild/bazel/issues/14502#issuecomment-1018366245. +build --jvmopt="-Djava.security.manager=allow" +build --jvmopt="--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED" diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 00000000000..c0be8a7992a --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +6.4.0 \ No newline at end of file diff --git a/.github/actions/artifact-verification-tests/action.yml b/.github/actions/artifact-verification-tests/action.yml new file mode 100644 index 00000000000..96e37925fb9 --- /dev/null +++ b/.github/actions/artifact-verification-tests/action.yml @@ -0,0 +1,25 @@ +name: 'Artifact verification tests' +description: 'Runs verification tests on the Dagger LOCAL-SNAPSHOT artifacts.' + +runs: + using: "composite" + steps: + - name: 'Check out repository' + uses: actions/checkout@v3 + - name: 'Cache Gradle files' + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: 'Download local snapshot for tests' + uses: actions/download-artifact@v3 + with: + name: local-snapshot + path: ~/.m2/repository/com/google/dagger + - name: 'Validate artifact jars' + run: ./util/validate-artifacts.sh + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a18be6594d..10a608480af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,6 @@ env: USE_JAVA_VERSION: '11' # This is required by AGP 8.3+. USE_JAVA_VERSION_FOR_PLUGIN: '17' - # Our Bazel builds currently rely on 6.4.0. The version is set via - # baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk. - USE_BAZEL_VERSION: '6.4.0' # The default Maven 3.9.0 has a regression so we manually install 3.8.7. # https://issues.apache.org/jira/browse/MNG-7679 USE_MAVEN_VERSION: '3.8.7' @@ -43,6 +40,13 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ./.github/actions/bazel-test + artifact-verification-tests: + name: 'Artifact verification tests' + needs: bazel-build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/artifact-verification-tests artifact-java-local-tests: name: 'Artifact Java local tests' needs: bazel-build @@ -98,7 +102,13 @@ jobs: name: 'Publish snapshot' # TODO(bcorso): Consider also waiting on artifact-android-emulator-tests # and artifact-android-emulator-legacy-api-tests after checking flakiness. - needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin] + needs: [ + bazel-test, + artifact-verification-tests, + artifact-java-local-tests, + artifact-android-local-tests, + test-gradle-plugin + ] if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master' runs-on: ubuntu-latest steps: @@ -177,7 +187,13 @@ jobs: name: 'Clean up GitHub Action caches' # TODO(bcorso): Consider also waiting on artifact-android-emulator-tests # and artifact-android-emulator-legacy-api-tests after checking flakiness. - needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin] + needs: [ + bazel-test, + artifact-verification-tests, + artifact-java-local-tests, + artifact-android-local-tests, + test-gradle-plugin + ] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 31ecc66bb78..182d5867a04 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,9 +12,6 @@ env: USE_JAVA_VERSION: '11' # This is required by AGP 8.3+. USE_JAVA_VERSION_FOR_PLUGIN: '17' - # Our Bazel builds currently rely on 6.4.0. The version is set via - # baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk. - USE_BAZEL_VERSION: '6.4.0' DAGGER_RELEASE_VERSION: "${{ github.event.inputs.dagger_release_version }}" # The default Maven 3.9.0 has a regression so we manually install 3.8.7. # https://issues.apache.org/jira/browse/MNG-7679 @@ -45,6 +42,13 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ./.github/actions/bazel-test + artifact-verification-tests: + name: 'Artifact verification tests' + needs: bazel-build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/artifact-verification-tests artifact-java-local-tests: name: 'Artifact Java local tests' needs: bazel-build @@ -80,7 +84,13 @@ jobs: jdk: '${{ matrix.jdk }}' publish-artifacts: name: 'Publish Artifact' - needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests, test-gradle-plugin] + needs: [ + bazel-test, + artifact-verification-tests, + artifact-java-local-tests, + artifact-android-local-tests, + test-gradle-plugin + ] runs-on: ubuntu-latest steps: - name: 'Install Java ${{ env.USE_JAVA_VERSION }}' diff --git a/BUILD b/BUILD index 25856d90411..f8b02b5064d 100644 --- a/BUILD +++ b/BUILD @@ -19,18 +19,18 @@ load("//tools/javadoc:javadoc.bzl", "javadoc_library") package(default_visibility = ["//visibility:public"]) -define_kt_toolchain( - name = "kotlin_toolchain", - api_version = "1.4", - jvm_target = "1.8", - language_version = "1.4", -) - package_group( name = "src", packages = ["//..."], ) +define_kt_toolchain( + name = "kotlin_toolchain", + api_version = "1.6", + jvm_target = "1.8", + language_version = "1.6", +) + java_library( name = "dagger_with_compiler", exported_plugins = ["//java/dagger/internal/codegen:component-codegen"], diff --git a/WORKSPACE b/WORKSPACE index ec2774bc7ed..d10d6ab5410 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -118,13 +118,13 @@ http_archive( # Load Robolectric repository ############################# -ROBOLECTRIC_VERSION = "4.4" +ROBOLECTRIC_VERSION = "4.11.1" http_archive( name = "robolectric", - sha256 = "d4f2eb078a51f4e534ebf5e18b6cd4646d05eae9b362ac40b93831bdf46112c7", + sha256 = "1ea1cfe67848decf959316e80dd69af2bbaa359ae2195efe1366cbdf3e968356", strip_prefix = "robolectric-bazel-%s" % ROBOLECTRIC_VERSION, - urls = ["https://github.com/robolectric/robolectric-bazel/archive/%s.tar.gz" % ROBOLECTRIC_VERSION], + urls = ["https://github.com/robolectric/robolectric-bazel/releases/download/%s/robolectric-bazel-%s.tar.gz" % (ROBOLECTRIC_VERSION, ROBOLECTRIC_VERSION)], ) load("@robolectric//bazel:robolectric.bzl", "robolectric_repositories") @@ -135,14 +135,14 @@ robolectric_repositories() # Load Kotlin repository ############################# -RULES_KOTLIN_TAG = "v1.8" +RULES_KOTLIN_TAG = "1.9.6" -RULES_KOTLIN_SHA = "01293740a16e474669aba5b5a1fe3d368de5832442f164e4fbfc566815a8bc3a" +RULES_KOTLIN_SHA = "3b772976fec7bdcda1d84b9d39b176589424c047eb2175bed09aac630e50af43" http_archive( name = "io_bazel_rules_kotlin", sha256 = RULES_KOTLIN_SHA, - urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % RULES_KOTLIN_TAG], + urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v%s/rules_kotlin-v%s.tar.gz" % (RULES_KOTLIN_TAG, RULES_KOTLIN_TAG)], ) load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories", "kotlinc_version") @@ -159,9 +159,7 @@ kotlin_repositories( ), ) -load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains") - -kt_register_toolchains() +register_toolchains("//:kotlin_toolchain") ############################# # Load Maven dependencies @@ -301,8 +299,8 @@ maven_install( "org.ow2.asm:asm:%s" % ASM_VERSION, "org.ow2.asm:asm-tree:%s" % ASM_VERSION, "org.ow2.asm:asm-commons:%s" % ASM_VERSION, - "org.robolectric:robolectric:4.4", - "org.robolectric:shadows-framework:4.4", # For ActivityController + "org.robolectric:robolectric:%s" % ROBOLECTRIC_VERSION, + "org.robolectric:shadows-framework:%s" % ROBOLECTRIC_VERSION, # For ActivityController ], repositories = [ "https://repo1.maven.org/maven2", diff --git a/gwt/BUILD b/gwt/BUILD index 87b7c957aa8..88f622d4469 100644 --- a/gwt/BUILD +++ b/gwt/BUILD @@ -16,13 +16,14 @@ # GWT-specific files for Dagger load("@rules_java//java:defs.bzl", "java_library") -load("//:build_defs.bzl", "POM_VERSION") +load("//:build_defs.bzl", "JAVA_RELEASE_MIN", "POM_VERSION") load("//tools/maven:maven.bzl", "dagger_pom_file") package(default_visibility = ["//:src"]) java_library( name = "gwt", + javacopts = JAVA_RELEASE_MIN, resource_strip_prefix = "gwt/", resources = glob(["**/*.gwt.xml"]), tags = ["maven_coordinates=com.google.dagger:dagger-gwt:" + POM_VERSION], diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD index e8e0824ba22..e445d2e21fb 100644 --- a/java/dagger/android/BUILD +++ b/java/dagger/android/BUILD @@ -17,6 +17,8 @@ load( "//:build_defs.bzl", + "DOCLINT_HTML_AND_SYNTAX", + "JAVA_RELEASE_MIN", "POM_VERSION", ) load("//tools:dejetify.bzl", "dejetified_library") @@ -43,6 +45,7 @@ filegroup( android_library( name = "android", srcs = SRCS, + javacopts = JAVA_RELEASE_MIN + DOCLINT_HTML_AND_SYNTAX, plugins = [ "//java/dagger/android/internal/proguard:plugin", ], diff --git a/java/dagger/android/support/BUILD b/java/dagger/android/support/BUILD index f404f1ae969..bedf1ffeb65 100644 --- a/java/dagger/android/support/BUILD +++ b/java/dagger/android/support/BUILD @@ -17,6 +17,8 @@ load( "//:build_defs.bzl", + "DOCLINT_HTML_AND_SYNTAX", + "JAVA_RELEASE_MIN", "POM_VERSION", ) load("//tools:dejetify.bzl", "dejetified_library") @@ -36,6 +38,7 @@ filegroup( android_library( name = "support", srcs = glob(["*.java"]), + javacopts = JAVA_RELEASE_MIN + DOCLINT_HTML_AND_SYNTAX, tags = ["maven_coordinates=com.google.dagger:dagger-android-support:" + POM_VERSION], deps = [ "//:dagger_with_compiler", diff --git a/java/dagger/grpc/server/BUILD b/java/dagger/grpc/server/BUILD index 83d96e8cd09..49d23b08310 100644 --- a/java/dagger/grpc/server/BUILD +++ b/java/dagger/grpc/server/BUILD @@ -5,6 +5,7 @@ load( "//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES", + "JAVA_RELEASE_MIN", "POM_VERSION", ) load("//tools/javadoc:javadoc.bzl", "javadoc_library") @@ -21,7 +22,7 @@ ANNOTATIONS_SRCS = [ java_library( name = "annotations", srcs = ANNOTATIONS_SRCS, - javacopts = DOCLINT_HTML_AND_SYNTAX, + javacopts = DOCLINT_HTML_AND_SYNTAX + JAVA_RELEASE_MIN, tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server-annotations:" + POM_VERSION], deps = [ "//third_party/java/jsr330_inject", @@ -36,7 +37,7 @@ java_library( exclude = ANNOTATIONS_SRCS, ), exported_plugins = ["//java/dagger/grpc/server/processor:plugin"], - javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES, + javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES + JAVA_RELEASE_MIN, tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server:" + POM_VERSION], exports = [":annotations"], deps = [ diff --git a/tools/bazel.rc b/tools/bazel.rc deleted file mode 100644 index 2707c1c3ac6..00000000000 --- a/tools/bazel.rc +++ /dev/null @@ -1,11 +0,0 @@ -# Global bazelrc file (see https://bazel.build/run/bazelrc#global-bazelrc) - -# Note: This flag is required to prevent actions from clashing with each when -# reading/writing tmp files. Without this flag we get errors like: -# -# Error: Cannot use file /tmp/hsperfdata_runner/12 because it is locked by -# another process -# -# This flag will be enabled by default in Bazel 7.0.0, but for now we enable it -# manually. For more details: https://github.com/bazelbuild/bazel/issues/3236. -build --incompatible_sandbox_hermetic_tmp \ No newline at end of file diff --git a/tools/jarjar/jarjar_runner.sh b/tools/jarjar/jarjar_runner.sh index 20bc27ca764..502fea0409f 100755 --- a/tools/jarjar/jarjar_runner.sh +++ b/tools/jarjar/jarjar_runner.sh @@ -59,6 +59,12 @@ fi popd &>/dev/null -"${JARJAR}" process "${RULES_FILE}" "${TMPDIR}/combined.jar" "${OUTFILE}" +# If the RULES_FILE exists and is not empty then run jarjar. +# Otherwise, we're done so just copy the combined jar to the output file. +if [[ -f "${RULES_FILE}" && -s "${RULES_FILE}" ]]; then + "${JARJAR}" process "${RULES_FILE}" "${TMPDIR}/combined.jar" "${OUTFILE}" +else + cp $TMPDIR/combined.jar $OUTFILE +fi rm -rf "${TMPDIR}" diff --git a/util/deploy-library.sh b/util/deploy-library.sh index 35c566b6b7f..02962946d4c 100755 --- a/util/deploy-library.sh +++ b/util/deploy-library.sh @@ -33,9 +33,6 @@ deploy_library() { library="${library%.*}-shaded.${library##*.}" fi - # Validate that the classes in the library jar begin with expected prefixes. - validate_jar $(bazel_output_file $library) - # TODO(bcorso): Consider moving this into the "gen_maven_artifact" macro, this # requires having the version checked-in for the build system. add_tracking_version \ @@ -101,20 +98,6 @@ add_tracking_version() { fi } -validate_jar() { - local library=$1 - if [[ $library == */gwt/libgwt.jar ]]; then - python $(dirname $0)/validate-jar-entry-prefixes.py \ - $library "dagger/,META-INF/,javax/inject/" - elif [[ $library == */java/dagger/hilt/android/artifact.aar ]]; then - python $(dirname $0)/validate-jar-entry-prefixes.py \ - $library "dagger/,META-INF/,hilt_aggregated_deps/" - else - python $(dirname $0)/validate-jar-entry-prefixes.py \ - $library "dagger/,META-INF/" - fi -} - add_automatic_module_name_manifest_entry() { local library=$1 local module_name=$2 diff --git a/util/validate-artifacts.sh b/util/validate-artifacts.sh new file mode 100755 index 00000000000..d26c6b7d4b8 --- /dev/null +++ b/util/validate-artifacts.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +set -eu + +readonly M2_DAGGER_REPO=~/.m2/repository/com/google/dagger +readonly JDK7="51" +readonly JDK8="52" + +_validate_jar() { + local artifact_id=$1 + local artifact_jar=$M2_DAGGER_REPO/$1/LOCAL-SNAPSHOT/$1-LOCAL-SNAPSHOT.$2 + local java_language_level=$3 + + # Validate the java language level of the classes in the jar. + python $(dirname $0)/validate-jar-language-level.py \ + $artifact_jar $java_language_level + + # Validate the package prefixes of the files in the jar. + if [[ $artifact_id == "dagger-gwt" ]]; then + python $(dirname $0)/validate-jar-entry-prefixes.py \ + $artifact_jar "dagger/,META-INF/,javax/inject/" + elif [[ $artifact_id == "hilt-android" ]]; then + python $(dirname $0)/validate-jar-entry-prefixes.py \ + $artifact_jar "dagger/,META-INF/,hilt_aggregated_deps/" + else + python $(dirname $0)/validate-jar-entry-prefixes.py \ + $artifact_jar "dagger/,META-INF/" + fi +} + +# Dagger API artifacts +_validate_jar "dagger-gwt" "jar" $JDK7 +_validate_jar "dagger" "jar" $JDK7 +_validate_jar "dagger-android" "aar" $JDK7 +_validate_jar "dagger-android-legacy" "aar" $JDK7 +_validate_jar "dagger-android-support" "aar" $JDK7 +_validate_jar "dagger-android-support-legacy" "aar" $JDK7 +_validate_jar "dagger-producers" "jar" $JDK7 +_validate_jar "dagger-grpc-server" "jar" $JDK7 +_validate_jar "dagger-grpc-server-annotations" "jar" $JDK7 +_validate_jar "dagger-lint" "jar" $JDK8 +_validate_jar "dagger-lint-aar" "aar" $JDK8 + +# Hilt API artifacts +# TODO(bcorso): reenable hilt-android-gradle-plugin validation. +# _validate_jar "hilt-android-gradle-plugin" "jar" $JDK8 +_validate_jar "hilt-core" "jar" $JDK8 +_validate_jar "hilt-android" "aar" $JDK8 +_validate_jar "hilt-android-testing" "aar" $JDK8 + +# Processor artifacts +_validate_jar "dagger-spi" "jar" $JDK8 +_validate_jar "dagger-compiler" "jar" $JDK8 +_validate_jar "dagger-android-processor" "jar" $JDK8 +_validate_jar "dagger-grpc-server-processor" "jar" $JDK8 +_validate_jar "hilt-compiler" "jar" $JDK8 +_validate_jar "hilt-android-compiler" "jar" $JDK8 \ No newline at end of file diff --git a/util/validate-jar-language-level.py b/util/validate-jar-language-level.py new file mode 100644 index 00000000000..ef8afed19a5 --- /dev/null +++ b/util/validate-jar-language-level.py @@ -0,0 +1,109 @@ +"""Validates classes in the deployed jar have a max java language level . + +Usage: + python validate-jar-language-level.py +""" + +import re +import shutil +import subprocess +import sys +import tempfile +import zipfile + + +_LANGUAGE_LEVEL_PATTERN = re.compile(r'major version: (\d+)') + + +def main(argv): + if len(argv) > 3: + raise ValueError( + 'Expected only two arguments but got {0}'.format(len(argv)) + ) + + jar_file, expected_language_level = argv[-2:] + print( + 'Processing {0} with expected language level {1}...'.format( + jar_file, + expected_language_level + ) + ) + if jar_file.endswith('.jar'): + invalid_entries = _invalid_language_level(jar_file, expected_language_level) + elif jar_file.endswith('.aar'): + dirpath = tempfile.mkdtemp() + with zipfile.ZipFile(jar_file, 'r') as zip_file: + class_file = zip_file.extract('classes.jar', dirpath) + invalid_entries = _invalid_language_level( + class_file, + expected_language_level + ) + shutil.rmtree(dirpath) + else: + raise ValueError('Invalid jar file: {0}'.format(jar_file)) + + if invalid_entries: + raise ValueError( + 'Found invalid entries in {0} that do not match the expected java' + ' language level ({1}):\n {2}'.format( + jar_file, expected_language_level, '\n '.join(invalid_entries) + ) + ) + + +def _invalid_language_level(jar_file, expected_language_level): + """Returns a list of jar entries with invalid language levels.""" + invalid_entries = [] + with zipfile.ZipFile(jar_file, 'r') as zip_file: + class_infolist = [ + info for info in zip_file.infolist() + if ( + not info.is_dir() + and info.filename.endswith('.class') + and not is_shaded_class(info.filename) + ) + ] + num_classes = len(class_infolist) + for i, info in enumerate(class_infolist): + cmd = 'javap -cp {0} -v {1}'.format(jar_file, info.filename[:-6]) + output1 = subprocess.run( + cmd.split(), + stdout=subprocess.PIPE, + text=True, + check=True, + ) + matches = _LANGUAGE_LEVEL_PATTERN.findall(output1.stdout) + if len(matches) != 1: + raise ValueError('Expected exactly one match but found: %s' % matches) + class_language_level = matches[0] + if class_language_level != expected_language_level: + invalid_entries.append( + '{0}: {1}'.format(info.filename, class_language_level) + ) + # This can take a while so print an update. + print( + ' ({0} of {1}) Found language level {2}: {3}'.format( + i + 1, + num_classes, + class_language_level, + info.filename, + ) + ) + + return invalid_entries + + +def is_shaded_class(filename): + # Ignore the shaded deps because we don't really control these classes. + shaded_prefixes = [ + 'dagger/spi/internal/shaded/', + 'dagger/grpc/shaded/', + ] + for shaded_prefix in shaded_prefixes: + if filename.startswith(shaded_prefix): + return True + return False + + +if __name__ == '__main__': + main(sys.argv)