Skip to content

Commit 920394c

Browse files
Compile with Java 24 (#3049)
* Compile with Java 24 * Prevent test failures on Windows runners in GitHub build Especially on Windows runners it sometimes happens that the test process is not terminated after completion of the command that is being tested. If the command prints its exit code to the log, that is being used once the test process times out. Commands which are fully handled by Clikt, do not print the exit code to the log, which results in a test failure if the test process expires. So, for Clikt commands the assertions on the exit code are ignored, if the test process has timed out. --------- Co-authored-by: Mateusz Kwieciński <mateusz.kwiatek@gmail.com>
1 parent 3fe5896 commit 920394c

8 files changed

Lines changed: 89 additions & 29 deletions

File tree

.github/actions/setup-gradle-build/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ runs:
2222
distribution: 'zulu'
2323
java-version: | # last version (set as default) should match all `jvmToolchain(xxx)` calls in the project
2424
${{ inputs.additional-java-versions }}
25-
21
25+
24
2626
2727
# Please note these settings will override the ones set via `gradle.properties` committed to the repository - https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
2828
# List of optimizations:

.github/workflows/generate-changelog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/setup-java@v4
1515
with:
1616
distribution: 'zulu'
17-
java-version: 21
17+
java-version: 24
1818

1919
- uses: gradle/actions/setup-gradle@v4
2020

.github/workflows/pull-request-with-code.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ env:
2929

3030
# Note that all "jobs" (build, tests) including "jobs.*.runs-on" should be kept in sync with "pull-request-without-code"
3131
jobs:
32+
smoke-test:
33+
runs-on: [windows-latest]
34+
steps:
35+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
36+
37+
- uses: ./.github/actions/setup-gradle-build
38+
39+
- run: java -version
40+
shell: bash
41+
42+
- run: java -jar ktlint-dev.jar --help
43+
shell: bash
44+
45+
- run: java --add-opens=java.base/java.lang=ALL-UNNAMED --sun-misc-unsafe-memory-access=allow -jar ktlint-dev.jar --log-level=trace --help
46+
shell: bash
47+
3248
build:
3349
strategy:
3450
matrix:
@@ -83,7 +99,7 @@ jobs:
8399
fail-fast: false
84100
matrix:
85101
os: [ubuntu-latest, windows-latest]
86-
jdk: [8, 11, 17] # list of Java versions to run tests against (excluding `java-compilation` version for which tests already have run during `build` job)
102+
jdk: [8, 11, 17, 21] # list of Java versions to run tests against (excluding `java-compilation` version for which tests already have run during `build` job)
87103
runs-on: ${{ matrix.os }}
88104
name: "[tests] OS=${{ matrix.os }}, Java=${{ matrix.jdk }}"
89105
steps:

build-logic/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
3+
14
plugins {
25
// TODO: Remove if the build is migrated to Gradle 9
36
kotlin("jvm") version libs.versions.kotlin.get() apply false // Enforce higher Kotlin version to make `poko-gradle-plugin` compatible.
@@ -19,6 +22,15 @@ kotlin {
1922
)
2023
}
2124

25+
// Override java target for build-logic, to the latest version. Kotlin version forced by kotlin-dsl doesn't yet support targeting Java 24
26+
val buildLogicJavaTarget = JvmTarget.JVM_22
27+
tasks.withType<KotlinJvmCompile>().configureEach {
28+
compilerOptions.jvmTarget.set(buildLogicJavaTarget)
29+
}
30+
tasks.withType<JavaCompile>().configureEach {
31+
options.release.set(buildLogicJavaTarget.target.toInt())
32+
}
33+
2234
dependencies {
2335
val kotlinPlugin =
2436
if (hasProperty("kotlinDev")) {

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[versions]
22
# The java-compilation version is the latest supported (not necessarily LTS) version of Java. It should be identical to Java-version used in `actions/setup-java`
3-
java-compilation = "21"
3+
java-compilation = "24"
44
# The java-target version is the lowest supported LTS version of Java. Jar's produced are bytecode compatible with this version.
55
java-target = "8"
66
kotlin = "2.2.0"

ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/CommandLineTestRunner.kt

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ package com.pinterest.ktlint.cli
33
import com.pinterest.ktlint.cli.environment.OsEnvironment
44
import com.pinterest.ktlint.logger.api.initKtLintKLogger
55
import io.github.oshai.kotlinlogging.KotlinLogging
6-
import org.assertj.core.api.AbstractAssert
7-
import org.assertj.core.api.AbstractBooleanAssert
8-
import org.assertj.core.api.AbstractIntegerAssert
96
import org.assertj.core.api.Assertions.assertThat
107
import org.assertj.core.api.ListAssert
118
import org.junit.jupiter.api.fail
@@ -39,6 +36,7 @@ class CommandLineTestRunner(
3936
testProjectName: String,
4037
arguments: List<String> = emptyList(),
4138
stdin: InputStream? = null,
39+
expectExitCodeLoggedWhenKtlintIsFinished: Boolean = true,
4240
executionAssertions: ExecutionResult.() -> Unit,
4341
) {
4442
val projectPath = prepareTestProject(testProjectName)
@@ -66,18 +64,20 @@ class CommandLineTestRunner(
6664
val output = process.inputStream.bufferedReader().use { it.readLines() }
6765
val error = process.errorStream.bufferedReader().use { it.readLines() }
6866

69-
if (process.isAlive) {
67+
if (process.isAlive || true) {
7068
// Destroy the process as it is still running
7169
process.destroyForcibly()
7270

73-
// For unknown reasons the process sometimes results in a timeout although the ktlint command is terminated when the last line
74-
// of the output contains the debug line containing the exit code. If this line is found, consider it as a normal termination.
71+
// For an unknown reason, the process sometimes (mostly on Windows) results in a timeout, although the ktlint command is
72+
// terminated. On termination, ktlint prints the exit code on the last line of the output in most cases. Whenever that line is
73+
// expected, and found, then consider this as normal termination. When such a line is not expected, then use a null value as the
74+
// exit code cannot be determined.
7575
val exitCode =
7676
output
7777
.lastOrNull { it.contains(EXIT_KTLINT_WITH_EXIT_CODE_DEBUG_LINE) }
7878
?.substringAfter(EXIT_KTLINT_WITH_EXIT_CODE_DEBUG_LINE)
7979
?.toInt()
80-
if (exitCode != null) {
80+
if (exitCode != null || !expectExitCodeLoggedWhenKtlintIsFinished) {
8181
executionAssertions(ExecutionResult(exitCode, output, error, projectPath))
8282
} else {
8383
// Ktlint is either not terminated or is terminated with a non-zero exit code.
@@ -136,6 +136,7 @@ class CommandLineTestRunner(
136136
private fun ktlintCommand(arguments: List<String>): String =
137137
mutableListOf<String>()
138138
.apply {
139+
println("Java version is=${System.getProperty("java.specification.version")}")
139140
if (isWindows()) {
140141
// KtLint is not an executable command on Windows OS
141142
add("java")
@@ -147,6 +148,8 @@ class CommandLineTestRunner(
147148
if (javaVersion >= 24) {
148149
// Suppress warning "sun.misc.Unsafe::objectFieldOffset" on Java24+ (https://github.com/pinterest/ktlint/issues/2973)
149150
add("--sun-misc-unsafe-memory-access=allow")
151+
// Suppress warning "A restricted method in java.lang.System has been called" on Java24+ (https://github.com/pinterest/ktlint/issues/3041)
152+
add("--enable-native-access=ALL-UNNAMED")
150153
}
151154
}
152155
add("-jar")
@@ -228,35 +231,58 @@ class CommandLineTestRunner(
228231
}
229232

230233
data class ExecutionResult(
231-
val exitCode: Int,
234+
val exitCode: Int?,
232235
val normalOutput: List<String>,
233236
val errorOutput: List<String>,
234237
val testProject: Path,
235238
) {
236-
fun assertNormalExitCode(): AbstractIntegerAssert<*> =
237-
assertThat(exitCode)
238-
.withFailMessage(
239-
"Expected process to exit with exitCode 0, but was $exitCode."
240-
.followedByIndentedList(
241-
listOf(
242-
"RESULTS OF STDOUT:".followedByIndentedList(normalOutput, 2),
243-
"RESULTS OF STDERR:".followedByIndentedList(errorOutput, 2),
239+
fun assertNormalExitCode() {
240+
if (exitCode == null) {
241+
LOGGER.warn {
242+
"The exit code could not be determined. This only happens when the process in which ktlint was run, has not been " +
243+
"finished before the timeout expired, although the actual Ktlint command has been completed. Most ktlint " +
244+
"commands do print the exit code on termination, and when found the exit code is extracted from that line. " +
245+
"Of course, this is only possible when the command being tested, results in printing that line. So do not " +
246+
"call this assertion for commands that never print this line."
247+
}
248+
} else {
249+
assertThat(exitCode)
250+
.withFailMessage(
251+
"Expected process to exit with exitCode 0, but was $exitCode."
252+
.followedByIndentedList(
253+
listOf(
254+
"RESULTS OF STDOUT:".followedByIndentedList(normalOutput, 2),
255+
"RESULTS OF STDERR:".followedByIndentedList(errorOutput, 2),
256+
),
244257
),
245-
),
246-
).isEqualTo(0)
258+
).isEqualTo(0)
259+
}
260+
}
247261

248-
fun assertErrorExitCode(): AbstractIntegerAssert<*> =
249-
assertThat(exitCode)
250-
.withFailMessage("Execution was expected to finish with error. However, exitCode is $exitCode")
251-
.isNotEqualTo(0)
262+
fun assertErrorExitCode() {
263+
if (exitCode == null) {
264+
LOGGER.warn {
265+
"The exit code could not be determined. This only happens when the process in which ktlint was run, has not been " +
266+
"finished before the timeout expired, although the actual Ktlint command has been completed. Most ktlint " +
267+
"commands do print the exit code on termination, and when found the exit code is extracted from that line. " +
268+
"Of course, this is only possible when the command being tested, results in printing that line. So do not " +
269+
"call this assertion for commands that never print this line."
270+
}
271+
} else {
272+
assertThat(exitCode)
273+
.withFailMessage("Execution was expected to finish with error. However, exitCode is $exitCode")
274+
.isNotEqualTo(0)
275+
}
276+
}
252277

253-
fun assertErrorOutputIsEmpty(): AbstractBooleanAssert<*> =
278+
fun assertErrorOutputIsEmpty() {
254279
assertThat(errorOutput.isEmpty())
255280
.withFailMessage(
256281
"Expected error output to be empty but was:".followedByIndentedList(errorOutput),
257282
).isTrue
283+
}
258284

259-
fun assertSourceFileWasFormatted(filePathInProject: String): AbstractAssert<*, *> {
285+
fun assertSourceFileWasFormatted(filePathInProject: String) {
260286
val originalCode =
261287
TEST_PROJECTS_PATHS
262288
.resolve(testProject.last())
@@ -269,7 +295,7 @@ class CommandLineTestRunner(
269295
.toFile()
270296
.readText()
271297

272-
return assertThat(formattedCode).isNotEqualTo(originalCode)
298+
assertThat(formattedCode).isNotEqualTo(originalCode)
273299
}
274300
}
275301

ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/SimpleCLITest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class SimpleCLITest {
2020
.run(
2121
"no-code-style-error",
2222
listOf("--help"),
23+
// The clikt command does not print the exit code as last logline.
24+
expectExitCodeLoggedWhenKtlintIsFinished = false,
2325
) {
2426
SoftAssertions()
2527
.apply {
@@ -47,6 +49,7 @@ class SimpleCLITest {
4749
.run(
4850
"no-code-style-error",
4951
listOf(version),
52+
expectExitCodeLoggedWhenKtlintIsFinished = false,
5053
) {
5154
SoftAssertions()
5255
.apply {
@@ -355,6 +358,7 @@ class SimpleCLITest {
355358
.run(
356359
"too-many-empty-lines",
357360
listOf("generateEditorConfig", "--code-style ktlint_official"),
361+
expectExitCodeLoggedWhenKtlintIsFinished = false,
358362
) {
359363
SoftAssertions()
360364
.apply {
@@ -373,6 +377,7 @@ class SimpleCLITest {
373377
.run(
374378
"too-many-empty-lines",
375379
listOf("generateEditorConfig"),
380+
expectExitCodeLoggedWhenKtlintIsFinished = false,
376381
) {
377382
SoftAssertions()
378383
.apply {
@@ -508,6 +513,7 @@ class SimpleCLITest {
508513
.run(
509514
testProjectName = "too-many-empty-lines",
510515
arguments = listOf("--code-style=android_studio"),
516+
expectExitCodeLoggedWhenKtlintIsFinished = false,
511517
) {
512518
assertThat(errorOutput).containsLineMatching(
513519
"Parameter '--code-style' is no longer valid. The code style should be defined as '.editorconfig' property " +

ktlint-dev.jar

67 MB
Binary file not shown.

0 commit comments

Comments
 (0)