diff --git a/.travis.yml b/.travis.yml index f494148c45..b51351063b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: - echo "errorProne=true" >> $HOME/.gradle/gradle.properties install: - - ./gradlew assemble generateTestProto install + - ./gradlew assemble generateTestProto publishToMavenLocal - pushd examples && ./gradlew build && popd - pushd examples && mvn verify && popd - pushd examples/example-alts && ../gradlew build && popd diff --git a/COMPILING.md b/COMPILING.md index e23a2f425e..dfbc0c7222 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -19,7 +19,7 @@ $ ./gradlew build To install the artifacts to your Maven local repository for use in your own project, run: ``` -$ ./gradlew install +$ ./gradlew publishToMavenLocal ``` ### Notes for IntelliJ @@ -82,7 +82,7 @@ $ export CXXFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" When building on Windows and VC++, you need to specify project properties for Gradle to find protobuf: ``` -.\gradlew install ^ +.\gradlew publishToMavenLocal ^ -PvcProtobufInclude=C:\path\to\protobuf-3.5.1\src ^ -PvcProtobufLibs=C:\path\to\protobuf-3.5.1\vsprojects\Release ^ -PtargetArch=x86_32 diff --git a/alts/build.gradle b/alts/build.gradle index 56ab93ba04..5a53894926 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -61,15 +61,10 @@ import net.ltgt.gradle.errorprone.CheckSeverity javadoc { exclude 'io/grpc/alts/internal/**' } -artifacts { - archives shadowJar -} - jar { // Must use a different classifier to avoid conflicting with shadowJar classifier = 'original' } -configurations.archives.artifacts.removeAll { it.classifier == "original" } // We want to use grpc-netty-shaded instead of grpc-netty. But we also want our // source to work with Bazel, so we rewrite the code as part of the build. @@ -82,14 +77,21 @@ shadowJar { relocate 'io.netty', 'io.grpc.netty.shaded.io.netty' } -[ - install.repositories.mavenInstaller, - uploadArchives.repositories.mavenDeployer, -]*.pom*.whenConfigured { pom -> - def netty = pom.dependencies.find {dep -> dep.artifactId == 'grpc-netty'} - // Swap our dependency to grpc-netty-shaded. Projects depending on this via - // project(':grpc-alts') will still be using the non-shaded form. - netty.artifactId = "grpc-netty-shaded" - // Depend on specific version of grpc-netty-shaded because it is unstable API - netty.version = "[" + netty.version + "]" +publishing { + publications { + maven(MavenPublication) { + artifact shadowJar + + pom.withXml { + // Swap our dependency to grpc-netty-shaded. Projects depending on this via + // project(':grpc-alts') will still be using the non-shaded form. + asNode().dependencies.'*'.findAll() { dep -> + dep.artifactId.text() == 'grpc-netty' + }.each() { netty -> + netty.artifactId*.value = 'grpc-netty-shaded' + netty.version*.value = "[" + netty.version.text() + "]" + } + } + } + } } diff --git a/android/build.gradle b/android/build.gradle index 67cb515288..4f0d5713be 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -134,7 +134,6 @@ uploadArchives.repositories.mavenDeployer { name "gRPC Contributors" email "grpc-io@googlegroups.com" url "https://grpc.io/" - // https://issues.gradle.org/browse/GRADLE-2719 organization = "gRPC Authors" organizationUrl "https://www.google.com" } diff --git a/build.gradle b/build.gradle index ca776a3835..b94117e841 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,7 @@ subprojects { apply plugin: "checkstyle" apply plugin: "java" apply plugin: "maven" + apply plugin: "maven-publish" apply plugin: "idea" apply plugin: "signing" apply plugin: "jacoco" @@ -277,11 +278,6 @@ subprojects { 'org.openjdk.jmh:jmh-generator-bytecode:1.19' } - signing { - required false - sign configurations.archives - } - // Disable JavaDoc doclint on Java 8. It's annoying. if (JavaVersion.current().isJava8Compatible()) { allprojects { @@ -300,9 +296,7 @@ subprojects { } } - jacoco { - toolVersion = "0.8.2" - } + jacoco { toolVersion = "0.8.2" } checkstyle { configDir = file("$rootDir/buildscripts") @@ -348,79 +342,99 @@ subprojects { from sourceSets.main.allSource } - artifacts { archives javadocJar, sourcesJar } - - uploadArchives.repositories.mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - if (rootProject.hasProperty('repositoryDir')) { - repository(url: new File(rootProject.repositoryDir).toURI()) - } else { - String stagingUrl - if (rootProject.hasProperty('repositoryId')) { - stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' + - rootProject.repositoryId - } else { - stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' - } - def configureAuth = { - if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) { - authentication(userName: rootProject.ossrhUsername, password: rootProject.ossrhPassword) + publishing { + publications { + // do not use mavenJava, as java plugin will modify it via "magic" + maven(MavenPublication) { + if (!project.name.contains("grpc-netty-shaded") && !name.contains("grpc-alts") + && !name.contains("grpc-compiler")) { + from components.java } - } - repository(url: stagingUrl, configureAuth) - snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/', configureAuth) - } - } - uploadArchives.onlyIf { !name.contains("grpc-gae-interop-testing") && !name.contains("grpc-xds") } - [ - install.repositories.mavenInstaller, - uploadArchives.repositories.mavenDeployer, - ]*.pom*.whenConfigured { pom -> - pom.project { - name "$project.group:$project.name" - description project.description - url 'https://github.com/grpc/grpc-java' + artifact javadocJar + artifact sourcesJar - scm { - connection 'scm:git:https://github.com/grpc/grpc-java.git' - developerConnection 'scm:git:git@github.com:grpc/grpc-java.git' - url 'https://github.com/grpc/grpc-java' - } + pom { + name = project.group + ":" + project.name + url = 'https://github.com/grpc/grpc-java' + afterEvaluate { + // description is not available until evaluated. + description = project.description + } - licenses { - license { - name 'Apache 2.0' - url 'https://opensource.org/licenses/Apache-2.0' - } - } + scm { + connection = 'scm:git:https://github.com/grpc/grpc-java.git' + developerConnection = 'scm:git:git@github.com:grpc/grpc-java.git' + url = 'https://github.com/grpc/grpc-java' + } - developers { - developer { - id "grpc.io" - name "gRPC Contributors" - email "grpc-io@googlegroups.com" - url "https://grpc.io/" - // https://issues.gradle.org/browse/GRADLE-2719 - organization = "gRPC Authors" - organizationUrl "https://www.google.com" + licenses { + license { + name = 'Apache 2.0' + url = 'https://opensource.org/licenses/Apache-2.0' + } + } + + developers { + developer { + id = "grpc.io" + name = "gRPC Contributors" + email = "grpc-io@googlegroups.com" + url = "https://grpc.io/" + organization = "gRPC Authors" + organizationUrl = "https://www.google.com" + } + } + + withXml { + if (!(project.name in + [ + "grpc-stub", + "grpc-protobuf", + "grpc-protobuf-lite", + "grpc-protobuf-nano" + ])) { + asNode().dependencies.'*'.findAll() { dep -> + dep.artifactId.text() == 'grpc-core' + }.each() { core -> + core.version*.value = "[" + core.version.text() + "]" + } + } + } } } } - if (!(project.name in - [ - "grpc-stub", - "grpc-protobuf", - "grpc-protobuf-lite", - "grpc-protobuf-nano" - ])) { - def core = pom.dependencies.find {dep -> dep.artifactId == 'grpc-core'} - if (core != null) { - // Depend on specific version of grpc-core because internal package is unstable - core.version = "[" + core.version + "]" + repositories { + maven { + String stagingUrl + if (rootProject.hasProperty('repositoryId')) { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' + + rootProject.repositoryId + } else { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' + } + credentials { + if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) { + username = rootProject.ossrhUsername + password = rootProject.ossrhPassword + } + } + def releaseUrl = stagingUrl + def snapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' + url = version.endsWith('SNAPSHOT') ? snapshotUrl : releaseUrl } } } + + signing { + required false + sign publishing.publications.maven + } + + publishMavenPublicationToMavenRepository.onlyIf { + !name.contains("grpc-gae-interop-testing") && !name.contains("grpc-xds") + } + // At a test failure, log the stack trace to the console so that we don't // have to open the HTML in a browser. test { diff --git a/buildscripts/kokoro/android-interop.sh b/buildscripts/kokoro/android-interop.sh index a1439266d1..8c0fc55c59 100755 --- a/buildscripts/kokoro/android-interop.sh +++ b/buildscripts/kokoro/android-interop.sh @@ -19,7 +19,7 @@ export OS_NAME=$(uname) # Proto deps buildscripts/make_dependencies.sh -./gradlew install +./gradlew publishToMavenLocal # Build and run interop instrumentation tests on Firebase Test Lab diff --git a/buildscripts/kokoro/android.sh b/buildscripts/kokoro/android.sh index 971b456888..e261c5a2ac 100755 --- a/buildscripts/kokoro/android.sh +++ b/buildscripts/kokoro/android.sh @@ -19,7 +19,7 @@ export OS_NAME=$(uname) # Proto deps buildscripts/make_dependencies.sh -./gradlew install +./gradlew publishToMavenLocal # Build grpc-cronet @@ -79,7 +79,7 @@ new_apk_size="$(stat --printf=%s $HELLO_WORLD_OUTPUT_DIR/apk/release/app-release cd $BASE_DIR/github/grpc-java git checkout HEAD^ -./gradlew install +./gradlew publishToMavenLocal cd examples/android/helloworld/ ../../gradlew build diff --git a/buildscripts/kokoro/unix.sh b/buildscripts/kokoro/unix.sh index 3106f00793..7a82356e10 100755 --- a/buildscripts/kokoro/unix.sh +++ b/buildscripts/kokoro/unix.sh @@ -46,7 +46,7 @@ export CXXFLAGS="-I/tmp/protobuf/include" if [[ -z "${SKIP_TESTS:-}" ]]; then # Ensure all *.proto changes include *.java generated code - ./gradlew assemble generateTestProto install $GRADLE_FLAGS + ./gradlew assemble generateTestProto publishToMavenLocal $GRADLE_FLAGS if [[ -z "${SKIP_CLEAN_CHECK:-}" && ! -z $(git status --porcelain) ]]; then git status @@ -70,11 +70,11 @@ fi LOCAL_MVN_TEMP=$(mktemp -d) # Note that this disables parallel=true from GRADLE_FLAGS if [[ -z "${ALL_ARTIFACTS:-}" ]]; then - ./gradlew grpc-compiler:build grpc-compiler:uploadArchives $GRADLE_FLAGS \ - -Dorg.gradle.parallel=false -PrepositoryDir=$LOCAL_MVN_TEMP + ./gradlew grpc-compiler:build grpc-compiler:publishToMavenLocal $GRADLE_FLAGS \ + -Dorg.gradle.parallel=false -Dmaven.repo.local=$LOCAL_MVN_TEMP else - ./gradlew uploadArchives $GRADLE_FLAGS \ - -Dorg.gradle.parallel=false -PrepositoryDir=$LOCAL_MVN_TEMP + ./gradlew publishToMavenLocal $GRADLE_FLAGS \ + -Dorg.gradle.parallel=false -Dmaven.repo.local=$LOCAL_MVN_TEMP fi readonly MVN_ARTIFACT_DIR="${MVN_ARTIFACT_DIR:-$GRPC_JAVA_DIR/mvn-artifacts}" diff --git a/buildscripts/kokoro/windows32.bat b/buildscripts/kokoro/windows32.bat index dbe677d697..d9534eaf5b 100644 --- a/buildscripts/kokoro/windows32.bat +++ b/buildscripts/kokoro/windows32.bat @@ -48,4 +48,4 @@ IF NOT %GRADLEEXIT% == 0 ( @rem make sure no daemons have any files open cmd.exe /C "%WORKSPACE%\gradlew.bat --stop" -cmd.exe /C "%WORKSPACE%\gradlew.bat %GRADLE_FLAGS% -Dorg.gradle.parallel=false -PrepositoryDir=%WORKSPACE%\artifacts clean grpc-compiler:build grpc-compiler:uploadArchives" || exit /b 1 +cmd.exe /C "%WORKSPACE%\gradlew.bat %GRADLE_FLAGS% -Dorg.gradle.parallel=false -Dmaven.repo.local=%WORKSPACE%\artifacts clean grpc-compiler:build grpc-compiler:publishToMavenLocal" || exit /b 1 diff --git a/buildscripts/kokoro/windows64.bat b/buildscripts/kokoro/windows64.bat index 6346b44d1b..f3fbae8804 100644 --- a/buildscripts/kokoro/windows64.bat +++ b/buildscripts/kokoro/windows64.bat @@ -32,4 +32,4 @@ SET GRADLE_FLAGS=-PtargetArch=%TARGET_ARCH% -PfailOnWarnings=%FAIL_ON_WARNINGS% @rem make sure no daemons have any files open cmd.exe /C "%WORKSPACE%\gradlew.bat --stop" -cmd.exe /C "%WORKSPACE%\gradlew.bat %GRADLE_FLAGS% -Dorg.gradle.parallel=false -PrepositoryDir=%WORKSPACE%\artifacts clean grpc-compiler:build grpc-compiler:uploadArchives" || exit /b 1 +cmd.exe /C "%WORKSPACE%\gradlew.bat %GRADLE_FLAGS% -Dorg.gradle.parallel=false -Dmaven.repo.local=%WORKSPACE%\artifacts clean grpc-compiler:build grpc-compiler:publishToMavenLocal" || exit /b 1 diff --git a/compiler/README.md b/compiler/README.md index 0d10207df0..fc87b2d026 100644 --- a/compiler/README.md +++ b/compiler/README.md @@ -53,7 +53,7 @@ This will compile a codegen and put it under your ``~/.m2/repository``. This will make it available to any build tool that pulls codegens from Maven repostiories. ``` -$ ../gradlew install +$ ../gradlew publishToMavenLocal ``` ## Creating a release of GRPC Java diff --git a/compiler/build.gradle b/compiler/build.gradle index 59da081343..a35478446f 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -232,77 +232,71 @@ task buildArtifacts(type: Copy) { archivesBaseName = "$protocPluginBaseName" -artifacts { - archives("$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" as File) { - classifier osdetector.os + "-" + arch - type "exe" - extension "exe" - builtBy buildArtifacts +task checkArtifacts { + dependsOn buildArtifacts + doLast { + if (!usingVisualCpp) { + def ret = exec { + executable 'bash' + args 'check-artifact.sh', osdetector.os, arch + } + if (ret.exitValue != 0) { + throw new GradleException("check-artifact.sh exited with " + ret.exitValue) + } + } else { + def exeName = "$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" + def os = new ByteArrayOutputStream() + def ret = exec { + executable 'dumpbin' + args '/nologo', '/dependents', exeName + standardOutput = os + } + if (ret.exitValue != 0) { + throw new GradleException("dumpbin exited with " + ret.exitValue) + } + def dlls = os.toString() =~ /Image has the following dependencies:\s+(.*)\s+Summary/ + if (dlls[0][1] != "KERNEL32.dll") { + throw new Exception("unexpected dll deps: " + dlls[0][1]); + } + os.reset() + ret = exec { + executable 'dumpbin' + args '/nologo', '/headers', exeName + standardOutput = os + } + if (ret.exitValue != 0) { + throw new GradleException("dumpbin exited with " + ret.exitValue) + } + def machine = os.toString() =~ / machine \(([^)]+)\)/ + def expectedArch = [x86_32: "x86", x86_64: "x64"][arch] + if (machine[0][1] != expectedArch) { + throw new Exception("unexpected architecture: " + machine[0][1]); + } + } } } // Exe files are skipped by Maven by default. Override it. // Also skip jar files that is generated by the java plugin. -[ - install.repositories.mavenInstaller, - uploadArchives.repositories.mavenDeployer, -]*.setFilter {artifact, file -> - ! (file.getName().endsWith('jar') || file.getName().endsWith('jar.asc')) -} - -[ - uploadArchives.repositories.mavenDeployer, -]*.beforeDeployment { it -> - if (!usingVisualCpp) { - def ret = exec { - executable 'bash' - args 'check-artifact.sh', osdetector.os, arch +publishing { + publications { + maven(MavenPublication) { + // Removes all artifacts since grpc-compiler doesn't generates any Jar + artifacts = [] + artifactId 'protoc-gen-grpc-java' + artifact("$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" as File) { + classifier osdetector.os + "-" + arch + extension "exe" + builtBy checkArtifacts + } + pom.withXml { + // This isn't any sort of Java archive artifact, and OSSRH doesn't enforce + // javadoc for 'pom' packages. 'exe' would be a more appropriate packaging + // value, but it isn't clear how that will be interpreted. In addition, + // 'pom' is typically the value used when building an exe with Maven. + asNode().project.packaging*.value = 'pom' + } } - if (ret.exitValue != 0) { - throw new GradleException("check-artifact.sh exited with " + ret.exitValue) - } - } else { - def exeName = "$artifactStagingPath/java_plugin/${protocPluginBaseName}.exe" - def os = new ByteArrayOutputStream() - def ret = exec { - executable 'dumpbin' - args '/nologo', '/dependents', exeName - standardOutput = os - } - if (ret.exitValue != 0) { - throw new GradleException("dumpbin exited with " + ret.exitValue) - } - def dlls = os.toString() =~ /Image has the following dependencies:\s+(.*)\s+Summary/ - if (dlls[0][1] != "KERNEL32.dll") { - throw new Exception("unexpected dll deps: " + dlls[0][1]); - } - os.reset() - ret = exec { - executable 'dumpbin' - args '/nologo', '/headers', exeName - standardOutput = os - } - if (ret.exitValue != 0) { - throw new GradleException("dumpbin exited with " + ret.exitValue) - } - def machine = os.toString() =~ / machine \(([^)]+)\)/ - def expectedArch = [x86_32: "x86", x86_64: "x64"][arch] - if (machine[0][1] != expectedArch) { - throw new Exception("unexpected architecture: " + machine[0][1]); - } - } -} - -[ - install.repositories.mavenInstaller, - uploadArchives.repositories.mavenDeployer, -]*.pom*.whenConfigured { pom -> - pom.project { - // This isn't any sort of Java archive artifact, and OSSRH doesn't enforce - // javadoc for 'pom' packages. 'exe' would be a more appropriate packaging - // value, but it isn't clear how that will be interpreted. In addition, - // 'pom' is typically the value used when building an exe with Maven. - packaging = "pom" } } diff --git a/compiler/check-artifact.sh b/compiler/check-artifact.sh index af318611c9..d21bfca042 100755 --- a/compiler/check-artifact.sh +++ b/compiler/check-artifact.sh @@ -56,18 +56,18 @@ checkArch () echo Format=$format if [[ "$OS" == linux ]]; then if [[ "$ARCH" == x86_32 ]]; then - assertEq $format "elf32-i386" $LINENO + assertEq "$format" "elf32-i386" $LINENO elif [[ "$ARCH" == x86_64 ]]; then - assertEq $format "elf64-x86-64" $LINENO + assertEq "$format" "elf64-x86-64" $LINENO else fail "Unsupported arch: $ARCH" fi else # $OS == windows if [[ "$ARCH" == x86_32 ]]; then - assertEq $format "pei-i386" $LINENO + assertEq "$format" "pei-i386" $LINENO elif [[ "$ARCH" == x86_64 ]]; then - assertEq $format "pei-x86-64" $LINENO + assertEq "$format" "pei-x86-64" $LINENO else fail "Unsupported arch: $ARCH" fi @@ -76,9 +76,9 @@ checkArch () format="$(file -b "$1" | grep -o "[^ ]*$")" echo Format=$format if [[ "$ARCH" == x86_32 ]]; then - assertEq $format "i386" $LINENO + assertEq "$format" "i386" $LINENO elif [[ "$ARCH" == x86_64 ]]; then - assertEq $format "x86_64" $LINENO + assertEq "$format" "x86_64" $LINENO else fail "Unsupported arch: $ARCH" fi diff --git a/netty/shaded/build.gradle b/netty/shaded/build.gradle index 434b7fb109..dc39aa13e2 100644 --- a/netty/shaded/build.gradle +++ b/netty/shaded/build.gradle @@ -20,15 +20,10 @@ dependencies { shadow project(':grpc-core') } -artifacts { // We want uploadArchives to handle the shadowJar; we don't care about - // uploadShadow - archives shadowJar } - jar { // Must use a different classifier to avoid conflicting with shadowJar classifier = 'original' } -configurations.archives.artifacts.removeAll { it.classifier == "original" } shadowJar { classifier = null @@ -46,13 +41,26 @@ shadowJar { mergeServiceFiles() } -// This is a hack to have shadow plugin modify the uploadArchives POM's -// dependencies. If we delete the uploadShadow task, then the plugin will no -// longer modify the POM. This probably can break horribly with parallel build, -// but that's broken anyway with install/uploadArchives -uploadShadow.repositories.addAll(uploadArchives.repositories) -// And then we use a further hack to share that POM with install -install.repositories.mavenInstaller.pom = uploadArchives.repositories.mavenDeployer.pom +publishing { + publications { + maven(MavenPublication) { + // Ideally swap to project.shadow.component(it) when it isn't broken for project deps + artifact shadowJar + + pom.withXml { + def dependencies = asNode().appendNode('dependencies') + project.configurations.shadow.allDependencies.each { dep -> + def dependencyNode = dependencies.appendNode('dependency') + dependencyNode.appendNode('groupId', dep.group) + dependencyNode.appendNode('artifactId', dep.name) + def version = (dep.name == 'grpc-core') ? '[' + dep.version + ']' : dep.version + dependencyNode.appendNode('version', version) + dependencyNode.appendNode('scope', 'runtime') + } + } + } + } +} task testShadow(type: Test) { testClassesDirs = sourceSets.testShadow.output.classesDirs diff --git a/settings.gradle b/settings.gradle index 6564ea8a1b..9663a3c195 100644 --- a/settings.gradle +++ b/settings.gradle @@ -47,3 +47,6 @@ if (settings.hasProperty('skipCodegen') && skipCodegen.toBoolean()) { include ":grpc-compiler" project(':grpc-compiler').projectDir = "$rootDir/compiler" as File } + +// Gradle 5.0 changed the behavior of publishing block, use new stable behavior +enableFeaturePreview('STABLE_PUBLISHING')