diff --git a/build-android.gradle b/build-android.gradle index e7b046b..a7901ec 100644 --- a/build-android.gradle +++ b/build-android.gradle @@ -9,7 +9,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.0' + classpath 'com.android.tools.build:gradle:4.2.0' } } // This Gradle script is used only when we are running tests in an Android environment to verify @@ -60,6 +60,14 @@ android { } dependencies { + // See note in build-shared.gradle on the purpose of "privateImplementation". The + // Android Gradle plugin doesn't seem to have a good way to customize the classpath + // of the compile and test tasks, but since we're not actually publishing any + // Android artifacts from this project (we use this build only for CI testing), we + // can simply copy the dependencies from "privateImplementation" into the standard + // "implementation" for the Android build. + implementation configurations.privateImplementation + androidTestImplementation "junit:junit:4.12" androidTestImplementation "org.hamcrest:hamcrest-library:1.3" androidTestImplementation "com.android.support.test:runner:1.0.2" diff --git a/build-shared.gradle b/build-shared.gradle index a6ec4eb..085dd5f 100644 --- a/build-shared.gradle +++ b/build-shared.gradle @@ -17,17 +17,36 @@ ext { ext.versions = [ "gson": "2.7", - "jackson": "2.10.0" + "jacksonCore": "2.10.5", + "jacksonDatabind": "2.10.5.1" ] ext.libraries = [:] +configurations { + privateImplementation +} + dependencies { - // Dependencies will not be exposed in the pom - see below in pom.withXml block - implementation "com.google.code.gson:gson:${versions.gson}" - implementation "com.fasterxml.jackson.core:jackson-core:${versions.jackson}" - implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}" + // The Gson and Jackson dependencies go into a custom configuration here, instead of + // the regular "implementation" configuration. We don't want them to be visible at + // all in the module's published dependencies - not even in "runtime" scope - because: + // + // 1. For Gson: While java-sdk-common does need Gson in order to work, the + // LaunchDarkly SDKs that use java-sdk-common have different strategies for packaging + // Gson. The Android SDK exposes it as a regular dependency; the Java server-side SDK + // embeds and shades Gson and does not expose it as a dependency. So we are leaving + // it up to the SDK to provide Gson in some way. + // + // 2. For Jackson: The SDKs do not use, require, or embed Jackson; we provide the + // LDJackson class as a convenience for applications that do use Jackson, and it is + // only usable if the application already has Jackson in its classpath. So we do not + // want Jackson to show up as a transitive dependency. + privateImplementation "com.google.code.gson:gson:${versions.gson}" + privateImplementation "com.fasterxml.jackson.core:jackson-core:${versions.jacksonCore}" + privateImplementation "com.fasterxml.jackson.core:jackson-databind:${versions.jacksonDatabind}" + testImplementation configurations.privateImplementation testImplementation "org.hamcrest:hamcrest-library:1.3" testImplementation "junit:junit:4.12" } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 470f688..0000000 --- a/build.gradle +++ /dev/null @@ -1,217 +0,0 @@ - -buildscript { - repositories { - mavenCentral() - mavenLocal() - } -} - -plugins { - id "java" - id "java-library" - id "checkstyle" - id "jacoco" - id "signing" - id "maven-publish" - id "de.marcphilipp.nexus-publish" version "0.3.0" - id "io.codearte.nexus-staging" version "0.21.2" - id "org.ajoberstar.git-publish" version "2.1.3" - id "idea" -} - -repositories { - mavenLocal() - // Before LaunchDarkly release artifacts get synced to Maven Central they are here along with snapshots: - maven { url "https://oss.sonatype.org/content/groups/public/" } - mavenCentral() -} - -configurations.all { - // check for updates every build for dependencies with: 'changing: true' - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' -} - -apply from: 'build-shared.gradle' - -checkstyle { - configFile file("${project.rootDir}/checkstyle.xml") -} - -// custom tasks for creating source/javadoc jars -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -javadoc { - // Force the Javadoc build to fail if there are any Javadoc warnings. See: https://discuss.gradle.org/t/javadoc-fail-on-warning/18141/3 - // The '-quiet' as second argument is actually a hack, - // since the one parameter addStringOption doesn't seem to - // work, we extra add '-quiet', which is added anyway by - // gradle. See https://github.com/gradle/gradle/issues/2354 - // See JDK-8200363 (https://bugs.openjdk.java.net/browse/JDK-8200363) - // for information about the -Xwerror option. - options.addStringOption('Xwerror', '-quiet') -} - -artifacts { - archives jar, sourcesJar, javadocJar -} - -test { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - showStandardStreams = true - exceptionFormat = 'full' - } -} - -jacocoTestReport { // code coverage report - reports { - xml.enabled - csv.enabled true - html.enabled true - } -} - -jacocoTestCoverageVerification { - // See notes in CONTRIBUTING.md on code coverage. Unfortunately we can't configure line-by-line code - // coverage overrides within the source code itself, because Jacoco operates on bytecode. - violationRules { rules -> - def knownMissedLinesForMethods = [ - // The key for each of these items is the complete method signature minus the "com.launchdarkly.sdk." prefix. - "EvaluationReason.error(com.launchdarkly.sdk.EvaluationReason.ErrorKind)": 1, - "EvaluationReasonTypeAdapter.parse(com.google.gson.stream.JsonReader)": 1, - "LDValue.equals(java.lang.Object)": 1, - "LDValueTypeAdapter.read(com.google.gson.stream.JsonReader)": 1, - "json.JsonSerialization.getDeserializableClasses()": -1, - "json.LDGson.LDTypeAdapter.write(com.google.gson.stream.JsonWriter, java.lang.Object)": 1, - "json.LDJackson.GsonReaderToJacksonParserAdapter.peekInternal()": 3 - ] - - knownMissedLinesForMethods.each { partialSignature, maxMissedLines -> - if (maxMissedLines > 0) { // < 0 means skip entire method - rules.rule { - element = "METHOD" - includes = [ "com.launchdarkly.sdk." + partialSignature ] - limit { - counter = "LINE" - value = "MISSEDCOUNT" - maximum = maxMissedLines - } - } - } - } - - // General rule that we should expect 100% test coverage; exclude any methods that have overrides above - rule { - element = "METHOD" - limit { - counter = "LINE" - value = "MISSEDCOUNT" - maximum = 0 - } - excludes = knownMissedLinesForMethods.collect { partialSignature, maxMissedLines -> - "com.launchdarkly.sdk." + partialSignature - } - } - } -} - -idea { - module { - downloadJavadoc = true - downloadSources = true - } -} - -nexusStaging { - packageGroup = "com.launchdarkly" - numberOfRetries = 40 // we've seen extremely long delays in closing repositories -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - - groupId = 'com.launchdarkly' - artifactId = 'launchdarkly-java-sdk-common' - - artifact sourcesJar - artifact javadocJar - - pom { - name = 'launchdarkly-java-sdk-common' - description = 'LaunchDarkly SDK Java Common Classes' - url = 'https://github.com/launchdarkly/java-sdk-common' - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - developers { - developer { - name = 'LaunchDarkly' - email = 'team@launchdarkly.com' - } - } - scm { - connection = 'scm:git:git://github.com/launchdarkly/java-sdk-common.git' - developerConnection = 'scm:git:ssh:git@github.com:launchdarkly/java-sdk-common.git' - url = 'https://github.com/launchdarkly/java-sdk-common' - } - } - - // We are deliberately hiding our dependencies in the pom, for the following reasons: - // - // 1. Gson: While java-sdk-common does need Gson in order to work, the LaunchDarkly SDKs that use - // java-sdk-common have different strategies for packaging Gson. The Android SDK exposes it as a - // regular dependency; the Java server-side SDK embeds and shades Gson and does not expose it as - // a dependency. So we are leaving it up to the SDK to provide Gson in some way. - // - // 2. Jackson: The SDKs do not use, require, or embed Jackson; we provide the LDJackson class as - // a convenience for applications that do use Jackson. So we do not want it to be a transitive - // dependency. - pom.withXml { - asNode().dependencies.forEach { it.value = "" } - } - } - } - repositories { - mavenLocal() - } -} - -nexusPublishing { - clientTimeout = java.time.Duration.ofMinutes(2) // we've seen extremely long delays in creating repositories - repositories { - sonatype { - username = ossrhUsername - password = ossrhPassword - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -tasks.withType(Sign) { - onlyIf { !"1".equals(project.findProperty("LD_SKIP_SIGNING")) } // so we can build jars for testing in CI -} - -gitPublish { - repoUri = 'git@github.com:launchdarkly/java-sdk-common.git' - branch = 'gh-pages' - contents { - from javadoc - } - commitMessage = 'publishing javadocs' -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..04f37af --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,180 @@ +import java.time.Duration +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.external.javadoc.CoreJavadocOptions + +// These values come from gradle.properties +val ossrhUsername: String by project +val ossrhPassword: String by project + +buildscript { + repositories { + mavenCentral() + mavenLocal() + } +} + +plugins { + java + "java-library" + checkstyle + signing + "maven-publish" + idea + jacoco + id("de.marcphilipp.nexus-publish") version "0.3.0" + id("io.codearte.nexus-staging") version "0.30.0" +} + +repositories { + mavenLocal() + // Before LaunchDarkly release artifacts get synced to Maven Central they are here along with snapshots: + maven { url = uri("https://oss.sonatype.org/content/groups/public/") } + mavenCentral() +} + +apply { from("build-shared.gradle") } + +java { + withJavadocJar() + withSourcesJar() +} + +checkstyle { + configFile = file("${project.rootDir}/checkstyle.xml") +} + +tasks.compileJava { + // See note in build-shared.gradle on the purpose of "privateImplementation" + classpath = configurations["privateImplementation"] +} + +tasks.javadoc.configure { + // Force the Javadoc build to fail if there are any Javadoc warnings. See: https://discuss.gradle.org/t/javadoc-fail-on-warning/18141/3 + // See JDK-8200363 (https://bugs.openjdk.java.net/browse/JDK-8200363) + // for information about the -Xwerror option. + (options as CoreJavadocOptions).addStringOption("Xwerror") + + // See note in build-shared.gradle on the purpose of "privateImplementation" + classpath = configurations["privateImplementation"] +} + +tasks.test.configure { + testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + showStandardStreams = true + exceptionFormat = TestExceptionFormat.FULL + } +} + +tasks.jacocoTestReport.configure { + reports { + xml.isEnabled = true + csv.isEnabled = true + html.isEnabled = true + } +} + +tasks.jacocoTestCoverageVerification.configure { + // See notes in CONTRIBUTING.md on code coverage. Unfortunately we can't configure line-by-line code + // coverage overrides within the source code itself, because Jacoco operates on bytecode. + violationRules { + val knownMissedLinesForMethods = mapOf( + "EvaluationReason.error(com.launchdarkly.sdk.EvaluationReason.ErrorKind)" to 1, + "EvaluationReasonTypeAdapter.parse(com.google.gson.stream.JsonReader)" to 1, + "LDValue.equals(java.lang.Object)" to 1, + "LDValueTypeAdapter.read(com.google.gson.stream.JsonReader)" to 1, + "json.JsonSerialization.getDeserializableClasses()" to -1, + "json.LDGson.LDTypeAdapter.write(com.google.gson.stream.JsonWriter, java.lang.Object)" to 1, + "json.LDJackson.GsonReaderToJacksonParserAdapter.peekInternal()" to 3 + ) + + knownMissedLinesForMethods.forEach { (signature, maxMissedLines) -> + if (maxMissedLines > 0) { // < 0 means skip entire method + rule { + element = "METHOD" + includes = listOf("com.launchdarkly.sdk." + signature) + limit { + counter = "LINE" + value = "MISSEDCOUNT" + maximum = maxMissedLines.toBigDecimal() + } + } + } + } + + // General rule that we should expect 100% test coverage; exclude any methods that have overrides above + rule { + element = "METHOD" + limit { + counter = "LINE" + value = "MISSEDCOUNT" + maximum = 0.toBigDecimal() + } + excludes = knownMissedLinesForMethods.map { (signature, maxMissedLines) -> + "com.launchdarkly.sdk." + signature } + } + } +} + +idea { + module { + isDownloadJavadoc = true + isDownloadSources = true + } +} + +nexusStaging { + packageGroup = "com.launchdarkly" + numberOfRetries = 40 // we've seen extremely long delays in closing repositories +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + + groupId = "com.launchdarkly" + artifactId = "launchdarkly-java-sdk-common" + + pom { + name.set("launchdarkly-java-sdk-common") + description.set("LaunchDarkly SDK Java Common Classes") + url.set("https://github.com/launchdarkly/java-sdk-common") + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + name.set("LaunchDarkly") + email.set("team@launchdarkly.com") + } + } + scm { + connection.set("scm:git:git://github.com/launchdarkly/java-sdk-common.git") + developerConnection.set("scm:git:ssh:git@github.com:launchdarkly/java-sdk-common.git") + url.set("https://github.com/launchdarkly/java-sdk-common") + } + } + } + } + repositories { + mavenLocal() + } +} + +nexusPublishing { + clientTimeout.set(Duration.ofMinutes(2)) // we've seen extremely long delays in creating repositories + repositories { + sonatype { + username.set(ossrhUsername) + password.set(ossrhPassword) + } + } +} + +signing { + sign(publishing.publications["mavenJava"]) +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf..f3d88b1 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a2bf131..442d913 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acf..2fe81a7 100755 --- a/gradlew +++ b/gradlew @@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +175,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a1..9109989 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"