diff --git a/.editorconfig b/.editorconfig index 01626914c0..ffa28b6ae7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -37,3 +37,6 @@ max_line_length = unset [gradle/verification-metadata.xml] indent_size = 3 + +[*.yml] +ij_yaml_spaces_within_brackets = false diff --git a/.github/actions/setup-gradle-build/action.yml b/.github/actions/setup-gradle-build/action.yml new file mode 100644 index 0000000000..6febb231c7 --- /dev/null +++ b/.github/actions/setup-gradle-build/action.yml @@ -0,0 +1,40 @@ +name: Setup Gradle +description: Sets up the environment to run Gradle + +inputs: + gradle-jvm-args: + description: "JVM args to pass to Gradle" + required: true + # Github-Hosted nodes have only 7GB of RAM available. Looking at build scans Gradle process requires slightly more than 0.5GB. + # Keeping this setting low, allows other, forked JVM processes (like tests) to use remaining memory. + # Increase this value, only if GC time visible in build scans will take more than a few seconds. + default: "-Xmx1g" + additional-java-versions: + description: "Java versions installed on the side of the default Java version required by the build" + required: false + +runs: + using: composite + + steps: + - uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: | # last version (set as default) should match all `jvmToolchain(xxx)` calls in the project + ${{ inputs.additional-java-versions }} + 20 + + # 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 + # List of optimizations: + # - `jvm-args` fine-tuned to the CI runner & tasks being invoked + # - disabled File System Watching to improve Windows build times. CI runs don't modify source files, hence they don't need to pay extra cost to efficiently track changed files. + - name: Optimize Gradle build properties for CI + run: | + mkdir -p ~/.gradle + printf "org.gradle.jvmargs=${{ inputs.gradle-jvm-args }}\n" >> ~/.gradle/gradle.properties + printf "org.gradle.vfs.watch=false\n" >> ~/.gradle/gradle.properties + shell: bash + + - uses: gradle/gradle-build-action@v2 + with: + gradle-home-cache-cleanup: true diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 9b0767d294..2b7cca24a3 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -1,6 +1,6 @@ name: "Validate Gradle Wrapper" -on: [ push, pull_request ] +on: [push, pull_request] jobs: validation: diff --git a/.github/workflows/publish-release-build.yml b/.github/workflows/publish-release-build.yml index 7ecfb50de2..82c6ac2bab 100644 --- a/.github/workflows/publish-release-build.yml +++ b/.github/workflows/publish-release-build.yml @@ -1,8 +1,8 @@ name: Publish release build -on : - push : - tags : +on: + push: + tags: - '*.*.*' jobs: @@ -14,26 +14,23 @@ jobs: - uses: actions/checkout@v3 with: ref: 'master' - - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: 19 - - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true + + + - uses: ./.github/actions/setup-gradle-build + - name: Build executable and publish to Maven run: ./gradlew clean shadowJarExecutable publishMavenPublicationToMavenCentralRepository --no-daemon --no-parallel --no-configuration-cache env: SONATYPE_NEXUS_USERNAME: ${{ secrets.SONATYPE_NEXUS_USERNAME }} SONATYPE_NEXUS_PASSWORD: ${{ secrets.SONATYPE_NEXUS_PASSWORD }} - ORG_GRADLE_PROJECT_signingKey : ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEYID }} - ORG_GRADLE_PROJECT_signingKeyPassword : ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} + ORG_GRADLE_PROJECT_signingKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} - - name : Extract release notes - id : release_notes + - name: Extract release notes + id: release_notes if: ${{ success() }} - uses : ffurrer2/extract-release-notes@v1 + uses: ffurrer2/extract-release-notes@v1 - name: Get version id: get_version @@ -49,18 +46,18 @@ jobs: cp ktlint ktlint-${{ env.version }}/bin zip -rm ktlint-${{ env.version }}.zip ktlint-${{ env.version }} - - name : Create release + - name: Create release id: github_release if: ${{ success() }} - uses : softprops/action-gh-release@v1 - with : + uses: softprops/action-gh-release@v1 + with: draft: false prerelease: false - body : ${{ steps.release_notes.outputs.release_notes }} + body: ${{ steps.release_notes.outputs.release_notes }} files: | ktlint-cli/build/run/* - env : - GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Bump Homebrew Formula if: ${{ success() }} diff --git a/.github/workflows/publish-snapshot-build.yml b/.github/workflows/publish-snapshot-build.yml index 59c9add0d3..6c6cb80ae2 100644 --- a/.github/workflows/publish-snapshot-build.yml +++ b/.github/workflows/publish-snapshot-build.yml @@ -2,7 +2,7 @@ name: Publish snapshot build on: push: - branches: [ master ] + branches: [master] paths: ['**/*.kt', '**/*.kts', '**/*.properties', '**/*.toml'] env: @@ -15,14 +15,11 @@ jobs: if: github.repository == 'pinterest/ktlint' steps: - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: 19 - - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true + + - uses: ./.github/actions/setup-gradle-build + - name: Publish snapshot to Maven run: ./gradlew clean publishMavenPublicationToMavenCentralRepository --no-daemon --no-parallel --no-configuration-cache + - name: Publish Kotlin-dev snapshot to Maven run: ./gradlew -PkotlinDev clean publishMavenPublicationToMavenCentralRepository --no-daemon --no-parallel --no-configuration-cache diff --git a/.github/workflows/pull-request-with-code.yml b/.github/workflows/pull-request-with-code.yml index 9dcc8293de..7a8be89c8d 100644 --- a/.github/workflows/pull-request-with-code.yml +++ b/.github/workflows/pull-request-with-code.yml @@ -17,38 +17,31 @@ on: - '**/*.toml' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + env: - ORG_GRADLE_PROJECT_signingKey : ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEYID }} - ORG_GRADLE_PROJECT_signingKeyPassword : ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} + ORG_GRADLE_PROJECT_signingKeyPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} CLI_TEST_MAX_DURATION_IN_SECONDS: 10 -# Note that "jobs.build.strategy" and "jobs.build.runs-on" should be kept in sync with "pull-request-wth-code" +# Note that all "jobs" (build, tests) including "jobs.*.runs-on" should be kept in sync with "pull-request-without-code" jobs: build: strategy: matrix: - os: [ ubuntu-latest, windows-latest ] - # When changing the list of JDK versions, the build configuration has to be changed by a repository admin. See - # https://github.com/pinterest/ktlint/pull/1787#issuecomment-1409074092 - jdk: [ 8, 11, 17, 19 ] - exclude: # windows with JDK8 are *really* flaky - - os: windows-latest - jdk: 8 + os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} + name: "[build] OS=${{ matrix.os }} Kotlin=stable" steps: - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: ${{ matrix.jdk }} - - uses: gradle/gradle-build-action@v2 - with: - gradle-home-cache-cleanup: true + + - uses: ./.github/actions/setup-gradle-build + - name: Build with release Kotlin version - run: ./gradlew build ktlintCheck --no-configuration-cache - - name: Build with dev Kotlin version - run: ./gradlew -PkotlinDev build ktlintCheck --no-configuration-cache + run: ./gradlew ktlintCheck build - name: Check `data class`es are not part of public API run: | @@ -70,3 +63,34 @@ jobs: exit 1 fi shell: bash + + build-dev: + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + name: "[build] OS=${{ matrix.os }}, Kotlin=dev" + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup-gradle-build + + - name: Build with assemble Kotlin version + run: ./gradlew -PkotlinDev ktlintCheck build + + tests: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + 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) + runs-on: ${{ matrix.os }} + name: "[tests] OS=${{ matrix.os }}, Java=${{ matrix.jdk }}" + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup-gradle-build + with: + additional-java-versions: ${{ matrix.jdk }} + + - run: ./gradlew testOnJdk${{ matrix.jdk }} -PtestJdkVersion=${{ matrix.jdk }} diff --git a/.github/workflows/pull-request-without-code.yml b/.github/workflows/pull-request-without-code.yml index adb7caa688..926c463373 100644 --- a/.github/workflows/pull-request-without-code.yml +++ b/.github/workflows/pull-request-without-code.yml @@ -19,18 +19,32 @@ on: - '!**/*.toml' # Add a dummy job that return true so that a PR not containing any code can be merged to master -# Note that "jobs.build.strategy" and "jobs.build.runs-on" should be kept in sync with "pull-request-wth-code" +# Note that all "jobs" (build, tests) including "jobs.*.runs-on" should be kept in sync with "pull-request-with-code" jobs: build: strategy: matrix: - os: [ ubuntu-latest, windows-latest ] - # When changing the list of JDK versions, the build configuration has to be changed by a repository admin. See - # https://github.com/pinterest/ktlint/pull/1787#issuecomment-1409074092 - jdk: [ 8, 11, 17, 19 ] - exclude: # windows with JDK8 are *really* flaky - - os: windows-latest - jdk: 8 + os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} + name: "[build] OS=${{ matrix.os }} Kotlin=stable" + steps: + - run: 'echo "No build required"' + + build-dev: + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + name: "[build] OS=${{ matrix.os }}, Kotlin=dev" + steps: + - run: 'echo "No build required"' + + tests: + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + jdk: [ 8, 11, 17 ] + runs-on: ${{ matrix.os }} + name: "[tests] OS=${{ matrix.os }}, Java=${{ matrix.jdk }}" steps: - run: 'echo "No build required"' diff --git a/CHANGELOG.md b/CHANGELOG.md index b6948386f4..ee2868f0ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Update dependency com.google.jimfs:jimfs to v1.3.0 ([#2112](https://github.com/pinterest/ktlint/pull/2112)) * As a part of public API stabilization, configure `binary-compatibility-validator` plugin for compile-time verification of binary compatibility with previous `ktlint` versions ([#2131](https://github.com/pinterest/ktlint/pull/2131)) * Update dependency org.junit.jupiter:junit-jupiter to v5.10.0 ([#2148](https://github.com/pinterest/ktlint/pull/2148)) +* Build the project with Java 20, run test on Java 8, 11, 17 and 20 ([#1888](https://github.com/pinterest/ktlint/issues/1888)) ## [0.50.0] - 2023-06-29 diff --git a/README.md b/README.md index 9e494db6fc..dcc23c2d6c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

Join the chat at https://kotlinlang.slack.com -Build status +Build status Maven Central JitPack HomeBrew diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index bffd7b7aff..f35ccc42ef 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -1,3 +1,6 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { `kotlin-dsl` } @@ -6,14 +9,30 @@ repositories { mavenCentral() } +kotlin { + jvmToolchain(libs.versions.java.compilation.get().toInt()) +} + +// TODO: Remove setting `options.release` and `compilerOptions.jvmTarget` after upgrade to Kotlin Gradle Plugin 1.9 +// build-logic is an internal project and given we know how the "actual" project is built - it's fine to target current java here as well. +// @see https://github.com/pinterest/ktlint/pull/2120#discussion_r1260229055 for more details +val buildLogicTargetJavaVersion = JavaVersion.VERSION_17 +tasks.withType().configureEach { + options.release.set(buildLogicTargetJavaVersion.majorVersion.toInt()) +} +tasks.withType().configureEach { + // Convert Java version (e.g. "1.8" or "11") to Kotlin JvmTarget ("8" resp. "11") + compilerOptions.jvmTarget.set(JvmTarget.fromTarget(buildLogicTargetJavaVersion.toString())) +} + dependencies { val kotlinPlugin = - if (providers.gradleProperty("kotlinDev").orNull.toBoolean()) { + if (hasProperty("kotlinDev")) { // Pass '-PkotlinDev' to command line to enable kotlin-in-development version logger.warn("Enabling kotlin dev version!") libs.kotlin.plugin.dev } else { - libs.kotlin.plugin + libs.kotlin.plugin.asProvider() } implementation(kotlinPlugin) implementation(libs.dokka) diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts index b5a0fabf66..7c6780a926 100644 --- a/build-logic/settings.gradle.kts +++ b/build-logic/settings.gradle.kts @@ -5,3 +5,7 @@ dependencyResolutionManagement { } } } + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0" +} diff --git a/build-logic/src/main/kotlin/ktlint-kotlin-common.gradle.kts b/build-logic/src/main/kotlin/ktlint-kotlin-common.gradle.kts index 8a6f779a01..c573dd0000 100644 --- a/build-logic/src/main/kotlin/ktlint-kotlin-common.gradle.kts +++ b/build-logic/src/main/kotlin/ktlint-kotlin-common.gradle.kts @@ -6,22 +6,38 @@ plugins { id("dev.drewhamilton.poko") } +val projectLibs = extensions.getByType().named("libs") +val javaCompilationVersion = JavaLanguageVersion.of(projectLibs.findVersion("java-compilation").get().requiredVersion) +val javaTargetVersion = JavaLanguageVersion.of(projectLibs.findVersion("java-target").get().requiredVersion) + kotlin { // All modules, the CLI included, must have an explicit API explicitApi() + jvmToolchain(jdkVersion = javaCompilationVersion.asInt()) } +tasks.withType().configureEach { + options.release.set(javaTargetVersion.asInt()) +} tasks.withType().configureEach { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) - } + // Convert Java version (e.g. "1.8" or "11") to Kotlin JvmTarget ("8" resp. "11") + compilerOptions.jvmTarget.set(JvmTarget.fromTarget(JavaVersion.toVersion(javaTargetVersion).toString())) } -// compileJava task and compileKotlin task jvm target compatibility should be set to the same Java version. -// For some reason, we fallback from toolchain using, see https://github.com/pinterest/ktlint/pull/1787 -tasks.withType().configureEach { - sourceCompatibility = JavaVersion.VERSION_1_8.toString() - targetCompatibility = JavaVersion.VERSION_1_8.toString() +val requestedJdkVersion = project.findProperty("testJdkVersion")?.toString()?.toInt() +// List all non-current Java versions the developers may want to run via IDE click +setOfNotNull(8, 11, 17, requestedJdkVersion).forEach { version -> + tasks.register("testOnJdk$version") { + javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(version) } + + description = "Runs the test suite on JDK $version" + group = LifecycleBasePlugin.VERIFICATION_GROUP + + // Copy inputs from normal Test task. + val testTask = tasks.test.get() + classpath = testTask.classpath + testClassesDirs = testTask.testClassesDirs + } } val skipTests: String = providers.systemProperty("skipTests").getOrElse("false") @@ -40,8 +56,8 @@ tasks.withType().configureEach { (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 } - if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) { - // https://docs.gradle.org/7.5/userguide/upgrading_version_7.html#removes_implicit_add_opens_for_test_workers + if (javaLauncher.get().metadata.languageVersion.canCompileOrRun(JavaLanguageVersion.of(11))) { + // workaround for https://github.com/pinterest/ktlint/issues/1618. Java 11 started printing warning logs. Java 16 throws an error jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") } } diff --git a/build-logic/src/main/kotlin/ktlint-publication.gradle.kts b/build-logic/src/main/kotlin/ktlint-publication.gradle.kts index be2dd30536..2c472d4e02 100644 --- a/build-logic/src/main/kotlin/ktlint-publication.gradle.kts +++ b/build-logic/src/main/kotlin/ktlint-publication.gradle.kts @@ -7,13 +7,14 @@ plugins { signing } -if (providers.gradleProperty("isKotlinDev").orNull.toBoolean()) { - val definedVersion = ext["VERSION_NAME"].toString().removeSuffix("-SNAPSHOT") - ext["VERSION_NAME"] = "$definedVersion-kotlin-dev-SNAPSHOT" -} +val definedVersion: String = providers.gradleProperty("VERSION_NAME").get() -project.version = providers.gradleProperty("VERSION_NAME").orNull - ?: throw GradleException("Project version property is missing") +project.version = + if (hasProperty("kotlinDev")) { + "${definedVersion.removeSuffix("-SNAPSHOT")}-kotlin-dev-SNAPSHOT" + } else { + definedVersion + } // TODO: Remove `localGradleProperty` once https://github.com/gradle/gradle/issues/23572 or https://github.com/pinterest/ktlint/issues/1931 is fixed. project.group = localGradleProperty("GROUP").orNull ?: providers.gradleProperty("GROUP").orNull ?: throw GradleException("Project group property is missing") diff --git a/build.gradle.kts b/build.gradle.kts index d78715fbaf..268016650f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,4 @@ -import java.net.URL +import java.net.URI plugins { alias(libs.plugins.kotlin.jvm) apply false @@ -57,6 +57,6 @@ tasks.register("ktlintFormat") { tasks.wrapper { distributionSha256Sum = - URL("$distributionUrl.sha256") + URI.create("$distributionUrl.sha256").toURL() .openStream().use { it.reader().readText().trim() } } diff --git a/gradle.properties b/gradle.properties index 294cddc1dc..68c44f89f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ POM_LICENSE_DIST=repo POM_DEVELOPER_ID=pinterest POM_DEVELOPER_NAME=Pinterest, Inc. -# Gradle properties +# Default Gradle properties, can be overriden by other locations https://docs.gradle.org/8.2.1/userguide/build_environment.html#sec:gradle_configuration_properties org.gradle.jvmargs=-Xmx4g org.gradle.parallel=true org.gradle.caching=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 776a77520a..76118cc73f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,10 @@ [versions] +# 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` +java-compilation = "20" +# The java-target version is the lowest supported LTS version of Java. Jar's produced are bytecode compatible with this version. +java-target = "8" kotlin = "1.8.22" -kotlinDev = "1.8.22" +kotlinDev = "1.9.0" [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/settings.gradle.kts b/settings.gradle.kts index da9c7fa7b4..9e2c80933f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,6 +8,7 @@ pluginManagement { } dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() } @@ -15,13 +16,16 @@ dependencyResolutionManagement { plugins { `gradle-enterprise` + id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0" } gradleEnterprise { buildScan { termsOfServiceUrl = "https://gradle.com/terms-of-service" termsOfServiceAgree = "yes" - publishAlways() + if (System.getenv("CI") != null) { + publishAlways() + } } }