Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Gradle to 8.1.1 #4854

Merged
merged 13 commits into from
May 15, 2023
5 changes: 4 additions & 1 deletion .github/workflows/actions_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,10 @@ jobs:

- name: Run flaky tests
run: |
./gradlew --no-daemon --stacktrace --max-workers=2 --parallel check -PnoLint -PflakyTests=true
./gradlew --no-daemon --stacktrace --max-workers=2 --parallel check -PnoLint -PflakyTests=true \
-PbuildJdkVersion=${{ env.BUILD_JDK_VERSION }} \
-PtestJavaVersion=${{ env.BUILD_JDK_VERSION }} \
-Porg.gradle.java.installations.paths=${{ steps.setup-build-jdk.outputs.path }}

- name: Summarize the failed tests
if: failure()
Expand Down
2 changes: 2 additions & 0 deletions benchmarks/jmh/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ dependencies {
implementation project(':testing-internal')
}

tasks.sourcesJar.dependsOn(tasks.compileJmhThrift)

jmh {
duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE
jmhVersion = libs.versions.jmh.core.get()
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ allprojects {
tasks.withType(JavaForkOptions) {
maxHeapSize = '768m'

if (rootProject.ext.testJavaVersion >= 9) {
if (project.ext.testJavaVersion >= 9) {
jvmArgs '--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED'
}

Expand All @@ -74,7 +74,7 @@ allprojects {
// `-Pjava.security.manager` was added in Java 17 and the default value was changed to `disallow` in Java 18.
// - https://openjdk.org/jeps/411
// - https://bugs.openjdk.org/browse/JDK-8270380
if (rootProject.ext.testJavaVersion >= 17) {
if (project.ext.testJavaVersion >= 17) {
systemProperty "java.security.manager", "allow"
}

Expand Down
90 changes: 54 additions & 36 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mrJarVersions.each { version->
classpath = sourceSets."java${version}Test".runtimeClasspath

enabled = Integer.parseInt(JavaVersion.current().getMajorVersion()) >= version &&
rootProject.ext.testJavaVersion >= version
project.ext.testJavaVersion >= version
}

configurations."java${version}Implementation".extendsFrom configurations.implementation
Expand Down Expand Up @@ -173,45 +173,63 @@ if (!rootProject.hasProperty('noWeb')) {
// Run HttpServerStreamingTest separately with memory constraint.
tasks.test.exclude '**/HttpServerStreamingTest**'
tasks.shadedTest.exclude '**/HttpServerStreamingTest**'
task testStreaming(type: Test,
group: 'Verification',
description: 'Runs the streaming tests.',
dependsOn: tasks.shadedTestClasses) {
// Use small heap for streaming tests to quickly ensure we can stream the content larger than heap.
maxHeapSize = '64m'

include '**/HttpServerStreamingTest**'
testClassesDirs = tasks.shadedTest.testClassesDirs
classpath = testClassesDirs

// Set the class path as late as possible so that the 'shadedTest' task has the correct classpath.
doFirst {
classpath += project.files(configurations.shadedTestRuntime.resolve())
testing {
suites {
testStreaming(JvmTestSuite) {

group = 'Verification'
description = 'Runs the streaming tests.'

targets {
all {
testTask.configure {
dependsOn(tasks.shadedTestClasses)
// Use small heap for streaming tests to quickly ensure we can stream the content larger than heap.
maxHeapSize = '64m'

include '**/HttpServerStreamingTest**'
testClassesDirs = tasks.shadedTest.testClassesDirs
classpath = testClassesDirs

// Set the class path as late as possible so that the 'shadedTest' task has the correct classpath.
doFirst {
classpath += project.files(configurations.shadedTestRuntime.resolve())
}
}
}
}
}
}
}
tasks.shadedTest.finalizedBy tasks.testStreaming
tasks.check.dependsOn tasks.testStreaming

if (rootProject.findProperty('FLAKY_TESTS') != 'true') {
// Run the test cases based on reactive-streams-tck only with non-flaky mode
task testNg(type: Test,
group: 'Verification',
description: 'Runs the TestNG unit tests.',
dependsOn: tasks.shadedTestClasses) {
useTestNG()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gradle prohibits overriding the test engine with Test tasks.
On the other hand, the JVM Test Suite Plugin supports multiple test engines.
So the test tasks have been migrated to the new test plugin.

include '/com/linecorp/armeria/common/**'

scanForTestClasses = false
testClassesDirs = tasks.shadedTest.testClassesDirs
classpath = testClassesDirs

// Set the class path as late as possible so that the 'shadedTest' task has the correct classpath.
doFirst {
classpath += project.files(configurations.shadedTestRuntime.resolve())
tasks.shadedTest.finalizedBy testing.suites.testStreaming
tasks.check.dependsOn testing.suites.testStreaming

// Run the test cases based on reactive-streams-tck only with non-flaky mode
if (rootProject.findProperty('flakyTests') != 'true') {
testing {
suites {
testNg(JvmTestSuite) {
useTestNG()

targets {
all {
testTask.configure {
include '/com/linecorp/armeria/**/common/**'
dependsOn tasks.shadedTestClasses
scanForTestClasses = false
testClassesDirs = tasks.shadedTest.testClassesDirs
classpath = testClassesDirs
doFirst {
classpath += project.files(configurations.shadedTestRuntime.resolve())
}
}
}
}
}
}
}
tasks.shadedTest.finalizedBy tasks.testNg
tasks.check.dependsOn tasks.testNg
tasks.shadedTest.finalizedBy testing.suites.testNg
tasks.check.dependsOn testing.suites.testNg
}

if (tasks.findByName('trimShadedJar')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ public void required_completionFutureMustCompleteOnCancellation() throws Throwab
@Test
public void required_subscribeOnAbortedStreamMustFail() throws Throwable {
final StreamMessage<T> pub = createAbortedPublisher(0);
if (pub == null) {
notVerified();
}
assumeAbortedPublisherAvailable(pub);
assertThatThrownBy(() -> pub.whenComplete().join())
.isInstanceOf(CompletionException.class)
Expand Down Expand Up @@ -234,7 +231,7 @@ public void required_abortMustNotifySubscriber() throws Throwable {
.hasCauseInstanceOf(AbortedStreamException.class);
}

private void assumeAbortedPublisherAvailable(@Nullable Publisher<T> pub) {
protected void assumeAbortedPublisherAvailable(@Nullable Publisher<T> pub) {
if (pub == null) {
throw new SkipException("Skipping because no aborted StreamMessage provided.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@

package com.linecorp.armeria.internal.common.stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.util.concurrent.CompletionException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.LongStream;

import org.reactivestreams.Subscription;
import org.reactivestreams.tck.TestEnvironment.Latch;
import org.reactivestreams.tck.TestEnvironment.TestSubscriber;
import org.testng.annotations.Test;

import com.linecorp.armeria.common.stream.AbortedStreamException;
import com.linecorp.armeria.common.stream.StreamMessage;
import com.linecorp.armeria.common.stream.StreamMessageVerification;

Expand Down Expand Up @@ -58,4 +67,48 @@ public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue()
// are all pre-allocated.
notVerified();
}

/**
* Modified from {@link #optional_spec104_mustSignalOnErrorWhenFails()}.
*/
@Test
public void required_subscribeOnAbortedStreamMustFail() throws Throwable {
// EmptyFixedStreamMessage performs nothing on abortion.
final StreamMessage<Long> pub = createAbortedPublisher(1);
if (pub == null || pub instanceof EmptyFixedStreamMessage) {
notVerified();
}
assumeAbortedPublisherAvailable(pub);
assertThatThrownBy(() -> pub.whenComplete().join())
.isInstanceOf(CompletionException.class)
.hasCauseInstanceOf(AbortedStreamException.class);
assertThat(pub.isOpen()).isFalse();

final AtomicReference<Throwable> capturedCause = new AtomicReference<>();
final Latch onErrorLatch = new Latch(env());
final Latch onSubscribeLatch = new Latch(env());
pub.subscribe(new TestSubscriber<Long>(env()) {
@Override
public void onSubscribe(Subscription subs) {
onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
onSubscribeLatch.close();
}

@Override
public void onError(Throwable cause) {
onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
onErrorLatch.assertOpen(String.format(
"Error-state Publisher %s called `onError` twice on new Subscriber", pub));
capturedCause.set(cause);
onErrorLatch.close();
}
});

onSubscribeLatch.expectClose("Should have received onSubscribe");
onErrorLatch.expectClose(String.format(
"Error-state Publisher %s did not call `onError` on new Subscriber", pub));

env().verifyNoAsyncErrors();
assertThat(capturedCause.get()).isInstanceOf(AbortedStreamException.class);
}
}
4 changes: 2 additions & 2 deletions gradle/scripts/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/line/gradle-scripts
branch = main
commit = a706e2826247c958aed17a1d7ec1168bb1a9c7e1
parent = 506e1b3c1236579d7344e3f10f3de13f811af5b1
commit = c20bc5b416c7fe19475dd1a2ca658d9177d23f35
parent = d48d5fa5c0e30f34deac6df1ada7e41b58ae444c
method = merge
cmdver = 0.4.5
15 changes: 1 addition & 14 deletions gradle/scripts/lib/common-dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ buildscript {
}
}

def managedDependencyOverrides = [] as Set
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an unused code.


allprojects { p ->
ext {
// Add managedVersions() for backward compatibility with dependencies.yml
Expand Down Expand Up @@ -178,19 +176,8 @@ configure(projectsWithFlags('java')) {
dependencies {
configurations.configureEach { configuration ->
// Add to resolvable configurations
if (configuration.canBeResolved && !configuration.canBeConsumed) {
add(configuration.name, platform(dependencyManagementProject))
}

// Find version overrides in dependency declaration configurations
if (!configuration.canBeResolved && !configuration.canBeConsumed) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) I'm wondering if we want to target resolvable dependencies instead (since these are the configurations which will actually be applied)

Suggested change
if (!configuration.canBeResolved && !configuration.canBeConsumed) {
if (configuration.canBeResolved && !configuration.canBeConsumed) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are three types of configurations.

  • Bucket - implementation, api ...
  • Resolvable - compileClasspath, runtimeClasspath, ...
  • Consumable - apiElement, ...

We directly added the dependencies to resolvable configurations. In particular, platform dependencies are added to each configuration here. Unfortunately, in Gradle 8, bucket styles are only allowed to add dependencies, and exceptions are raised if the dependencies are added to resolvable ones.

So I changed to add the platform dependencies to the buckets. It should be fine because they will be eventually inherited into resolvable configurations. All resolvable configurations defined in the Gradle Java plugin have at least one bucket configuration.
https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph

The only exception was shadedTestRuntime created by gradle-scripts that does not have a bucket parent. I added shadedTestImplementation as a bucket so that we inject the platform dependencies into it. As shadedTestRuntime extends shadedTestImplementation, all dependencies added to shadedTestImplementation will be visible to shadedTestRuntime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understood the concept while reviewing the PR, but I'm not sure why I left this review 😅 Sorry about that.
In short, I understood that we can't add dependencies to a resolvable configuration 🙇

configuration.dependencies.configureEach { dep ->
if (dep instanceof org.gradle.api.artifacts.ExternalDependency) {
if (dep.version != null) {
managedDependencyOverrides.add(String.valueOf("${dep.module}:${dep.version}"))
}
}
}
add(configuration.name, platform(dependencyManagementProject))
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions gradle/scripts/lib/common-git.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,17 @@ private static String executeCommand(...command) {
def stdout = new StringWriter()
def stderr = new StringWriter()
proc.waitForProcessOutput(stdout, stderr)
def outMsg = stdout.toString().trim()

if (proc.exitValue() != 0) {
var errMsg = stderr.toString().trim()
if (errMsg.isEmpty()) {
errMsg = outMsg
}
throw new IOException(
"'${command}' exited with a non-zero exit code: ${proc.exitValue()}:" +
"${System.lineSeparator()}${stderr.toString().trim()}")
"${System.lineSeparator()}$errMsg")
}

return stdout.toString().trim()
return outMsg
}
15 changes: 10 additions & 5 deletions gradle/scripts/lib/java-alpn.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// JDK 9 or above does not require Jetty ALPN agent at all.
if (JavaVersion.current() >= JavaVersion.VERSION_1_9 && rootProject.ext.testJavaVersion != 8) {
return
}

configure(projectsWithFlags('java')) {
// JDK 9 or above does not require Jetty ALPN agent at all.
if (JavaVersion.current() >= JavaVersion.VERSION_1_9 && project.ext.testJavaVersion != 8) {
return
}

// Use Jetty ALPN agent if dependencyManagement mentions it.
if (managedVersions.containsKey('org.mortbay.jetty.alpn:jetty-alpn-agent')) {
configurations {
Expand All @@ -24,6 +24,11 @@ configure(projectsWithFlags('java')) {
fileName.replaceFirst("-[0-9]+\\.[0-9]+\\.[0-9]+(?:\\.[^.]+)?\\.jar", ".jar")
}
}
tasks.compileJava.dependsOn(tasks.copyAlpnAgent)
tasks.processResources.dependsOn(tasks.copyAlpnAgent)
tasks.sourcesJar.dependsOn(tasks.copyAlpnAgent)
tasks.javadoc.dependsOn(tasks.copyAlpnAgent)
project.ext.getLintTask().dependsOn(tasks.copyAlpnAgent)

tasks.withType(JavaForkOptions) {
dependsOn tasks.copyAlpnAgent
Expand Down
10 changes: 5 additions & 5 deletions gradle/scripts/lib/java-coverage.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ configure(rootProject) {
task jacocoTestReport(type: JacocoReport) {
def reportTask = delegate
reports {
csv.enabled = false
xml.enabled = true
xml.destination = file("${rootProject.buildDir}/report/jacoco/jacocoTestReport.xml")
html.enabled = true
html.destination = file("${rootProject.buildDir}/report/jacoco/html")
csv.required = false
xml.required = true
xml.outputLocation.set(file("${rootProject.buildDir}/report/jacoco/jacocoTestReport.xml"))
html.required = true
html.outputLocation.set(file("${rootProject.buildDir}/report/jacoco/html"))
}

jacocoClasspath = configurations.jacocoAnt
Expand Down
8 changes: 8 additions & 0 deletions gradle/scripts/lib/java-rpc-proto.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ configure(projectsWithFlags('java')) {
// declaring an explicit or implicit dependency.
sourcesJarTask.dependsOn(task)
}

def copyAlpnAgentTask= tasks.findByName('copyAlpnAgent')
if (copyAlpnAgentTask) {
// A workaround for ':generateProto' uses this output of task ':copyAlpnAgent' without
// declaring an explicit or implicit dependency.
task.dependsOn(copyAlpnAgentTask)
}

project.ext.getGenerateSourcesTask().dependsOn(task)
}
}
Expand Down
7 changes: 7 additions & 0 deletions gradle/scripts/lib/java-rpc-thrift.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ configure(projectsWithFlags('java')) {
compileTask.dependsOn(task)
}

def copyAlpnAgentTask= tasks.findByName('copyAlpnAgent')
if (copyAlpnAgentTask) {
// A workaround for ':generateProto' uses this output of task ':copyAlpnAgent' without
// declaring an explicit or implicit dependency.
task.dependsOn(copyAlpnAgentTask)
}

project.ext.getGenerateSourcesTask().dependsOn(task)
}
}
Expand Down
Loading