diff --git a/.github/actions/.bats/bats b/.github/actions/.bats/bats new file mode 160000 index 00000000..902578da --- /dev/null +++ b/.github/actions/.bats/bats @@ -0,0 +1 @@ +Subproject commit 902578da790fbcb035747d2964747f192f6e1603 diff --git a/.github/actions/.bats/test_helper/bats-assert b/.github/actions/.bats/test_helper/bats-assert new file mode 160000 index 00000000..e2d855bc --- /dev/null +++ b/.github/actions/.bats/test_helper/bats-assert @@ -0,0 +1 @@ +Subproject commit e2d855bc78619ee15b0c702b5c30fb074101159f diff --git a/.github/actions/.bats/test_helper/bats-support b/.github/actions/.bats/test_helper/bats-support new file mode 160000 index 00000000..9bf10e87 --- /dev/null +++ b/.github/actions/.bats/test_helper/bats-support @@ -0,0 +1 @@ +Subproject commit 9bf10e876dd6b624fe44423f0b35e064225f7556 diff --git a/.github/actions/create-github-release/action.yml b/.github/actions/create-github-release/action.yml new file mode 100644 index 00000000..1d72cd3a --- /dev/null +++ b/.github/actions/create-github-release/action.yml @@ -0,0 +1,21 @@ +name: Create GitHub Release +description: Create the release on GitHub with a changelog +inputs: + milestone: + required: true + token: + required: true +runs: + using: composite + steps: + - name: Generate Changelog + uses: spring-io/github-changelog-generator@v0.0.10 + with: + milestone: ${{ inputs.milestone }} + token: ${{ inputs.token }} + config-file: .github/actions/create-github-release/changelog-generator.yml + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md diff --git a/.github/actions/create-github-release/changelog-generator.yml b/.github/actions/create-github-release/changelog-generator.yml new file mode 100644 index 00000000..2ce74a09 --- /dev/null +++ b/.github/actions/create-github-release/changelog-generator.yml @@ -0,0 +1,2 @@ +changelog: + repository: spring-io/spring-javaformat diff --git a/.github/actions/deduce-versions/action.yml b/.github/actions/deduce-versions/action.yml new file mode 100644 index 00000000..b8e197c4 --- /dev/null +++ b/.github/actions/deduce-versions/action.yml @@ -0,0 +1,22 @@ +name: 'Deduce Versions' +description: 'Deduce the version to stage and the next SNAPSHOT version' +inputs: + current-version: + required: true + release-type: + required: true +outputs: + release-version: + value: ${{ steps.deduce-versions.outputs.release-version }} + next-version: + value: ${{ steps.deduce-versions.outputs.next-version }} +runs: + using: composite + steps: + - name: Deduce Versions + id: deduce-versions + shell: bash + run: . ${{ github.action_path }}/deduce-versions.sh; deduce_versions + env: + CURRENT_VERSION: "${{ inputs.current-version }}" + RELEASE_TYPE: "${{ inputs.release-type }}" diff --git a/.github/actions/deduce-versions/deduce-versions.sh b/.github/actions/deduce-versions/deduce-versions.sh new file mode 100755 index 00000000..6a3d14e0 --- /dev/null +++ b/.github/actions/deduce-versions/deduce-versions.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +# Get the next milestone release for the given number by inspecting current tags +get_next_milestone_release() { + [[ -n $1 ]] || { echo "missing get_next_milestone_release() version argument" >&2; return 1; } + get_next_tag_based_release "$1" "M" +} + +# Get the next RC release for the given number by inspecting current tags +get_next_rc_release() { + [[ -n $1 ]] || { echo "missing get_next_rc_release() version argument" >&2; return 1; } + get_next_tag_based_release "$1" "RC" +} + +# Get the next release for the given number +get_next_release() { + [[ -n $1 ]] || { echo "missing get_next_release() version argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + local join="." + else + local join="-" + fi + local version + local result + version=$( strip_snapshot_suffix "$1" ) + if [[ -n $2 ]]; then + result="${version}${join}${2}" + else + result="${version}" + fi + echo $result +} + +# Get the next milestone or RC release for the given number by inspecting current tags +get_next_tag_based_release() { + [[ -n $1 ]] || { echo "missing get_next_tag_based_release() version argument" >&2; return 1; } + [[ -n $2 ]] || { echo "missing get_next_tag_based_release() tag type argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + local join="." + else + local join="-" + fi + local version + local last + version=$( strip_snapshot_suffix "$1" ) + git fetch --tags --all > /dev/null + last=$( git tag --list "v${version}${join}${2}*" | sed -E "s/^.*${2}([0-9]+)$/\1/g" | sort -rn | head -n1 ) + if [[ -z $last ]]; then + last="0" + fi + last="${version}${join}${2}${last}" + bump_version_number "$last" +} + +# Remove any "-SNAPSHOT" or ".BUILD-SNAPSHOT" suffix +strip_snapshot_suffix() { + [[ -n $1 ]] || { echo "missing get_relase_version() argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + echo "${BASH_REMATCH[1]}" + elif [[ $1 =~ ^(.*)-SNAPSHOT$ ]]; then + echo "${BASH_REMATCH[1]}" + else + echo "$1" + fi +} + +# Bump version number by incrementing the last numeric, RC or M token +bump_version_number() { + local version=$1 + [[ -n $version ]] || { echo "missing bump_version_number() argument" >&2; return 1; } + if [[ $version =~ ^(.*(\.|-)([A-Za-z]+))([0-9]+)$ ]]; then + local prefix=${BASH_REMATCH[1]} + local suffix=${BASH_REMATCH[4]} + (( suffix++ )) + echo "${prefix}${suffix}" + return 0; + fi + local suffix + if [[ $version =~ ^(.*)(\-SNAPSHOT)$ ]]; then + version=${BASH_REMATCH[1]} + suffix="-SNAPSHOT" + fi + tokens=(${version//\./ }) + local bumpIndex + for i in "${!tokens[@]}"; do + if [[ "${tokens[$i]}" =~ ^[0-9]+$ ]] ; then + bumpIndex=$i + fi + done + [[ -n $bumpIndex ]] || { echo "unsupported version number" >&2; return 1; } + (( tokens[bumpIndex]++ )) + local bumpedVersion + IFS=. eval 'bumpedVersion="${tokens[*]}"' + echo "${bumpedVersion}${suffix}" +} + +# Deduce versions +deduce_versions() { + [[ -n ${GITHUB_OUTPUT} ]] || { echo "missing GITHUB_OUTPUT environment variable" >&2; return 1; } + [[ -n ${CURRENT_VERSION} ]] || { echo "missing CURRENT_VERSION environment variable" >&2; return 1; } + [[ -n ${RELEASE_TYPE} ]] || { echo "missing RELEASE_TYPE environment variable" >&2; return 1; } + if [[ ${RELEASE_TYPE,,} = "milestone" ]]; then + releaseVersion=$( get_next_milestone_release ${CURRENT_VERSION}) + nextVersion=${CURRENT_VERSION} + elif [[ ${RELEASE_TYPE,,} = "release-candidate" ]]; then + releaseVersion=$( get_next_rc_release ${CURRENT_VERSION}) + nextVersion=${CURRENT_VERSION} + elif [[ ${RELEASE_TYPE,,} = "release" ]]; then + releaseVersion=$( get_next_release ${CURRENT_VERSION}) + nextVersion=$( bump_version_number ${CURRENT_VERSION}) + else + echo "Unknown release type '${RELEASE_TYPE}'" >&2; exit 1; + fi + echo "release-version=${releaseVersion}" >> "$GITHUB_OUTPUT" + echo "next-version=${nextVersion}" >> "$GITHUB_OUTPUT" +} diff --git a/.github/actions/deduce-versions/test.sh b/.github/actions/deduce-versions/test.sh new file mode 100755 index 00000000..0a8e4130 --- /dev/null +++ b/.github/actions/deduce-versions/test.sh @@ -0,0 +1 @@ +../.bats/bats/bin/bats test/*.bats \ No newline at end of file diff --git a/.github/actions/deduce-versions/test/bump_version.bats b/.github/actions/deduce-versions/test/bump_version.bats new file mode 100644 index 00000000..5efd9f0b --- /dev/null +++ b/.github/actions/deduce-versions/test/bump_version.bats @@ -0,0 +1,58 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "bump_version_number() should bump '.M'" { + run bump_version_number "1.2.0.M2" + assert_output "1.2.0.M3" +} + +@test "bump_version_number() should bump '.RC'" { + run bump_version_number "1.2.0.RC3" + assert_output "1.2.0.RC4" +} + +@test "bump_version_number() should bump '-M'" { + run bump_version_number "1.2.0-M2" + assert_output "1.2.0-M3" +} + +@test "bump_version_number() should bump '-RC'" { + run bump_version_number "1.2.0-RC3" + assert_output "1.2.0-RC4" +} + +@test "bump_version_number() should bump without suffix" { + run bump_version_number "1.2.0" + assert_output "1.2.1" +} + +@test "bump_version_number() should bump '.RELEASE'" { + run bump_version_number "1.2.0.RELEASE" + assert_output "1.2.1.RELEASE" +} + +@test "bump_version_number() should bump '-SNAPSHOT'" { + run bump_version_number "1.2.0-SNAPSHOT" + assert_output "1.2.1-SNAPSHOT" +} + +@test "bump_version_number() should bump '.BUILD-SNAPSHOT'" { + run bump_version_number "1.2.0.BUILD-SNAPSHOT" + assert_output "1.2.1.BUILD-SNAPSHOT" +} + +@test "bump_version_number() when missing argument should fail" { + run bump_version_number + assert_output "missing bump_version_number() argument" + assert [ "$status" -eq 1 ] +} + +@test "bump_version_number() when bad argument should fail" { + run bump_version_number "foo.bar.baz" + assert_output "unsupported version number" + assert [ "$status" -eq 1 ] +} diff --git a/.github/actions/deduce-versions/test/deduce_versions.bats b/.github/actions/deduce-versions/test/deduce_versions.bats new file mode 100644 index 00000000..2ffbf599 --- /dev/null +++ b/.github/actions/deduce-versions/test/deduce_versions.bats @@ -0,0 +1,96 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +teardown() { + rm .githuboutput | true +} + +@test "deduce_versions() when 'milestone' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="milestone" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3-M2" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ] +} + +@test "deduce_versions() when 'release-candidate' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release-candidate" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3-RC2" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ] +} + +@test "deduce_versions() when 'release' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.4-SNAPSHOT" ] +} + +@test "deduce_versions() when no GITHUB_OUTPUT should fail" { + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing GITHUB_OUTPUT environment variable" +} + +@test "deduce_versions() when no CURRENT_VERSION should fail" { + GITHUB_OUTPUT=".githuboutput" + RELEASE_TYPE="release" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing CURRENT_VERSION environment variable" +} + +@test "deduce_versions() when no RELEASE_TYPE should fail" { + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing RELEASE_TYPE environment variable" +} + +@test "deduce_versions() when wrong RELEASE_TYPE should fail" { + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="nope" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "Unknown release type 'nope'" +} + +mock_git_repo() { + local tmpdir=$(mktemp -d $BATS_TMPDIR/gitrepo.XXXXXX) >&2 + mkdir -p "$tmpdir" >&2 + cd "$tmpdir" >&2 + git init >&2 + echo "foo" > foo.txt + git add foo.txt >&2 + git commit -m'Initial commit' >&2 + for tag in "$@"; do + git tag "$tag" >&2 + done + echo "$tmpdir" +} \ No newline at end of file diff --git a/.github/actions/deduce-versions/test/get_next_release.bats b/.github/actions/deduce-versions/test/get_next_release.bats new file mode 100644 index 00000000..b9be5c0e --- /dev/null +++ b/.github/actions/deduce-versions/test/get_next_release.bats @@ -0,0 +1,119 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "get_next_milestone_release() when has no version should fail" { + run get_next_milestone_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_milestone_release() version argument" +} + +@test "get_next_rc_release() when has no version should fail" { + run get_next_rc_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_rc_release() version argument" +} + +@test "get_next_tag_based_release() when has no version should fail" { + run get_next_tag_based_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_tag_based_release() version argument" +} + +@test "get_next_tag_based_release() when has no tag type should fail" { + run get_next_tag_based_release "1.2.3" + assert [ "$status" -eq 1 ] + assert_output "missing get_next_tag_based_release() tag type argument" +} + +@test "get_next_milestone_release() when has no tag should return M1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_milestone_release "1.2.3-SNAPSHOT" + assert_output "1.2.3-M1" +} + +@test "get_next_rc_release() when has no tag should return RC1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_rc_release "1.2.3-SNAPSHOT" + assert_output "1.2.3-RC1" +} + +@test "get_next_tag_based_release() when has no tag and dash SNAPSHOT suffix should return dashed X1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_tag_based_release "1.2.3-SNAPSHOT" "X" + assert_output "1.2.3-X1" +} + +@test "get_next_tag_based_release() when has no tag and dash BUILD-SNAPSHOT suffix should return dashed X1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_tag_based_release "1.2.3.BUILD-SNAPSHOT" "X" + assert_output "1.2.3.X1" +} + +@test "get_next_tag_based_release() when has tags and dashed should return dashed X tag+1" { + repo=$( mock_git_repo "v1.2.3-X1" "v1.2.3-X3" "v1.2.3-X2" ) + cd "$repo" + run get_next_tag_based_release "1.2.3-SNAPSHOT" "X" + assert_output "1.2.3-X4" +} + +@test "get_next_tag_based_release() when has tags and dashed should return dot X tag+1" { + repo=$( mock_git_repo "v1.2.3.X1" "v1.2.3.X3" "v1.2.3.X2" ) + cd "$repo" + run get_next_tag_based_release "1.2.3.BUILD-SNAPSHOT" "X" + assert_output "1.2.3.X4" +} + +@test "get_next_tag_based_release() when has multiple tags should return version match tag+1" { + repo=$( mock_git_repo "v1.5.0.A1" "v1.5.0.A2" "v1.5.0.B1" "v2.0.0.A1" "v2.0.0.B1" "v2.0.0.B2" ) + cd "$repo" + run get_next_tag_based_release "1.5.0.BUILD-SNAPSHOT" "A" + assert_output "1.5.0.A3" + run get_next_tag_based_release "1.5.0.BUILD-SNAPSHOT" "B" + assert_output "1.5.0.B2" + run get_next_tag_based_release "2.0.0.BUILD-SNAPSHOT" "A" + assert_output "2.0.0.A2" + run get_next_tag_based_release "2.0.0.BUILD-SNAPSHOT" "B" + assert_output "2.0.0.B3" +} + +@test "get_next_release() should return next release version with release suffix" { + run get_next_release "1.5.0.BUILD-SNAPSHOT" "RELEASE" + assert_output "1.5.0.RELEASE" + run get_next_release "1.5.0-SNAPSHOT" "RELEASE" + assert_output "1.5.0-RELEASE" +} + +@test "get_next_release() should return next release version" { + run get_next_release "1.5.0.BUILD-SNAPSHOT" + assert_output "1.5.0" + run get_next_release "1.5.0-SNAPSHOT" + assert_output "1.5.0" +} + +@test "get_next_release() when has no version should fail" { + run get_next_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_release() version argument" +} + +mock_git_repo() { + local tmpdir=$(mktemp -d $BATS_TMPDIR/gitrepo.XXXXXX) >&2 + mkdir -p "$tmpdir" >&2 + cd "$tmpdir" >&2 + git init >&2 + echo "foo" > foo.txt + git add foo.txt >&2 + git commit -m'Initial commit' >&2 + for tag in "$@"; do + git tag "$tag" >&2 + done + echo "$tmpdir" +} diff --git a/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats b/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats new file mode 100644 index 00000000..bef64867 --- /dev/null +++ b/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats @@ -0,0 +1,21 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "strip_snapshot_suffix() should strip '-SNAPSHOT" { + run strip_snapshot_suffix "1.2.0-SNAPSHOT" + assert_output "1.2.0" +} + +@test "strip_snapshot_suffix() should strip '.BUILD-SNAPSHOT" { + run strip_snapshot_suffix "1.2.0.BUILD-SNAPSHOT" + assert_output "1.2.0" +} + +@test "strip_snapshot_suffix() when no suffix should return unchanged" { + run strip_snapshot_suffix "1.2.0" + assert_output "1.2.0" +} diff --git a/.github/actions/publish-eclipse-update-site/action.yml b/.github/actions/publish-eclipse-update-site/action.yml new file mode 100644 index 00000000..4235c9e8 --- /dev/null +++ b/.github/actions/publish-eclipse-update-site/action.yml @@ -0,0 +1,22 @@ +name: 'Publish Eclipse Update Site ' +inputs: + version: + required: true + build-number: + required: true + artifactory-username: + required: true + artifactory-password: + required: true +runs: + using: composite + steps: + - name: Stage + id: stage + shell: bash + run: . ${{ github.action_path }}/publish-eclipse-update-site.sh; + env: + VERSION: "${{ inputs.version }}" + BUILD_NUMBER: "${{ inputs.build-number }}" + ARTIFACTORY_USERNAME: "${{ inputs.artifactory-username }}" + ARTIFACTORY_PASSWORD: "${{ inputs.artifactory-password }}" diff --git a/ci/scripts/publish-eclipse-update-site-pom-template.xml b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site-pom-template.xml similarity index 100% rename from ci/scripts/publish-eclipse-update-site-pom-template.xml rename to .github/actions/publish-eclipse-update-site/publish-eclipse-update-site-pom-template.xml diff --git a/ci/scripts/publish-eclipse-update-site.sh b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh old mode 100755 new mode 100644 similarity index 59% rename from ci/scripts/publish-eclipse-update-site.sh rename to .github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh index 761f74c3..9ddcee29 --- a/ci/scripts/publish-eclipse-update-site.sh +++ b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh @@ -1,14 +1,11 @@ -#!/bin/bash -set -e +buildInfo=$( jfrog rt curl api/build/spring-javaformat-${VERSION}/${BUILD_NUMBER} ) +groupId=$( echo ${buildInfo} | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) +version=$( echo ${buildInfo} | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) -source $(dirname $0)/common.sh +echo "Publishing ${buildName}/${buildNumber} (${groupId}:${version}) to Eclipse Update Site" -buildName=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.name' ) -buildNumber=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.number' ) -groupId=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) +jfrog rt dl --build spring-javaformat-${VERSION}/${BUILD_NUMBER} '**/io.spring.javaformat.eclipse.site*.zip' -echo "Publishing ${buildName}/${buildNumber} to Eclipse Update Site" curl \ -s \ --connect-timeout 240 \ @@ -17,7 +14,7 @@ curl \ -f \ -H "X-Explode-Archive: true" \ -X PUT \ - -T "artifactory-repo/io/spring/javaformat/io.spring.javaformat.eclipse.site/${version}/io.spring.javaformat.eclipse.site-${version}.zip" \ + -T "io/spring/javaformat/io.spring.javaformat.eclipse.site/${version}/io.spring.javaformat.eclipse.site-${version}.zip" \ "https://repo.spring.io/javaformat-eclipse-update-site/${version}/" > /dev/null || { echo "Failed to publish" >&2; exit 1; } releasedVersions=$( curl -s -f -X GET https://repo.spring.io/api/storage/javaformat-eclipse-update-site | jq -r '.children[] | .uri' | cut -c 2- | grep '[0-9].*' | sort -V ) @@ -28,9 +25,8 @@ while read -r releasedVersion; do repositories="${repositories}https://repo.spring.io/javaformat-eclipse-update-site/${releasedVersion}p2" done <<< "${releasedVersions}" -pushd git-repo > /dev/null -sed "s|##repositories##|${repositories}|" ci/scripts/publish-eclipse-update-site-pom-template.xml > publish-eclipse-update-site-pom.xml -run_maven -f publish-eclipse-update-site-pom.xml clean package || { echo "Failed to publish" >&2; exit 1; } +sed "s|##repositories##|${repositories}|" ${GITHUB_ACTION_PATH}/publish-eclipse-update-site-pom-template.xml > publish-eclipse-update-site-pom.xml +./mvnw -f publish-eclipse-update-site-pom.xml clean package || { echo "Failed to publish" >&2; exit 1; } curl \ -s \ @@ -52,6 +48,4 @@ curl \ -T "target/repository/artifacts.jar" \ "https://repo.spring.io/javaformat-eclipse-update-site/" > /dev/null || { echo "Failed to publish" >&2; exit 1; } -popd > /dev/null - echo "Publish complete" diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..c1d38d98 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,16 @@ +name: 'Setup' +runs: + using: composite + steps: + - name: Set Up Utilities + shell: bash + run: sudo apt-get update && sudo apt-get -y install libxml2-utils + - name: Set Up Java + uses: actions/setup-java@v4 + with: + distribution: 'liberica' + java-version: '17' + cache: maven + - name: Disable Java Problem Matcher + shell: bash + run: echo "::remove-matcher owner=java::" diff --git a/.github/actions/stage-code/action.yml b/.github/actions/stage-code/action.yml new file mode 100644 index 00000000..1fc1f060 --- /dev/null +++ b/.github/actions/stage-code/action.yml @@ -0,0 +1,22 @@ +name: 'Stage ' +inputs: + current-version: + required: true + release-version: + required: true + next-version: + required: true +outputs: + distribution-repository: + value: ${{ steps.stage.outputs.distribution-repository }} +runs: + using: composite + steps: + - name: Stage + id: stage + shell: bash + run: . ${{ github.action_path }}/stage.sh; + env: + CURRENT_VERSION: "${{ inputs.current-version }}" + RELEASE_VERSION: "${{ inputs.release-version }}" + NEXT_VERSION: "${{ inputs.next-version }}" diff --git a/.github/actions/stage-code/stage.sh b/.github/actions/stage-code/stage.sh new file mode 100644 index 00000000..6ac9c2f0 --- /dev/null +++ b/.github/actions/stage-code/stage.sh @@ -0,0 +1,32 @@ +repository=${GITHUB_WORKSPACE}/distribution-repository + +echo "Staging ${RELEASE_VERSION} to ${repository} (next version will be ${NEXT_VERSION})" + +./mvnw versions:set --batch-mode --no-transfer-progress -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false +./mvnw org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata --batch-mode --no-transfer-progress +./mvnw --projects io.spring.javaformat:spring-javaformat-vscode-extension --batch-mode --no-transfer-progress -P '!formatter-dependencies' antrun:run@update-version frontend:install-node-and-npm frontend:npm@update-package-lock + +git config user.name "Spring Builds" > /dev/null +git config user.email "spring-builds@users.noreply.github.com" > /dev/null +git add pom.xml > /dev/null +git commit -m"Release v${RELEASE_VERSION}" > /dev/null +git tag -a "v${RELEASE_VERSION}" -m"Release v${RELEASE_VERSION}" > /dev/null + +./mvnw clean deploy --batch-mode --no-transfer-progress -U -Dfull -DaltDeploymentRepository=distribution::file://${repository} + +git reset --hard HEAD^ > /dev/null +if [[ ${NEXT_VERSION} != ${CURRENT_VERSION} ]]; then + echo "Setting next development version (v${NEXT_VERSION})" + ./mvnw versions:set --batch-mode --no-transfer-progress -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false + ./mvnw org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata --batch-mode --no-transfer-progress + ./mvnw --projects io.spring.javaformat:spring-javaformat-vscode-extension --batch-mode --no-transfer-progress -P '!formatter-dependencies' antrun:run@update-version frontend:npm@update-package-lock + sed -i "s/:release-version:.*/:release-version: ${RELEASE_VERSION}/g" README.adoc + sed -i "s/spring-javaformat-gradle-plugin:.*/spring-javaformat-gradle-plugin:${NEXT_VERSION}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle + sed -i "s/spring-javaformat-checkstyle:.*/spring-javaformat-checkstyle:${NEXT_VERSION}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle + sed -i "s|.*|${NEXT_VERSION}|" samples/spring-javaformat-maven-sample/pom.xml + git add -u . > /dev/null + git commit -m"Next development version (v${NEXT_VERSION})" > /dev/null +fi; + +echo "Staged the following files:" +find ${repository} diff --git a/.github/artifacts.spec b/.github/artifacts.spec new file mode 100644 index 00000000..0f6c3aac --- /dev/null +++ b/.github/artifacts.spec @@ -0,0 +1,23 @@ +{ + "files": [ + { + "aql": { + "items.find": { + "$and": [ + { + "@build.name": "${buildName}", + "@build.number": "${buildNumber}", + "name": { + "$nmatch": "*.zip" + }, + "name": { + "$nmatch": "*.zip.asc" + } + } + ] + } + }, + "target": "nexus/" + } + ] +} diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 00000000..0c4b142e --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,2 @@ +require: + members: false diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml new file mode 100644 index 00000000..d269a903 --- /dev/null +++ b/.github/workflows/build-and-deploy-snapshot.yml @@ -0,0 +1,30 @@ +name: Build and Deploy Snapshot +on: + push: + branches: + - main +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} +jobs: + build-and-deploy-snapshot: + name: Build and Deploy Snapshot + runs-on: ubuntu-latest + if: ${{ github.repository == 'spring-io/spring-javaformat' }} + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Build + run: ./mvnw clean deploy --batch-mode --no-transfer-progress --update-snapshots -DaltDeploymentRepository=distribution::file://$(pwd)/distribution-repository + - name: Deploy + uses: spring-io/artifactory-deploy-action@v0.0.1 + with: + folder: 'distribution-repository' + uri: 'https://repo.spring.io' + repository: 'libs-snapshot-local' + build-name: spring-javaformat + username: ${{ secrets.ARTIFACTORY_USERNAME }} + password: ${{ secrets.ARTIFACTORY_PASSWORD }} + signing-key: ${{ secrets.GPG_PRIVATE_KEY }} + signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml new file mode 100644 index 00000000..9e085b69 --- /dev/null +++ b/.github/workflows/build-pull-request.yml @@ -0,0 +1,16 @@ +name: Build Pull Request +on: pull_request +permissions: + contents: read +jobs: + build: + name: Build Pull Request + runs-on: ubuntu-latest + if: ${{ github.repository == 'spring-io/spring-javaformat' }} + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Build + run: ./mvnw clean install --batch-mode --no-transfer-progress --update-snapshots diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml new file mode 100644 index 00000000..e1faac58 --- /dev/null +++ b/.github/workflows/promote.yml @@ -0,0 +1,92 @@ +name: Promote +run-name: >- + Promote of version ${{ inputs.version }} (build number ${{ inputs.build-number}}) by ${{ github.actor }} to '${{ inputs.environment }}' environment' +on: + workflow_call: + inputs: + environment: + type: string + required: true + version: + type: string + required: true + build-number: + type: string + required: true + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true + version: + description: The version number to promote + type: string + required: true + build-number: + description: The build number to promote + type: string + required: true +jobs: + promote: + environment: ${{ inputs.environment }} + name: Promote + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up JFrog CLI + uses: jfrog/setup-jfrog-cli@ff5cb544114ffc152db9cea1cd3d5978d5074946 # v4.5.11 + env: + JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} + - name: Check Maven Central Sync Status + id: check-sync-status + run: | + url=${{ format('https://repo.maven.apache.org/maven2/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + status_code=$( curl --write-out '%{http_code}' --head --silent --output /dev/null ${url} ) + if [ "${status_code}" != 200 ] && [ "${status_code}" != 404 ]; then + echo "Unexpected status code ${status_code}" + exit 1 + fi + echo "status-code=${status_code}" >> $GITHUB_OUTPUT + - name: Download Release Artifacts + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: jf rt download --spec ./.github/artifacts.spec --spec-vars 'buildName=${{ format('spring-javaformat-{0}', inputs.version) }};buildNumber=${{ inputs.build-number }}' + - name: Sync to Maven Central + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + uses: spring-io/nexus-sync-action@v0.0.1 + with: + username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} + password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} + staging-profile-name: ${{ secrets.OSSRH_S01_STAGING_PROFILE }} + create: true + upload: true + close: true + release: true + generate-checksums: true + - name: Await Maven Central Sync + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: | + url=${{ format('https://repo.maven.apache.org/maven2/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + echo "Waiting for $url" + until curl --fail --head --silent $url > /dev/null + do + echo "." + sleep 60 + done + echo "$url is available" + - name: Promote Build + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: jfrog rt build-promote ${{ format('spring-javaformat-{0}', inputs.version)}} ${{ inputs.build-number }} libs-release-local + - name: Publish Eclipse Update Site + uses: ./.github/actions/publish-eclipse-update-site + with: + version: ${{ inputs.version }} + build-number: ${{ inputs.build-number }} + artifactory-username: ${{ secrets.ARTIFACTORY_USERNAME }} + artifactory-password: ${{ secrets.ARTIFACTORY_PASSWORD }} + - name: Create GitHub Release + uses: ./.github/actions/create-github-release + with: + milestone: ${{ inputs.version }} + token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..c80a4091 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release +run-name: >- + Release of '${{ github.ref_name }}' branch to '${{ inputs.environment }}' environment by ${{ github.actor }} +on: + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true +jobs: + stage: + name: Stage + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Get Current Version + id: get-version + run: echo "current-version=$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml)" >> $GITHUB_OUTPUT + - name: Deduce Versions + id: deduce-versions + uses: ./.github/actions/deduce-versions + with: + current-version: ${{ steps.get-version.outputs.current-version }} + release-type: ${{ inputs.environment }} + - name: Stage Code + id: stage-code + uses: ./.github/actions/stage-code + with: + current-version: ${{ steps.get-version.outputs.current-version }} + release-version: ${{ steps.deduce-versions.outputs.release-version }} + next-version: ${{ steps.deduce-versions.outputs.next-version }} + - name: Deploy to Staging + uses: spring-io/artifactory-deploy-action@v0.0.1 + with: + folder: distribution-repository + uri: 'https://repo.spring.io' + repository: 'libs-staging-local' + build-name: ${{ format('spring-javaformat-{0}', steps.deduce-versions.outputs.release-version)}} + username: ${{ secrets.ARTIFACTORY_USERNAME }} + password: ${{ secrets.ARTIFACTORY_PASSWORD }} + signing-key: ${{ secrets.GPG_PRIVATE_KEY }} + signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} + - name: Push + run: git push origin HEAD --tags + outputs: + release-version: ${{ steps.deduce-versions.outputs.release-version }} + release-build-number: ${{ github.run_number }} + promote: + name: Promote + needs: stage + uses: ./.github/workflows/promote.yml + with: + environment: ${{ inputs.environment }} + version: ${{needs.stage.outputs.release-version}} + build-number: ${{ needs.stage.outputs.release-build-number }} diff --git a/.github/workflows/rollback.yml b/.github/workflows/rollback.yml new file mode 100644 index 00000000..43e04a4d --- /dev/null +++ b/.github/workflows/rollback.yml @@ -0,0 +1,41 @@ +name: Rollback +run-name: >- + Rollback of version ${{ inputs.version }} (build number ${{ inputs.build-number}}) by ${{ github.actor }} +on: + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true + version: + description: The version number to roll back + type: string + required: true + build-number: + description: The build number to roll back + type: string + required: true +jobs: + rollback: + environment: ${{ inputs.environment }} + name: Roll Back + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up JFrog CLI + uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.1.2 + env: + JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} + - name: Delete Staged Artifacts + run: | + url=${{ format('libs-staging-local/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + artifact_count=$( jf rt s ${url} --count ) + if [ "${artifact_count}" != 1 ]; then + echo "Unexpected aretifact count ${artifact_count}" + exit 1 + fi + build_name=${{ format('spring-javaformat-{0}', inputs.version)}} + build_number=${{ inputs.build-number }} + jf rt delete --build ${build_name}/${build_number} diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..64d1aa9d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule ".github/actions/.bats/bats"] + path = .github/actions/.bats/bats + url = https://github.com/bats-core/bats-core.git + tag = v1.11.0 +[submodule ".github/actions/.bats/test_helper/bats-support"] + path = .github/actions/.bats/test_helper/bats-support + url = https://github.com/bats-core/bats-support.git + tag = v0.3.0 +[submodule ".github/actions/.bats/test_helper/bats-assert"] + path = .github/actions/.bats/test_helper/bats-assert + url = https://github.com/bats-core/bats-assert.git + tag = v2.1.0 diff --git a/.sdkmanrc b/.sdkmanrc index 14fdc133..83ec5a0a 100644 --- a/.sdkmanrc +++ b/.sdkmanrc @@ -1,3 +1,3 @@ # Enable auto-env through the sdkman_auto_env config # Add key=value pairs of SDKs to use below -java=17.0.6-librca +java=17.0.14-librca diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index a5c92957..a7e07f62 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -12,10 +12,9 @@ Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. -== Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to https://cla.pivotal.io/sign/spring[sign the Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. -Active contributors might be asked to join the core team, and given the ability to merge pull requests. +== Include a Signed-off-by Trailer +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin[Developer Certificate of Origin (DCO)]. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. @@ -29,7 +28,7 @@ should also work without issue. === Building From Source -To build the source you will need to install JDK 11. +To build the source you will need to install JDK 17. @@ -206,9 +205,9 @@ Under `spring-javaformat` the following projects are defined: * `spring-javaformat-formatter-shader` - Shader support classes * `spring-javaformat-formatter-shaded` - A shaded version of the formatter with all dependencies included * `spring-javaformat-formatter-eclipse-jdk8` - The eclipse JDK 8 formatter (repackaged and slightly adapted) -* `spring-javaformat-formatter-eclipse-jdk11` - The eclipse JDK 11 formatter (repackaged and slightly adapted) +* `spring-javaformat-formatter-eclipse-jdk17` - The eclipse JDK 17 formatter (repackaged and slightly adapted) * `spring-javaformat-formatter-eclipse-jdt-jdk8` - The eclipse JDT import for JDK 8 -* `spring-javaformat-formatter-eclipse-jdt-jdk11` - The eclipse JDT import for JDK 8 +* `spring-javaformat-formatter-eclipse-jdt-jdk17` - The eclipse JDT import for JDK 17 * `spring-javaformat-formatter-eclipse-rewriter` - Internal utility used to modify eclipse code * `spring-javaformat-formatter-eclipse-runtime` - Eclipse runtime JAR for use when running outside of Eclipse diff --git a/README.adoc b/README.adoc index ffca7a09..bf0a6e1c 100644 --- a/README.adoc +++ b/README.adoc @@ -1,4 +1,4 @@ -:release-version: 0.0.39 +:release-version: 0.0.46 :checkstyle-version: 9.3 == Spring Java Format @@ -192,7 +192,7 @@ Your `checkstyle.xml` file should look then like this: === Java 8 Support -By default, the formatter requires Java 11. +By default, the formatter requires Java 17. If you are working on an older project, you can use a variation of the formatter based off Eclipse 2021-03 (the latest Eclipse JDT version built with Java 8). To use the Java 8 version, add a file called `.springjavaformatconfig` to the root of your project with the following content: @@ -391,7 +391,7 @@ For example: [source,java,indent=0,subs="normal"] ---- -class Name { +public class Name { private final String first; diff --git a/ci/README.adoc b/ci/README.adoc deleted file mode 100644 index bdf75bd5..00000000 --- a/ci/README.adoc +++ /dev/null @@ -1,18 +0,0 @@ -== Concourse pipeline - -Ensure that you've setup the target and can login - -[source] ----- -$ fly -t spring-javaformat login -n spring-javaformat -c https://ci.spring.io ----- - -The pipeline can be deployed using the following command: - -[source] ----- -$ fly -t spring-javaformat set-pipeline -p spring-javaformat -c ci/pipeline.yml -l ci/parameters.yml ----- - -NOTE: This assumes that you have credhub integration configured with the appropriate -secrets. diff --git a/ci/config/release-scripts.yml b/ci/config/release-scripts.yml deleted file mode 100644 index d31f8cba..00000000 --- a/ci/config/release-scripts.yml +++ /dev/null @@ -1,10 +0,0 @@ -logging: - level: - io.spring.concourse: DEBUG -spring: - main: - banner-mode: off -sonatype: - exclude: - - 'build-info\.json' - - '.*\.zip' diff --git a/ci/images/README.adoc b/ci/images/README.adoc deleted file mode 100644 index 84eae160..00000000 --- a/ci/images/README.adoc +++ /dev/null @@ -1,21 +0,0 @@ -== CI Images - -These images are used by CI to run the actual builds. - -To build the image locally run the following from this directory: - ----- -$ docker build --no-cache -f /Dockerfile . ----- - -For example - ----- -$ docker build --no-cache -f spring-boot-ci-image/Dockerfile . ----- - -To test run: - ----- -$ docker run -it --entrypoint /bin/bash ✈ ----- diff --git a/ci/images/ci-image/Dockerfile b/ci/images/ci-image/Dockerfile deleted file mode 100644 index fbdbb4c0..00000000 --- a/ci/images/ci-image/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM ubuntu:focal-20210401 - -ADD setup.sh /setup.sh -ADD get-docker-url.sh /get-docker-url.sh -RUN ./setup.sh - -ENV JAVA_HOME /opt/openjdk -ENV PATH $JAVA_HOME/bin:$PATH -ADD docker-lib.sh /docker-lib.sh - -ENTRYPOINT [ "switch", "shell=/bin/bash", "--", "codep", "/bin/docker daemon" ] diff --git a/ci/images/docker-lib.sh b/ci/images/docker-lib.sh deleted file mode 100755 index 4c7b1d58..00000000 --- a/ci/images/docker-lib.sh +++ /dev/null @@ -1,112 +0,0 @@ -# Based on: https://github.com/concourse/docker-image-resource/blob/master/assets/common.sh - -DOCKER_LOG_FILE=${DOCKER_LOG_FILE:-/tmp/docker.log} -SKIP_PRIVILEGED=${SKIP_PRIVILEGED:-false} -STARTUP_TIMEOUT=${STARTUP_TIMEOUT:-120} - -sanitize_cgroups() { - mkdir -p /sys/fs/cgroup - mountpoint -q /sys/fs/cgroup || \ - mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup - - mount -o remount,rw /sys/fs/cgroup - - sed -e 1d /proc/cgroups | while read sys hierarchy num enabled; do - if [ "$enabled" != "1" ]; then - # subsystem disabled; skip - continue - fi - - grouping="$(cat /proc/self/cgroup | cut -d: -f2 | grep "\\<$sys\\>")" || true - if [ -z "$grouping" ]; then - # subsystem not mounted anywhere; mount it on its own - grouping="$sys" - fi - - mountpoint="/sys/fs/cgroup/$grouping" - - mkdir -p "$mountpoint" - - # clear out existing mount to make sure new one is read-write - if mountpoint -q "$mountpoint"; then - umount "$mountpoint" - fi - - mount -n -t cgroup -o "$grouping" cgroup "$mountpoint" - - if [ "$grouping" != "$sys" ]; then - if [ -L "/sys/fs/cgroup/$sys" ]; then - rm "/sys/fs/cgroup/$sys" - fi - - ln -s "$mountpoint" "/sys/fs/cgroup/$sys" - fi - done - - if ! test -e /sys/fs/cgroup/systemd ; then - mkdir /sys/fs/cgroup/systemd - mount -t cgroup -o none,name=systemd none /sys/fs/cgroup/systemd - fi -} - -start_docker() { - mkdir -p /var/log - mkdir -p /var/run - - if [ "$SKIP_PRIVILEGED" = "false" ]; then - sanitize_cgroups - - # check for /proc/sys being mounted readonly, as systemd does - if grep '/proc/sys\s\+\w\+\s\+ro,' /proc/mounts >/dev/null; then - mount -o remount,rw /proc/sys - fi - fi - - local mtu=$(cat /sys/class/net/$(ip route get 8.8.8.8|awk '{ print $5 }')/mtu) - local server_args="--mtu ${mtu}" - local registry="" - - server_args="${server_args}" - - for registry in $3; do - server_args="${server_args} --insecure-registry ${registry}" - done - - if [ -n "$4" ]; then - server_args="${server_args} --registry-mirror $4" - fi - - try_start() { - dockerd --data-root /scratch/docker ${server_args} >$DOCKER_LOG_FILE 2>&1 & - echo $! > /tmp/docker.pid - - sleep 1 - - echo waiting for docker to come up... - until docker info >/dev/null 2>&1; do - sleep 1 - if ! kill -0 "$(cat /tmp/docker.pid)" 2>/dev/null; then - return 1 - fi - done - } - - export server_args DOCKER_LOG_FILE - declare -fx try_start - trap stop_docker EXIT - - if ! timeout ${STARTUP_TIMEOUT} bash -ce 'while true; do try_start && break; done'; then - echo Docker failed to start within ${STARTUP_TIMEOUT} seconds. - return 1 - fi -} - -stop_docker() { - local pid=$(cat /tmp/docker.pid) - if [ -z "$pid" ]; then - return 0 - fi - - kill -TERM $pid -} - diff --git a/ci/images/get-docker-url.sh b/ci/images/get-docker-url.sh deleted file mode 100755 index 221b3462..00000000 --- a/ci/images/get-docker-url.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -e - -version="20.10.6" -echo "https://download.docker.com/linux/static/stable/x86_64/docker-$version.tgz"; diff --git a/ci/images/setup.sh b/ci/images/setup.sh deleted file mode 100755 index 6c90192c..00000000 --- a/ci/images/setup.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -set -ex - -########################################################### -# UTILS -########################################################### -export DEBIAN_FRONTEND=noninteractive -apt-get update -apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig -ln -fs /usr/share/zoneinfo/UTC /etc/localtime -dpkg-reconfigure --frontend noninteractive tzdata -rm -rf /var/lib/apt/lists/* -curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh - -########################################################### -# JAVA -########################################################### -JDK_URL=https://github.com/bell-sw/Liberica/releases/download/17.0.6+10/bellsoft-jdk17.0.6+10-linux-amd64.tar.gz - -mkdir -p /opt/openjdk -cd /opt/openjdk -curl -L ${JDK_URL} | tar zx --strip-components=1 -test -f /opt/openjdk/bin/java -test -f /opt/openjdk/bin/javac - -########################################################### -# DOCKER -########################################################### -cd / -DOCKER_URL=$( ./get-docker-url.sh ) -curl -L ${DOCKER_URL} | tar zx -mv /docker/* /bin/ -chmod +x /bin/docker* -export ENTRYKIT_VERSION=0.4.0 -curl -L https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz | tar zx -chmod +x entrykit && \ -mv entrykit /bin/entrykit && \ -entrykit --symlink \ No newline at end of file diff --git a/ci/parameters.yml b/ci/parameters.yml deleted file mode 100644 index d4564cd2..00000000 --- a/ci/parameters.yml +++ /dev/null @@ -1,10 +0,0 @@ -project: spring-javaformat -branch: main -milestone: 0.0.x -github-owner: spring-io -github-repository: spring-javaformat -docker-hub-ci-organization: springci -ci-image: spring-javaformat-ci -artifactory-server: https://repo.spring.io -build-name: spring-javaformat -task-timeout: 2h00m diff --git a/ci/pipeline.yml b/ci/pipeline.yml deleted file mode 100644 index 128c9014..00000000 --- a/ci/pipeline.yml +++ /dev/null @@ -1,326 +0,0 @@ -anchors: - github-release-source: &github-release-source - owner: ((github-owner)) - repository: ((github-repository)) - access_token: ((github-ci-release-token)) - artifactory-repo-put-params: &artifactory-repo-put-params - signing_key: ((signing-key)) - signing_passphrase: ((signing-passphrase)) - repo: libs-snapshot-local - folder: distribution-repository - build_uri: https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME} - build_number: ${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME} - disable_checksum_uploads: true - threads: 8 - sonatype-task-params: &sonatype-task-params - SONATYPE_USERNAME: ((sonatype-username)) - SONATYPE_PASSWORD: ((sonatype-password)) - SONATYPE_URL: ((sonatype-url)) - SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id)) - artifactory-task-params: &artifactory-task-params - ARTIFACTORY_SERVER: ((artifactory-server)) - ARTIFACTORY_USERNAME: ((artifactory-username)) - ARTIFACTORY_PASSWORD: ((artifactory-password)) - docker-hub-task-params: &docker-hub-task-params - DOCKER_HUB_USERNAME: ((docker-hub-username)) - DOCKER_HUB_PASSWORD: ((docker-hub-password)) - slack-fail-params: &slack-fail-params - text: > - :concourse-failed: - silent: true - icon_emoji: ":concourse:" - username: concourse-ci - slack-success-params: &slack-success-params - text: > - :concourse-succeeded: - silent: true - icon_emoji: ":concourse:" - username: concourse-ci -resource_types: -- name: artifactory-resource - type: registry-image - source: - repository: springio/artifactory-resource - tag: "0.0.18" - username: ((docker-hub-username)) - password: ((docker-hub-password)) -- name: slack-notification - type: registry-image - source: - repository: cfcommunity/slack-notification-resource - username: ((docker-hub-username)) - password: ((docker-hub-password)) -resources: -- name: git-repo - type: git - icon: github - source: - uri: https://github.com/((github-owner))/((github-repository)).git - username: ((github-username)) - password: ((github-ci-release-token)) - branch: ((branch)) -- name: github-pre-release - type: github-release - icon: briefcase-download-outline - source: - <<: *github-release-source - pre_release: true - release: false -- name: github-release - type: github-release - icon: briefcase-download - source: - <<: *github-release-source - pre_release: false - release: true -- name: ci-images-git-repo - type: git - icon: github - source: - uri: https://github.com/((github-owner))/((github-repository)).git - branch: ((branch)) - paths: ["ci/images/*"] -- name: ci-image - type: registry-image - icon: docker - source: - username: ((docker-hub-username)) - password: ((docker-hub-password)) - tag: ((milestone)) - repository: ((docker-hub-ci-organization))/((ci-image)) -- name: artifactory-repo - type: artifactory-resource - icon: package-variant - source: - uri: ((artifactory-server)) - username: ((artifactory-username)) - password: ((artifactory-password)) - build_name: ((build-name)) -- name: slack-alert - type: slack-notification - icon: slack - source: - url: ((slack-webhook-url)) -jobs: -- name: build-ci-images - plan: - - get: ci-images-git-repo - trigger: true - - get: git-repo - - task: build-ci-image - privileged: true - file: git-repo/ci/tasks/build-ci-image.yml - params: - DOCKER_HUB_AUTH: ((docker-hub-auth)) - output_mapping: - image: ci-image - - put: ci-image - params: - image: ci-image/image.tar -- name: build - serial: true - public: true - plan: - - get: ci-image - - get: git-repo - trigger: true - - do: - - task: build-project - image: ci-image - privileged: true - timeout: ((task-timeout)) - file: git-repo/ci/tasks/build-project.yml - params: - <<: *docker-hub-task-params - BRANCH: ((branch)) - on_failure: - do: - - put: slack-alert - params: - <<: *slack-fail-params - - put: artifactory-repo - params: - <<: *artifactory-repo-put-params - get_params: - threads: 8 - on_failure: - do: - - put: slack-alert - params: - <<: *slack-fail-params - - put: slack-alert - params: - <<: *slack-success-params -- name: stage-milestone - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - task: stage - image: ci-image - file: git-repo/ci/tasks/stage.yml - params: - <<: *docker-hub-task-params - RELEASE_TYPE: M - - put: artifactory-repo - params: - <<: *artifactory-repo-put-params - repo: libs-staging-local - - put: git-repo - params: - repository: stage-git-repo -- name: stage-rc - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - task: stage - image: ci-image - file: git-repo/ci/tasks/stage.yml - params: - <<: *docker-hub-task-params - RELEASE_TYPE: RC - - put: artifactory-repo - params: - <<: *artifactory-repo-put-params - repo: libs-staging-local - - put: git-repo - params: - repository: stage-git-repo -- name: stage-release - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - task: stage - image: ci-image - file: git-repo/ci/tasks/stage.yml - params: - <<: *docker-hub-task-params - RELEASE_TYPE: RELEASE - - put: artifactory-repo - params: - <<: *artifactory-repo-put-params - repo: libs-staging-local - - put: git-repo - params: - repository: stage-git-repo -- name: promote-milestone - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [stage-milestone] - params: - download_artifacts: false - save_build_info: true - - task: promote - file: git-repo/ci/tasks/promote.yml - params: - RELEASE_TYPE: M - <<: *artifactory-task-params - - task: generate-changelog - file: git-repo/ci/tasks/generate-changelog.yml - params: - RELEASE_TYPE: M - GITHUB_USERNAME: ((github-username)) - GITHUB_TOKEN: ((github-ci-release-token)) - - put: github-pre-release - params: - name: generated-changelog/tag - tag: generated-changelog/tag - body: generated-changelog/changelog.md -- name: promote-rc - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [stage-rc] - params: - download_artifacts: false - save_build_info: true - - task: promote - file: git-repo/ci/tasks/promote.yml - params: - RELEASE_TYPE: RC - <<: *artifactory-task-params - - task: generate-changelog - file: git-repo/ci/tasks/generate-changelog.yml - params: - RELEASE_TYPE: RC - - put: github-pre-release - params: - name: generated-changelog/tag - tag: generated-changelog/tag - body: generated-changelog/changelog.md -- name: promote-release - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [stage-release] - params: - download_artifacts: true - save_build_info: true - - task: promote - file: git-repo/ci/tasks/promote.yml - params: - RELEASE_TYPE: RELEASE - <<: *artifactory-task-params - <<: *sonatype-task-params -- name: create-github-release - serial: true - plan: - - get: ci-image - - get: git-repo - - get: artifactory-repo - trigger: true - passed: [promote-release] - params: - download_artifacts: false - save_build_info: true - - task: generate-changelog - file: git-repo/ci/tasks/generate-changelog.yml - params: - RELEASE_TYPE: RELEASE - - put: github-release - params: - name: generated-changelog/tag - tag: generated-changelog/tag - body: generated-changelog/changelog.md -- name: publish-eclipse-update-site - serial: true - plan: - - get: ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [promote-release] - params: - save_build_info: true - - task: publish-eclipse-update-site - image: ci-image - file: git-repo/ci/tasks/publish-eclipse-update-site.yml - params: - ARTIFACTORY_USERNAME: ((artifactory-username)) - ARTIFACTORY_PASSWORD: ((artifactory-password)) -groups: -- name: builds - jobs: [build] -- name: releases - jobs: [stage-milestone, stage-rc, stage-release, promote-milestone, promote-rc, promote-release, create-github-release, publish-eclipse-update-site] -- name: ci-images - jobs: [build-ci-images] diff --git a/ci/scripts/build-project.sh b/ci/scripts/build-project.sh deleted file mode 100755 index bc833d36..00000000 --- a/ci/scripts/build-project.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh -repository=$(pwd)/distribution-repository - -pushd git-repo > /dev/null -run_maven clean deploy -U -Dfull -DaltDeploymentRepository=distribution::default::file://${repository} -popd > /dev/null diff --git a/ci/scripts/common.sh b/ci/scripts/common.sh deleted file mode 100644 index 8eea3f79..00000000 --- a/ci/scripts/common.sh +++ /dev/null @@ -1,9 +0,0 @@ -source /opt/concourse-java.sh - -setup_symlinks - -if [[ -n $DOCKER_HUB_USERNAME ]]; then - docker login -u $DOCKER_HUB_USERNAME -p $DOCKER_HUB_PASSWORD -fi - -cleanup_maven_repo "io.spring.javaformat" diff --git a/ci/scripts/generate-changelog.sh b/ci/scripts/generate-changelog.sh deleted file mode 100755 index 1e4b6e5b..00000000 --- a/ci/scripts/generate-changelog.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -e - -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) - -java -jar /github-changelog-generator.jar \ - --changelog.repository=spring-io/spring-javaformat \ - ${version} generated-changelog/changelog.md - -echo ${version} > generated-changelog/version -echo v${version} > generated-changelog/tag diff --git a/ci/scripts/promote.sh b/ci/scripts/promote.sh deleted file mode 100755 index 4ce8285b..00000000 --- a/ci/scripts/promote.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e - -CONFIG_DIR=git-repo/ci/config - -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) - -export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json - -java -jar /concourse-release-scripts.jar \ - --spring.config.location=${CONFIG_DIR}/release-scripts.yml \ - publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; } - -java -jar /concourse-release-scripts.jar \ - --spring.config.location=${CONFIG_DIR}/release-scripts.yml \ - promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; } - -echo "Promotion complete" diff --git a/ci/scripts/stage.sh b/ci/scripts/stage.sh deleted file mode 100755 index 5b36e8b4..00000000 --- a/ci/scripts/stage.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh -repository=$(pwd)/distribution-repository - -pushd git-repo > /dev/null -git fetch --tags --all > /dev/null -popd > /dev/null - -git clone git-repo stage-git-repo > /dev/null - -pushd stage-git-repo > /dev/null - -snapshotVersion=$( xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml ) -if [[ $RELEASE_TYPE = "M" ]]; then - stageVersion=$( get_next_milestone_release $snapshotVersion) - nextVersion=$snapshotVersion -elif [[ $RELEASE_TYPE = "RC" ]]; then - stageVersion=$( get_next_rc_release $snapshotVersion) - nextVersion=$snapshotVersion -elif [[ $RELEASE_TYPE = "RELEASE" ]]; then - stageVersion=$( get_next_release $snapshotVersion) - nextVersion=$( bump_version_number $snapshotVersion) -else - echo "Unknown release type $RELEASE_TYPE" >&2; exit 1; -fi - -echo "Staging ${stageVersion} (next version will be ${nextVersion})" -run_maven versions:set -DnewVersion=${stageVersion} -DgenerateBackupPoms=false -run_maven org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata -run_maven --projects io.spring.javaformat:spring-javaformat-vscode-extension -P '!formatter-dependencies' antrun:run@update-version frontend:install-node-and-npm frontend:npm@update-package-lock - -git config user.name "Spring Builds" > /dev/null -git config user.email "spring-builds@users.noreply.github.com" > /dev/null -git add pom.xml > /dev/null -git commit -m"Release v${stageVersion}" > /dev/null -git tag -a "v${stageVersion}" -m"Release v${stageVersion}" > /dev/null - -run_maven clean deploy -U -Dfull -DaltDeploymentRepository=distribution::default::file://${repository} - -git reset --hard HEAD^ > /dev/null -if [[ $nextVersion != $snapshotVersion ]]; then - echo "Setting next development version (v$nextVersion)" - run_maven versions:set -DnewVersion=$nextVersion -DgenerateBackupPoms=false - run_maven org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata - run_maven --projects io.spring.javaformat:spring-javaformat-vscode-extension -P '!formatter-dependencies' antrun:run@update-version frontend:npm@update-package-lock - sed -i "s/:release-version:.*/:release-version: ${stageVersion}/g" README.adoc - sed -i "s/spring-javaformat-gradle-plugin:.*/spring-javaformat-gradle-plugin:${nextVersion}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle - sed -i "s/spring-javaformat-checkstyle:.*/spring-javaformat-checkstyle:${nextVersion}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle - sed -i "s|.*|${nextVersion}|" samples/spring-javaformat-maven-sample/pom.xml - git add -u . > /dev/null - git commit -m"Next development version (v${nextVersion})" > /dev/null -fi; - -popd > /dev/null - -echo "Staging Complete" diff --git a/ci/scripts/sync-to-maven-central.sh b/ci/scripts/sync-to-maven-central.sh deleted file mode 100755 index f691b9f9..00000000 --- a/ci/scripts/sync-to-maven-central.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) -java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; } - -echo "Sync complete" diff --git a/ci/tasks/build-ci-image.yml b/ci/tasks/build-ci-image.yml deleted file mode 100644 index 6f4de778..00000000 --- a/ci/tasks/build-ci-image.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -platform: linux -image_resource: - type: registry-image - source: - repository: concourse/oci-build-task - tag: 0.10.0 - username: ((docker-hub-username)) - password: ((docker-hub-password)) -inputs: -- name: ci-images-git-repo -outputs: -- name: image -caches: -- path: ci-image-cache -params: - CONTEXT: ci-images-git-repo/ci/images - DOCKERFILE: ci-images-git-repo/ci/images/ci-image/Dockerfile -run: - path: /bin/sh - args: - - "-c" - - | - mkdir -p /root/.docker - cat > /root/.docker/config.json <4.0.0 io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT pom Spring JavaFormat Build Spring JavaFormat @@ -32,12 +32,12 @@ UTF-8 1.8 https://download.eclipse.org/releases/2021-03/202103171000/ - https://download.eclipse.org/releases/2022-12/202212071000/ + https://download.eclipse.org/releases/2024-03/202403131000/ https://checkstyle.org/eclipse-cs-update-site/ true 1.8.1 1.0b3 - 7.3.1 + 9.6 3.8.0 9.3 2.4.21 @@ -53,8 +53,8 @@ 1.16.0 1.16.0 3.0.3 - 3.0.1 - 3.0.1 + 4.0.4 + 4.0.4 @@ -290,6 +290,11 @@ cocoa x86_64 + + macosx + cocoa + aarch64 + @@ -461,7 +466,6 @@ src/checkstyle/checkstyle-suppressions.xml src/checkstyle/checkstyle-header.txt checkstyle.build.directory=${project.build.directory} - UTF-8 true true true diff --git a/samples/spring-javaformat-gradle-sample/build.gradle b/samples/spring-javaformat-gradle-sample/build.gradle index af133b51..9e1f5c9a 100644 --- a/samples/spring-javaformat-gradle-sample/build.gradle +++ b/samples/spring-javaformat-gradle-sample/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.40-SNAPSHOT") + classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.47-SNAPSHOT") } } @@ -25,5 +25,5 @@ checkstyle { } dependencies { - checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.40-SNAPSHOT") + checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.47-SNAPSHOT") } diff --git a/samples/spring-javaformat-maven-sample/pom.xml b/samples/spring-javaformat-maven-sample/pom.xml index d1787e95..9eb60913 100644 --- a/samples/spring-javaformat-maven-sample/pom.xml +++ b/samples/spring-javaformat-maven-sample/pom.xml @@ -8,7 +8,7 @@ 0.0.1-SNAPSHOT UTF-8 - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml index 86e75ce9..aebcd72d 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml @@ -2,7 +2,7 @@ @@ -22,7 +22,7 @@ id="io.spring.javaformat.eclipse" download-size="0" install-size="0" - version="0.0.40.qualifier" + version="0.0.47.qualifier" unpack="false"/> diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml index de73a542..7b4a2a51 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT io.spring.javaformat.eclipse.feature eclipse-feature diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml index 1671bd14..cc2c89a7 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml @@ -3,7 +3,7 @@ Maven Integration for Eclipse (maven-eclipse-plugin support) - + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product index 122cd325..20f32d4b 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product @@ -1,7 +1,7 @@ - + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml index 9ad814cb..982bb285 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT io.spring.javaformat.eclipse.site eclipse-repository diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF index e0eaabe7..d9e188f3 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF @@ -7,7 +7,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Spring Java Format Plugin Tests Bundle-SymbolicName: io.spring.javaformat.eclipse.tests Automatic-Module-Name: io.spring.javaformat.eclipse.tests -Bundle-Version: 0.0.40.qualifier +Bundle-Version: 0.0.47.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ClassPath: ., lib/assertj-core.jar, diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml index c478249a..99fa280e 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT io.spring.javaformat.eclipse.tests eclipse-test-plugin @@ -14,6 +14,7 @@ ${basedir}/../.. 17 + true @@ -31,10 +32,31 @@ org.apache.maven.plugins - maven-javadoc-plugin - - **/*Tests.java - + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java index c9261ead..226e0625 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,7 @@ void jdtCorePrefsFormatterWhenDefaultUsesTabs() throws IOException { Properties properties = new Properties(); properties.load(content); assertThat(properties.get("org.eclipse.jdt.core.javaFormatter")) - .isEqualTo("io.spring.javaformat.eclipse.formatter.jdk11.tabs"); + .isEqualTo("io.spring.javaformat.eclipse.formatter.jdk17.tabs"); } } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF index c792e683..12cac3a6 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Spring Java Format Plugin Bundle-SymbolicName: io.spring.javaformat.eclipse;singleton:=true Automatic-Module-Name: io.spring.javaformat.eclipse -Bundle-Version: 0.0.40.qualifier +Bundle-Version: 0.0.47.qualifier Bundle-Activator: io.spring.javaformat.eclipse.Activator Bundle-RequiredExecutionEnvironment: JavaSE-11 Require-Bundle: org.eclipse.ui, @@ -21,6 +21,6 @@ Bundle-ClassPath: ., lib/spring-javaformat-config.jar, lib/spring-javaformat-formatter.jar, lib/spring-javaformat-checkstyle.jar, - lib/spring-javaformat-formatter-eclipse-jdt-jdk11.jar, + lib/spring-javaformat-formatter-eclipse-jdt-jdk17.jar, lib/spring-javaformat-formatter-eclipse-jdt-jdk8.jar Bundle-ActivationPolicy: lazy diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties index 7780dc22..9bd6565a 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties @@ -6,5 +6,5 @@ bin.includes = META-INF/,\ lib/spring-javaformat-checkstyle.jar,\ lib/spring-javaformat-config.jar,\ lib/spring-javaformat-formatter.jar,\ - lib/spring-javaformat-formatter-eclipse-jdt-jdk11.jar,\ + lib/spring-javaformat-formatter-eclipse-jdt-jdk17.jar,\ lib/spring-javaformat-formatter-eclipse-jdt-jdk8.jar diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml index b6bdf963..f9864bd4 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml @@ -3,13 +3,13 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT io.spring.javaformat.eclipse eclipse-plugin @@ -38,6 +38,18 @@ + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + org.apache.maven.plugins maven-javadoc-plugin @@ -60,7 +72,7 @@ io.spring.javaformat - spring-javaformat-formatter-eclipse-jdt-jdk11 + spring-javaformat-formatter-eclipse-jdt-jdk17 ${project.version} diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java index 4b03b9eb..cfa779b0 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ public class Activator extends AbstractUIPlugin { public Activator() { this.javaCorePlugins.add(new io.spring.javaformat.eclipse.jdt.jdk8.core.JavaCore()); - this.javaCorePlugins.add(new io.spring.javaformat.eclipse.jdt.jdk11.core.JavaCore()); + this.javaCorePlugins.add(new io.spring.javaformat.eclipse.jdt.jdk17.core.JavaCore()); } @Override diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Spaces.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java similarity index 80% rename from spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Spaces.java rename to spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java index e6775b74..8680dbf8 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Spaces.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,10 +27,10 @@ * * @author Phillip Webb */ -public class SpringCodeFormatterJdk11Spaces extends SpringCodeFormatter { +public class SpringCodeFormatterJdk17Spaces extends SpringCodeFormatter { - public SpringCodeFormatterJdk11Spaces() { - super(JavaFormatConfig.of(JavaBaseline.V11, IndentationStyle.SPACES)); + public SpringCodeFormatterJdk17Spaces() { + super(JavaFormatConfig.of(JavaBaseline.V17, IndentationStyle.SPACES)); } } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Tabs.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java similarity index 80% rename from spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Tabs.java rename to spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java index 78bd7aba..b0301b2e 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk11Tabs.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,10 +27,10 @@ * * @author Phillip Webb */ -public class SpringCodeFormatterJdk11Tabs extends SpringCodeFormatter { +public class SpringCodeFormatterJdk17Tabs extends SpringCodeFormatter { - public SpringCodeFormatterJdk11Tabs() { - super(JavaFormatConfig.of(JavaBaseline.V11, IndentationStyle.TABS)); + public SpringCodeFormatterJdk17Tabs() { + super(JavaFormatConfig.of(JavaBaseline.V17, IndentationStyle.TABS)); } } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java index 792d207e..5062bfe9 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,7 +73,7 @@ private String updateFormatter(JavaFormatConfig javaFormatConfig, String content String formatterId = getFormatterId(javaFormatConfig); if (formatterId != null) { return content.replace( - "org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk11.tabs", + "org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk17.tabs", "org.eclipse.jdt.core.javaFormatter=" + formatterId); } return content; @@ -81,6 +81,7 @@ private String updateFormatter(JavaFormatConfig javaFormatConfig, String content private String getFormatterId(JavaFormatConfig config) { String jdk = config.getJavaBaseline().name().substring(1); + jdk = (!"11".equals(jdk)) ? jdk : "17"; String indentation = config.getIndentationStyle().name().toLowerCase(); return "io.spring.javaformat.eclipse.formatter.jdk" + jdk + "." + indentation; } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs index fd682fe6..c08217ef 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs @@ -45,7 +45,7 @@ org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning -org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled @@ -82,7 +82,7 @@ org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=info org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore @@ -99,6 +99,8 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference= org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=info org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk11.tabs +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk17.tabs diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs index af9117f9..23d79e64 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs @@ -1,3 +1,4 @@ +cleanup.add_all=false cleanup.add_default_serial_version_id=true cleanup.add_generated_serial_version_id=false cleanup.add_missing_annotations=true diff --git a/spring-javaformat-eclipse/pom.xml b/spring-javaformat-eclipse/pom.xml index 1388f7a5..3590c925 100644 --- a/spring-javaformat-eclipse/pom.xml +++ b/spring-javaformat-eclipse/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-eclipse pom @@ -17,9 +17,9 @@ - eclipse-jdk11 + eclipse-jdk17 p2 - ${eclipse.jdk11.repository} + ${eclipse.jdk17.repository} eclipse-checkstyle diff --git a/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml index af870f42..be5f1d3e 100644 --- a/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml +++ b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat-gradle - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT io.spring.javaformat io.spring.javaformat.gradle.plugin diff --git a/spring-javaformat-gradle/pom.xml b/spring-javaformat-gradle/pom.xml index bfe50daf..c13954a9 100644 --- a/spring-javaformat-gradle/pom.xml +++ b/spring-javaformat-gradle/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-gradle pom diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml index 49a158aa..5a6de1f3 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-gradle - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-gradle-plugin pom diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java index 096e1109..7e531d42 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java @@ -24,10 +24,10 @@ import java.util.List; import java.util.stream.Collectors; -import org.gradle.api.GradleException; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.VerificationException; import io.spring.javaformat.formatter.FileEdit; @@ -63,7 +63,7 @@ public void checkFormatting() throws IOException, InterruptedException { message.append("\nRun `format` to fix."); Files.write(this.reportLocation.toPath(), Collections.singletonList(message.toString()), StandardOpenOption.CREATE); - throw new GradleException(message.toString()); + throw new VerificationException(message.toString()); } else { this.reportLocation.createNewFile(); diff --git a/spring-javaformat-intellij-idea/pom.xml b/spring-javaformat-intellij-idea/pom.xml index 1e5a3d97..4d8c434c 100644 --- a/spring-javaformat-intellij-idea/pom.xml +++ b/spring-javaformat-intellij-idea/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-intellij-idea pom diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml index 359131b6..611a99fe 100644 --- a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-intellij-idea - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-intellij-idea-plugin Spring JavaFormat IntelliJ IDEA Plugin diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml index 43590141..dc437a12 100644 --- a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-intellij-idea - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-intellij-idea-runtime pom diff --git a/spring-javaformat-maven/pom.xml b/spring-javaformat-maven/pom.xml index 4e1b694d..a14e54eb 100644 --- a/spring-javaformat-maven/pom.xml +++ b/spring-javaformat-maven/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-maven pom diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml index aef8d6b2..88294ec8 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat-maven - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-maven-plugin maven-plugin diff --git a/spring-javaformat-vscode/pom.xml b/spring-javaformat-vscode/pom.xml index 1cd28651..c217c403 100644 --- a/spring-javaformat-vscode/pom.xml +++ b/spring-javaformat-vscode/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-vscode pom diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json index fcf5a077..5ea30c21 100644 --- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "spring-javaformat-vscode-extension", - "version": "0.0.40-SNAPSHOT", + "version": "0.0.47-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "spring-javaformat-vscode-extension", - "version": "0.0.40-SNAPSHOT", + "version": "0.0.47-SNAPSHOT", "devDependencies": { "@types/glob": "^8.0.1", "@types/mocha": "^10.0.1", @@ -14,7 +14,7 @@ "@types/vscode": "^1.75.0", "@typescript-eslint/eslint-plugin": "^5.52.0", "@vscode/test-electron": "^2.2.2", - "@vscode/vsce": "^2.17.0", + "@vscode/vsce": "^2.19.0", "eslint": "^8.33.0", "glob": "8.1.0", "mocha": "10.2.0", @@ -376,9 +376,9 @@ } }, "node_modules/@vscode/vsce": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.17.0.tgz", - "integrity": "sha512-W4HN5MtTVj/mroQU1d82bUEeWM3dUykMFnMYZPtZ6jrMiHN1PUoN3RGcS896N0r2rIq8KpWDtufcQHgK8VfgpA==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", + "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", "dev": true, "dependencies": { "azure-devops-node-api": "^11.0.1", @@ -387,6 +387,7 @@ "commander": "^6.1.0", "glob": "^7.0.6", "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", "leven": "^3.1.0", "markdown-it": "^12.3.2", "mime": "^1.3.4", @@ -397,7 +398,7 @@ "tmp": "^0.2.1", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", - "xml2js": "^0.4.23", + "xml2js": "^0.5.0", "yauzl": "^2.3.1", "yazl": "^2.2.2" }, @@ -2138,6 +2139,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -3636,9 +3643,9 @@ "dev": true }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "dependencies": { "sax": ">=0.6.0", diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json index 32267383..63e3b775 100644 --- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json @@ -2,7 +2,7 @@ "name": "spring-javaformat-vscode-extension", "description": "Spring JavaFormat Visual Studio Code Extension", "displayName": "Spring JavaFormat", - "version": "0.0.40-SNAPSHOT", + "version": "0.0.47-SNAPSHOT", "publisher": "io.spring.javaformat", "engines": { "vscode": "^1.75.0" @@ -33,7 +33,7 @@ "@types/vscode": "^1.75.0", "@typescript-eslint/eslint-plugin": "^5.52.0", "@vscode/test-electron": "^2.2.2", - "@vscode/vsce": "^2.17.0", + "@vscode/vsce": "^2.19.0", "eslint": "^8.33.0", "glob": "8.1.0", "mocha": "10.2.0", diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml index 3354a18f..3c439b79 100644 --- a/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat-vscode - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-vscode-extension Spring JavaFormat Visual Studio Code Extension diff --git a/spring-javaformat/pom.xml b/spring-javaformat/pom.xml index 81f95083..7c086cc7 100644 --- a/spring-javaformat/pom.xml +++ b/spring-javaformat/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat pom @@ -38,9 +38,9 @@ spring-javaformat-formatter-tests spring-javaformat-formatter-eclipse-rewriter spring-javaformat-formatter-eclipse-jdk8 - spring-javaformat-formatter-eclipse-jdk11 + spring-javaformat-formatter-eclipse-jdk17 spring-javaformat-formatter-eclipse-jdt-jdk8 - spring-javaformat-formatter-eclipse-jdt-jdk11 + spring-javaformat-formatter-eclipse-jdt-jdk17 spring-javaformat-formatter-eclipse-runtime spring-javaformat-formatter-shader spring-javaformat-formatter-shaded diff --git a/spring-javaformat/spring-javaformat-checkstyle/pom.xml b/spring-javaformat/spring-javaformat-checkstyle/pom.xml index c6f69b9c..7d74f0cc 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/pom.xml +++ b/spring-javaformat/spring-javaformat-checkstyle/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-checkstyle Spring JavaFormat CheckStyle diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java index 17e4e403..42ca7311 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,11 @@ package io.spring.javaformat.checkstyle; +import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.stream.Collectors; @@ -24,11 +28,14 @@ import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions; import com.puppycrawl.tools.checkstyle.PropertyResolver; -import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configurable; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.Context; +import com.puppycrawl.tools.checkstyle.api.Contextualizable; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; +import com.puppycrawl.tools.checkstyle.api.Scope; +import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck; import org.xml.sax.InputSource; /** @@ -49,17 +56,45 @@ class SpringConfigurationLoader { } public Collection load(PropertyResolver propertyResolver) { - Configuration config = loadConfiguration(getClass().getResourceAsStream("spring-checkstyle.xml"), - propertyResolver); + Configuration config = loadConfiguration(loadConfigurationSource(), propertyResolver); return Arrays.stream(config.getChildren()) .filter(this.moduleFactory::nonFiltered) .map(this::load) .collect(Collectors.toList()); } - private Configuration loadConfiguration(InputStream inputStream, PropertyResolver propertyResolver) { + private String loadConfigurationSource() { + try (InputStream stream = getClass().getResourceAsStream("spring-checkstyle.xml")) { + StringBuilder builder = new StringBuilder(); + byte[] buffer = new byte[4096]; + int read; + while ((read = stream.read(buffer)) > 0) { + builder.append(new String(buffer, 0, read, StandardCharsets.UTF_8)); + } + return preprocessConfigurationSource(builder.toString()); + } + catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private String preprocessConfigurationSource(String source) { + return source.replace("{{javadocVariableCheckScopeProperty}}", javadocVariableCheckScopeProperty()); + } + + private String javadocVariableCheckScopeProperty() { try { - InputSource inputSource = new InputSource(inputStream); + JavadocVariableCheck.class.getMethod("setScope", Scope.class); + return "scope"; + } + catch (NoSuchMethodException ex) { + return "accessModifiers"; + } + } + + private Configuration loadConfiguration(String source, PropertyResolver propertyResolver) { + try { + InputSource inputSource = new InputSource(new StringReader(source)); return ConfigurationLoader.loadConfiguration(inputSource, propertyResolver, IgnoredModulesOptions.EXECUTE); } catch (CheckstyleException ex) { @@ -79,9 +114,7 @@ private Object createModule(Configuration configuration) { String name = configuration.getName(); try { Object module = this.moduleFactory.createModule(name); - if (module instanceof AutomaticBean) { - initialize(configuration, (AutomaticBean) module); - } + initialize(configuration, module); return module; } catch (CheckstyleException ex) { @@ -89,9 +122,13 @@ private Object createModule(Configuration configuration) { } } - private void initialize(Configuration configuration, AutomaticBean bean) throws CheckstyleException { - bean.contextualize(this.context); - bean.configure(configuration); + private void initialize(Configuration configuration, Object module) throws CheckstyleException { + if (module instanceof Contextualizable) { + ((Contextualizable) module).contextualize(this.context); + } + if (module instanceof Configurable) { + ((Configurable) module).configure(configuration); + } } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java new file mode 100644 index 00000000..f0fc0d5e --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java @@ -0,0 +1,124 @@ +/* + * Copyright 2017-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtil; + +/** + * Spring variant of {@link AnnotationLocationCheck}. + * + * @author Phillip Webb + */ +public class SpringAnnotationLocationCheck extends AbstractCheck { + + private static final Set JSPECIFY_ANNOTATION_NAMES = new HashSet<>( + Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked")); + + @Override + public int[] getDefaultTokens() { + return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF, + TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, }; + } + + @Override + public int[] getAcceptableTokens() { + return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF, + TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, TokenTypes.ANNOTATION_DEF, TokenTypes.ANNOTATION_FIELD_DEF, + TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, }; + } + + @Override + public int[] getRequiredTokens() { + return CommonUtil.EMPTY_INT_ARRAY; + } + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() != TokenTypes.VARIABLE_DEF || ast.getParent().getType() == TokenTypes.OBJBLOCK) { + DetailAST node = ast.findFirstToken(TokenTypes.MODIFIERS); + node = (node != null) ? node : ast.findFirstToken(TokenTypes.ANNOTATIONS); + checkAnnotations(node, getExpectedAnnotationIndentation(node)); + } + } + + private int getExpectedAnnotationIndentation(DetailAST node) { + return node.getColumnNo(); + } + + private void checkAnnotations(DetailAST node, int correctIndentation) { + DetailAST annotation = node.getFirstChild(); + while (annotation != null && annotation.getType() == TokenTypes.ANNOTATION) { + checkAnnotation(correctIndentation, annotation); + annotation = annotation.getNextSibling(); + } + } + + private void checkAnnotation(int correctIndentation, DetailAST annotation) { + String annotationName = getAnnotationName(annotation); + if (!isCorrectLocation(annotation) && !isJSpecifyAnnotation(annotationName)) { + log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION_ALONE, annotationName); + } + else if (annotation.getColumnNo() != correctIndentation && !hasNodeBefore(annotation)) { + log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION, annotationName, + annotation.getColumnNo(), correctIndentation); + } + } + + private String getAnnotationName(DetailAST annotation) { + DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT); + if (identNode == null) { + identNode = annotation.findFirstToken(TokenTypes.DOT).findFirstToken(TokenTypes.IDENT); + } + return identNode.getText(); + } + + private boolean isCorrectLocation(DetailAST annotation) { + return !hasNodeBeside(annotation); + } + + private boolean hasNodeBeside(DetailAST annotation) { + return hasNodeBefore(annotation) || hasNodeAfter(annotation); + } + + private boolean hasNodeBefore(DetailAST annotation) { + int annotationLineNo = annotation.getLineNo(); + DetailAST previousNode = annotation.getPreviousSibling(); + return (previousNode != null) && (annotationLineNo == previousNode.getLineNo()); + } + + private boolean hasNodeAfter(DetailAST annotation) { + int annotationLineNo = annotation.getLineNo(); + DetailAST nextNode = annotation.getNextSibling(); + nextNode = (nextNode != null) ? nextNode : annotation.getParent().getNextSibling(); + return annotationLineNo == nextNode.getLineNo(); + } + + private boolean isJSpecifyAnnotation(String annotationName) { + return JSPECIFY_ANNOTATION_NAMES.contains(annotationName); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java index 255316b0..2e0de968 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ public class SpringAvoidStaticImportCheck extends AvoidStaticImportCheck { excludes.add("io.restassured.RestAssured.*"); excludes.add("org.assertj.core.api.Assertions.*"); excludes.add("org.assertj.core.api.Assumptions.*"); + excludes.add("org.assertj.core.api.BDDAssertions.*"); excludes.add("org.assertj.core.api.HamcrestCondition.*"); excludes.add("org.awaitility.Awaitility.*"); excludes.add("org.hamcrest.CoreMatchers.*"); @@ -46,11 +47,10 @@ public class SpringAvoidStaticImportCheck extends AvoidStaticImportCheck { excludes.add("org.junit.internal.matchers.ThrowableMessageMatcher.*"); excludes.add("org.junit.jupiter.api.Assertions.*"); excludes.add("org.junit.jupiter.api.Assumptions.*"); - excludes.add("org.junit.jupiter.api.Assertions.*"); + excludes.add("org.mockito.AdditionalMatchers.*"); excludes.add("org.mockito.ArgumentMatchers.*"); excludes.add("org.mockito.BDDMockito.*"); excludes.add("org.mockito.Matchers.*"); - excludes.add("org.mockito.AdditionalMatchers.*"); excludes.add("org.mockito.Mockito.*"); excludes.add("org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*"); excludes.add("org.springframework.boot.configurationprocessor.TestCompiler.*"); diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java index 5b5dc191..cdd8efc4 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java @@ -19,12 +19,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; @@ -38,33 +40,35 @@ */ public class SpringJUnit5Check extends AbstractSpringCheck { - private static final String JUNIT4_TEST_ANNOTATION = "org.junit.Test"; + private static final String JUNIT4_TEST_ANNOTATION_NAME = "org.junit.Test"; - private static final List TEST_ANNOTATIONS; + private static final List TEST_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - annotations.add("RepeatedTest"); - annotations.add("Test"); - annotations.add("TestFactory"); - annotations.add("TestTemplate"); - annotations.add("ParameterizedTest"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "RepeatedTest")); + annotations.add(new Annotation("org.junit.jupiter.api", "Test")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestFactory")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestTemplate")); + annotations.add(new Annotation("org.junit.jupiter.api", "ParameterizedTest")); TEST_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } - private static final List LIFECYCLE_ANNOTATIONS; + private static final List LIFECYCLE_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - annotations.add("BeforeAll"); - annotations.add("BeforeEach"); - annotations.add("AfterAll"); - annotations.add("AfterEach"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeEach")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterEach")); LIFECYCLE_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } + private static final Annotation NESTED_ANNOTATION = new Annotation("org.junit.jupiter.api", "Nested"); + private static final Set BANNED_IMPORTS; static { Set bannedImports = new LinkedHashSet<>(); - bannedImports.add(JUNIT4_TEST_ANNOTATION); + bannedImports.add(JUNIT4_TEST_ANNOTATION_NAME); bannedImports.add("org.junit.After"); bannedImports.add("org.junit.AfterClass"); bannedImports.add("org.junit.Before"); @@ -82,16 +86,22 @@ public class SpringJUnit5Check extends AbstractSpringCheck { private final List lifecycleMethods = new ArrayList<>(); + private final List nestedTestClasses = new ArrayList<>(); + + private DetailAST testClass; + @Override public int[] getAcceptableTokens() { - return new int[] { TokenTypes.METHOD_DEF, TokenTypes.IMPORT }; + return new int[] { TokenTypes.METHOD_DEF, TokenTypes.IMPORT, TokenTypes.CLASS_DEF }; } @Override public void beginTree(DetailAST rootAST) { + this.testClass = null; this.imports.clear(); this.testMethods.clear(); this.lifecycleMethods.clear(); + this.nestedTestClasses.clear(); } @Override @@ -99,26 +109,61 @@ public void visitToken(DetailAST ast) { switch (ast.getType()) { case TokenTypes.METHOD_DEF: visitMethodDef(ast); + break; case TokenTypes.IMPORT: visitImport(ast); break; + case TokenTypes.CLASS_DEF: + visitClassDefinition(ast); + break; } } private void visitMethodDef(DetailAST ast) { - if (AnnotationUtil.containsAnnotation(ast, TEST_ANNOTATIONS)) { + if (containsAnnotation(ast, TEST_ANNOTATIONS)) { this.testMethods.add(ast); } - if (AnnotationUtil.containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { + if (containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { this.lifecycleMethods.add(ast); } } + private boolean containsAnnotation(DetailAST ast, List annotations) { + List annotationNames = annotations.stream() + .flatMap((annotation) -> Stream.of(annotation.simpleName, annotation.fullyQualifiedName())) + .collect(Collectors.toList()); + try { + return AnnotationUtil.containsAnnotation(ast, annotationNames); + } + catch (NoSuchMethodError ex) { + // Checkstyle >= 10.3 (https://github.com/checkstyle/checkstyle/issues/14134) + Set annotationNamesSet = new HashSet<>(annotationNames); + try { + return (boolean) AnnotationUtil.class.getMethod("containsAnnotation", DetailAST.class, Set.class) + .invoke(null, ast, annotationNamesSet); + } + catch (Exception ex2) { + throw new RuntimeException("containsAnnotation failed", ex2); + } + } + } + private void visitImport(DetailAST ast) { FullIdent ident = FullIdent.createFullIdentBelow(ast); this.imports.put(ident.getText(), ident); } + private void visitClassDefinition(DetailAST ast) { + if (ast.getParent().getType() == TokenTypes.COMPILATION_UNIT) { + this.testClass = ast; + } + else { + if (containsAnnotation(ast, Arrays.asList(NESTED_ANNOTATION))) { + this.nestedTestClasses.add(ast); + } + } + } + @Override public void finishTree(DetailAST rootAST) { if (shouldCheck()) { @@ -127,7 +172,7 @@ public void finishTree(DetailAST rootAST) { } private boolean shouldCheck() { - if (this.testMethods.isEmpty() && this.lifecycleMethods.isEmpty()) { + if (this.testMethods.isEmpty() && this.lifecycleMethods.isEmpty() && this.nestedTestClasses.isEmpty()) { return false; } for (String unlessImport : this.unlessImports) { @@ -139,6 +184,10 @@ private boolean shouldCheck() { } private void check() { + if (this.testClass != null && !isAbstract(this.testClass)) { + checkVisibility(Arrays.asList(this.testClass), "junit5.publicClass", null); + } + checkVisibility(this.nestedTestClasses, "junit5.publicNestedClass", "junit5.privateNestedClass"); for (String bannedImport : BANNED_IMPORTS) { FullIdent ident = this.imports.get(bannedImport); if (ident != null) { @@ -146,29 +195,34 @@ private void check() { } } for (DetailAST testMethod : this.testMethods) { - if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION)) { + if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION_NAME)) { log(testMethod, "junit5.bannedTestAnnotation"); } } - checkMethodVisibility(this.testMethods, "junit5.testPublicMethod", "junit5.testPrivateMethod"); - checkMethodVisibility(this.lifecycleMethods, "junit5.lifecyclePublicMethod", "junit5.lifecyclePrivateMethod"); + checkVisibility(this.testMethods, "junit5.testPublicMethod", "junit5.testPrivateMethod"); + checkVisibility(this.lifecycleMethods, "junit5.lifecyclePublicMethod", "junit5.lifecyclePrivateMethod"); } - private void checkMethodVisibility(List methods, String publicMessageKey, String privateMessageKey) { - for (DetailAST method : methods) { - DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS); + private boolean isAbstract(DetailAST ast) { + DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); + return modifiers.findFirstToken(TokenTypes.ABSTRACT) != null; + } + + private void checkVisibility(List asts, String publicMessageKey, String privateMessageKey) { + for (DetailAST ast : asts) { + DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null) { - log(method, publicMessageKey); + log(ast, publicMessageKey); } - if (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null) { - log(method, privateMessageKey); + if ((privateMessageKey != null) && (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null)) { + log(ast, privateMessageKey); } } } - private void log(DetailAST method, String key) { - String name = method.findFirstToken(TokenTypes.IDENT).getText(); - log(method.getLineNo(), method.getColumnNo(), key, name); + private void log(DetailAST ast, String key) { + String name = ast.findFirstToken(TokenTypes.IDENT).getText(); + log(ast.getLineNo(), ast.getColumnNo(), key, name); } public void setUnlessImports(String unlessImports) { @@ -176,4 +230,21 @@ public void setUnlessImports(String unlessImports) { .unmodifiableList(Arrays.stream(unlessImports.split(",")).map(String::trim).collect(Collectors.toList())); } + private static final class Annotation { + + private final String packageName; + + private final String simpleName; + + private Annotation(String packageName, String simpleName) { + this.packageName = packageName; + this.simpleName = simpleName; + } + + private String fullyQualifiedName() { + return this.packageName + "." + this.simpleName; + } + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java index 188e6781..8e3fa83f 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java @@ -17,7 +17,9 @@ package io.spring.javaformat.checkstyle.check; import java.io.File; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; @@ -26,6 +28,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; import io.spring.javaformat.config.IndentationStyle; import io.spring.javaformat.config.JavaFormatConfig; @@ -49,14 +52,32 @@ public class SpringLeadingWhitespaceCheck extends AbstractSpringCheck { private IndentationStyle indentationStyle; + private final Deque textBlockPairs = new ArrayDeque<>(); + @Override public int[] getAcceptableTokens() { - return NO_REQUIRED_TOKENS; + return new int[] { TokenTypes.TEXT_BLOCK_LITERAL_BEGIN, TokenTypes.TEXT_BLOCK_LITERAL_END }; + } + + @Override + public void visitToken(DetailAST ast) { + super.visitToken(ast); + if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_BEGIN) { + this.textBlockPairs.add(new TextBlockPair(ast)); + } + else if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_END) { + this.textBlockPairs.getLast().end(ast); + } } @Override public void beginTree(DetailAST rootAST) { super.beginTree(rootAST); + this.textBlockPairs.clear(); + } + + @Override + public void finishTree(DetailAST rootAST) { FileContents fileContents = getFileContents(); FileText fileText = fileContents.getText(); File file = fileText.getFile(); @@ -66,8 +87,11 @@ public void beginTree(DetailAST rootAST) { IndentationStyle indentationStyle = (this.indentationStyle != null) ? this.indentationStyle : JavaFormatConfig.findFrom(file.getParentFile()).getIndentationStyle(); for (int i = 0; i < fileText.size(); i++) { - String line = fileText.get(i); int lineNo = i + 1; + if (isInTextBlock(lineNo)) { + continue; + } + String line = fileText.get(i); Matcher matcher = PATTERN.matcher(line); boolean found = matcher.find(0); while (found @@ -78,6 +102,11 @@ public void beginTree(DetailAST rootAST) { log(lineNo, "leadingwhitespace.incorrect", indentationStyle.toString().toLowerCase()); } } + super.finishTree(rootAST); + } + + private boolean isInTextBlock(int lineNo) { + return this.textBlockPairs.stream().anyMatch((textBlockPair) -> textBlockPair.contains(lineNo)); } public void setIndentationStyle(String indentationStyle) { @@ -85,4 +114,24 @@ public void setIndentationStyle(String indentationStyle) { ? IndentationStyle.valueOf(indentationStyle.toUpperCase()) : null; } + private static class TextBlockPair { + + private final DetailAST begin; + + private DetailAST end; + + TextBlockPair(DetailAST begin) { + this.begin = begin; + } + + public boolean contains(int lineNo) { + return (lineNo > this.begin.getLineNo()) && (lineNo <= this.end.getLineNo()); + } + + void end(DetailAST end) { + this.end = end; + } + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java index eeda7a05..01708750 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,20 @@ import java.io.File; +import com.puppycrawl.tools.checkstyle.JavaParser; +import com.puppycrawl.tools.checkstyle.JavaParser.Options; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** - * Checks that test filenames end {@literal Tests.java} and not {@literal Test.java}. + * Checks that test class filenames end {@literal Tests.java} and not + * {@literal Test.java}. * * @author Phillip Webb + * @author Andy Wilkinson */ public class SpringTestFileNameCheck extends AbstractFileSetCheck { @@ -33,7 +39,18 @@ public class SpringTestFileNameCheck extends AbstractFileSetCheck { protected void processFiltered(File file, FileText fileText) throws CheckstyleException { String path = file.getPath().replace('\\', '/'); if (path.contains("src/test/java") && file.getName().endsWith("Test.java")) { - log(1, "testfilename.wrongName"); + visitCompilationUnit(JavaParser.parseFileText(fileText, Options.WITHOUT_COMMENTS)); + } + } + + private void visitCompilationUnit(DetailAST ast) { + DetailAST child = ast.getFirstChild(); + while (child != null) { + if (child.getType() == TokenTypes.CLASS_DEF) { + log(1, "testfilename.wrongName"); + return; + } + child = child.getNextSibling(); } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties index 9982830e..cdea619e 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties @@ -1,3 +1,5 @@ +annotation.location=Annotation ''{0}'' have incorrect indentation level {1}, expected level should be {2}. +annotation.location.alone=Annotation ''{0}'' should be alone on line. catch.singleLetter=Single letter catch variable (use "ex" instead). catch.wideEye=''o_O'' catch variable (use "ex" instead). header.unexpected=Unexpected header. @@ -16,6 +18,9 @@ junit5.bannedImport=Import ''{0}'' should not be used in a JUnit 5 test. junit5.bannedTestAnnotation=JUnit 4 @Test annotation should not be used in a JUnit 5 test. junit5.lifecyclePrivateMethod=Lifecycle method ''{0}'' should not be private. junit5.lifecyclePublicMethod=Lifecycle method ''{0}'' should not be public. +junit5.publicClass=Test class ''{0}'' should not be public. +junit5.publicNestedClass=Nested test class ''{0}'' should not be public. +junit5.privateNestedClass=Nested test class ''{0}'' should not be private. junit5.testPrivateMethod=Test method ''{0}'' should not be private. junit5.testPublicMethod=Test method ''{0}'' should not be public. lambda.missingParen=Lambda argument missing parentheses. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml index c8838541..4da52558 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml @@ -22,11 +22,9 @@ + - - - + @@ -70,6 +68,7 @@ + @@ -88,7 +87,7 @@ - + diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java index 7d789a94..f3d31175 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,10 @@ public static Collection paramaters() throws IOException { .map(Parameter::new) .collect(Collectors.toCollection(ArrayList::new)); parameters.add(new Parameter(new File(SOURCES_DIR, "nopackageinfo/NoPackageInfo.java"))); - parameters.add(new Parameter(new File(SOURCES_DIR, "src/test/java/NamedTest.java"))); - parameters.add(new Parameter(new File(SOURCES_DIR, "src/test/java/NamedTests.java"))); + Arrays.stream(new File(SOURCES_DIR, "src/test/java").listFiles(SpringChecksTests::sourceFile)) + .sorted() + .map(Parameter::new) + .forEach(parameters::add); return parameters; } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java index 82e63f1e..33536e6b 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,10 @@ package io.spring.javaformat.checkstyle; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Properties; import java.util.Set; @@ -48,18 +50,23 @@ public void loadShouldLoadChecks() { assertThat(checks).hasSize(5); TreeWalker treeWalker = (TreeWalker) checks.toArray()[4]; Set ordinaryChecks = (Set) Extractors.byName("ordinaryChecks").extract(treeWalker); - assertThat(ordinaryChecks).hasSize(60); + assertThat(ordinaryChecks).hasSize(61); + Set commentChecks = (Set) Extractors.byName("commentChecks").extract(treeWalker); + assertThat(commentChecks).hasSize(6); } @Test public void loadWithExcludeShouldExcludeChecks() { - Set excludes = Collections - .singleton("com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck"); + Set excludes = new HashSet( + Arrays.asList("com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck", + "com.puppycrawl.tools.checkstyle.checks.annotation.MissingDeprecatedCheck")); Collection checks = load(excludes); assertThat(checks).hasSize(5); TreeWalker treeWalker = (TreeWalker) checks.toArray()[4]; Set ordinaryChecks = (Set) Extractors.byName("ordinaryChecks").extract(treeWalker); - assertThat(ordinaryChecks).hasSize(59); + assertThat(ordinaryChecks).hasSize(60); + Set commentChecks = (Set) Extractors.byName("commentChecks").extract(treeWalker); + assertThat(commentChecks).hasSize(5); } @Test diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt index 376aa13c..7ec1d4de 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt @@ -1,7 +1,11 @@ ++Test class 'JUnit5BadModifier' should not be public ++Nested test class 'PublicNestedTests' should not be public ++Nested test class 'PrivateNestedTests' should not be private +Test method 'doSomethingWorks' should not be public +Test method 'doSomethingElseWorks' should not be private +Test method 'doSomethingWithTemplateWorks' should not be public +Test method 'doSomethingElseWithTemplateWorks' should not be private ++Test method 'nestedPublicTest' should not be public +Lifecycle method 'publicBeforeAll' should not be public +Lifecycle method 'publicBeforeEach' should not be public +Lifecycle method 'publicAfterAll' should not be public diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java new file mode 100644 index 00000000..8799aae3 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jspecify.annotations.Nullable; + +/** + * This is a valid example. + * + * @author Phillip Webb + */ +public class AnnotationOnNewLine { + + @Override + public String toString() { + return ""; + } + + @Nullable String test1() { + return ""; + } + + @Override + @Nullable String test2() { + return ""; + } + + @Override + public @Nullable String test3() { + return ""; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java index e9b91697..9c59c587 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java @@ -88,4 +88,19 @@ private void doSomethingElseWithTemplateWorks() { // test here } + @Nested + public static class PublicNestedTests { + + @Test + public void nestedPublicTest() { + + } + + } + + @Nested + private static class PrivateNestedTests { + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java new file mode 100644 index 00000000..d56bbbd6 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.junit.jupiter.api.Test; + +/** + * This is a valid example. We allow abstract test classes to be + * public so that classes in other packages can extend them. + * + * @author Andy Wilkinson + */ +public abstract class JUnit5PublicAbstractIsValid { + + @Test + void doSomethingWorks() { + // test here + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java index cc7b4cd0..bad7023d 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ * * @author Phillip Webb */ -public class JUnit5Valid { +class JUnit5Valid { @Test void doSomethingWorks() { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java new file mode 100644 index 00000000..e9e27b7b --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Leading whitepace with a text block. + * + * @author Phillip Webb + */ +public class LeadingWhitespaceTabsAndTextBlock { + + /** + * Comments are ignored. + */ + public void hello() { + System.out.println("""" + Hello + World!"""); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java new file mode 100644 index 00000000..7579aac2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is an annotation with a legal name. Only test classes must + * have a name that ends with {@code Tests}. + * + * @author Andy Wilkinson + */ +public @interface AnnotationEndingInTest { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java new file mode 100644 index 00000000..b2aad5f9 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is an interface with a legal name. Only test classes must + * have a name that ends with {@code Tests}. + * + * @author Andy Wilkinson + */ +public interface InterfaceEndingInTest { + +} diff --git a/spring-javaformat/spring-javaformat-config/pom.xml b/spring-javaformat/spring-javaformat-config/pom.xml index c29dccfd..72fe7b7b 100644 --- a/spring-javaformat/spring-javaformat-config/pom.xml +++ b/spring-javaformat/spring-javaformat-config/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-config Spring JavaFormat Config diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java index 90bde24a..492f068c 100644 --- a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,8 +29,8 @@ public enum JavaBaseline { V8, /** - * Use JDK 11+ or higher compatible formatter. + * Use JDK 17+ or higher compatible formatter. */ - V11 + V17 } diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java index 300fcce1..89d19b78 100644 --- a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public interface JavaFormatConfig { /** * The default {@link JavaFormatConfig}. */ - JavaFormatConfig DEFAULT = of(JavaBaseline.V11, IndentationStyle.TABS); + JavaFormatConfig DEFAULT = of(JavaBaseline.V17, IndentationStyle.TABS); /** * Java JDK baseline version expected be used when formatting. diff --git a/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java index 135e9e0e..4fc21f26 100644 --- a/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java +++ b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ class PropertiesJavaFormatConfigTests { void getJavaBaselineWhenNoPropertyReturnsJava11() { Properties properties = new Properties(); PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties); - assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V11); + assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V17); } @Test diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF similarity index 78% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/META-INF/MANIFEST.MF rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF index 265335f9..f3b70674 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/META-INF/MANIFEST.MF +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF @@ -1,8 +1,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Spring Formatter Eclipse Runtime JDK11 -Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk11 -Bundle-Version: 0.0.40.qualifier +Bundle-Name: Spring Formatter Eclipse Runtime JDK17 +Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk17 +Bundle-Version: 0.0.47.qualifier Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)", org.eclipse.jface;bundle-version="[1.0.0,10.0.0)", org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/build.properties b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties similarity index 100% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/build.properties rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml similarity index 90% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/pom.xml rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml index 06ae09e3..cd3752e1 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk11/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml @@ -6,11 +6,11 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT - spring-javaformat-formatter-eclipse-jdk11 + spring-javaformat-formatter-eclipse-jdk17 eclipse-plugin - Spring JavaFormat Eclipse JDK-11 + Spring JavaFormat Eclipse JDK-17 ${basedir}/../.. org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source @@ -23,13 +23,29 @@ - eclipse-jdk11 + eclipse-jdk17 p2 - ${eclipse.jdk11.repository} + ${eclipse.jdk17.repository} + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + + org.apache.maven.plugins maven-antrun-plugin diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF index 438832d3..652b5065 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Spring Formatter Eclipse JDK8 Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk8 -Bundle-Version: 0.0.40.qualifier +Bundle-Version: 0.0.47.qualifier Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)", org.eclipse.jface;bundle-version="[1.0.0,10.0.0)", org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml index c0b49d6c..f22c974e 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-eclipse-jdk8 eclipse-plugin @@ -30,6 +30,22 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + + org.apache.maven.plugins maven-antrun-plugin diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml similarity index 85% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/pom.xml rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml index 88c061e4..8621592f 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml @@ -6,17 +6,17 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT - spring-javaformat-formatter-eclipse-jdt-jdk11 - Spring JavaFormat Eclipse JDT JDK-11 + spring-javaformat-formatter-eclipse-jdt-jdk17 + Spring JavaFormat Eclipse JDT JDK-17 ${basedir}/../.. io.spring.javaformat - spring-javaformat-formatter-eclipse-jdk11 + spring-javaformat-formatter-eclipse-jdk17 ${project.version} true @@ -48,7 +48,7 @@ - io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk11 + io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk17 org/eclipse/jdt/** @@ -57,7 +57,7 @@ org.eclipse.jdt - io.spring.javaformat.eclipse.jdt.jdk11 + io.spring.javaformat.eclipse.jdt.jdk17 false diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java similarity index 98% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java index 60b0e6e1..46e0f01d 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java similarity index 95% rename from spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java index 9873fc96..df66cda6 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk11/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ enum Phase { /** * Apply the preparator after wrapping. */ - POST_WRAPPING; + POST_WRAPPING } diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml index 98b380f7..0689734b 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-eclipse-jdt-jdk8 Spring JavaFormat Eclipse JDT JDK-8 diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java index 9873fc96..df66cda6 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ enum Phase { /** * Apply the preparator after wrapping. */ - POST_WRAPPING; + POST_WRAPPING } diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml index 655863ec..306b6166 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-eclipse-rewriter Spring JavaFormat Eclipse Rewriter diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java index 60aad783..e7ccea52 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,7 +80,7 @@ private void rewrite(JdkVersion jdkVersion, FileSystem zip) throws IOException { deleteWrapPreparator(zip); } else { - rewrite(zip, "org/eclipse/osgi/util/NLS.class", NlsJdk11Manipulator::new); + rewrite(zip, "org/eclipse/osgi/util/NLS.class", NlsJdk17Manipulator::new); } } @@ -111,12 +111,12 @@ public static void main(String[] args) throws Exception { private static class DefaultCodeFormatterManipulator extends ClassVisitor { DefaultCodeFormatterManipulator(ClassVisitor visitor) { - super(Opcodes.ASM7, visitor); + super(Opcodes.ASM9, visitor); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - if (access == Opcodes.ACC_PRIVATE && UPDATED_FIELDS.contains(name)) { + if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_FIELDS.contains(name)) { access = Opcodes.ACC_PROTECTED; } return super.visitField(access, name, desc, signature, value); @@ -124,7 +124,7 @@ public FieldVisitor visitField(int access, String name, String desc, String sign @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (access == Opcodes.ACC_PRIVATE && UPDATED_METHODS.contains(name)) { + if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_METHODS.contains(name)) { access = Opcodes.ACC_PROTECTED; } return new DefaultCodeFormatterMethodManipulator( @@ -140,7 +140,7 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si private static class DefaultCodeFormatterMethodManipulator extends MethodVisitor { DefaultCodeFormatterMethodManipulator(MethodVisitor mv) { - super(Opcodes.ASM7, mv); + super(Opcodes.ASM9, mv); } @Override @@ -160,7 +160,7 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, private static class NlsJdk8Manipulator extends ClassVisitor { NlsJdk8Manipulator(ClassVisitor visitor) { - super(Opcodes.ASM7, visitor); + super(Opcodes.ASM9, visitor); } @Override @@ -182,7 +182,7 @@ private static class NslJdk8MethodManipulator extends MethodVisitor { private final MethodVisitor methodVisitor; NslJdk8MethodManipulator(MethodVisitor mv) { - super(Opcodes.ASM7, null); + super(Opcodes.ASM9, null); this.methodVisitor = mv; } @@ -202,16 +202,16 @@ public void visitEnd() { * {@link ClassVisitor} to update the {@code NLS} class in the JDK 8 version so it * doesn't use a System property to disable warning messages. */ - private static class NlsJdk11Manipulator extends ClassVisitor { + private static class NlsJdk17Manipulator extends ClassVisitor { - NlsJdk11Manipulator(ClassVisitor visitor) { - super(Opcodes.ASM7, visitor); + NlsJdk17Manipulator(ClassVisitor visitor) { + super(Opcodes.ASM9, visitor); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if ("".equals(name)) { - return new NslJdk11MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions)); + return new NslJdk17MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions)); } return super.visitMethod(access, name, desc, signature, exceptions); } @@ -222,12 +222,12 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si * {@link MethodVisitor} to update the {@code NLS} class in the JDK 8 version so it * doesn't use a System property to disable warning messages. */ - private static class NslJdk11MethodManipulator extends MethodVisitor { + private static class NslJdk17MethodManipulator extends MethodVisitor { private final MethodVisitor methodVisitor; - NslJdk11MethodManipulator(MethodVisitor mv) { - super(Opcodes.ASM7, null); + NslJdk17MethodManipulator(MethodVisitor mv) { + super(Opcodes.ASM9, null); this.methodVisitor = mv; } diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml index 12989051..73007642 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-eclipse-runtime Spring JavaFormat Eclipse Runtime diff --git a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml index 6222dd58..5476a0c9 100644 --- a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-shaded Spring JavaFormat Formatter Shaded diff --git a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml index fc4b092a..0648a5b4 100644 --- a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-shader Spring JavaFormat Formatter Shader diff --git a/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml index 203a96a0..e34149fe 100644 --- a/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-test-support Spring JavaFormat Formatter Test Support diff --git a/spring-javaformat/spring-javaformat-formatter-tests/pom.xml b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml index a50507a4..ce9bf2a2 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml @@ -6,13 +6,13 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter-tests Spring JavaFormat Formatter Tests ${basedir}/../.. - 11 + 17 diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java index bf873dd2..f2bebe0a 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import io.spring.javaformat.config.JavaBaseline; @@ -60,6 +61,7 @@ protected static Item[] items(String expectedOverride) { addItem(items, javaBaseline, source, expected, config); } } + items.sort(Comparator.comparing(Item::getName)); return items.toArray(new Item[0]); } @@ -139,6 +141,10 @@ private JavaFormatConfig loadConfig(JavaBaseline javaBaseline, File configFile) return JavaFormatConfig.of(javaBaseline, config.getIndentationStyle()); } + String getName() { + return this.source.getName(); + } + public File getSource() { return this.source; } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java index 88d41505..4639a550 100644 --- a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,16 +54,16 @@ void formatCodeWithV8BaselineCanFormatOnAllVersions(String version) throws Excep } @ParameterizedTest - @ValueSource(strings = { "11", "17" }) + @ValueSource(strings = { "17" }) void formatCodeWithV11BaselineCanFormatOn11OrHigher(String version) throws Exception { - runFormatter(JavaBaseline.V11, version); + runFormatter(JavaBaseline.V17, version); } @ParameterizedTest @ValueSource(strings = "8") void formatCodeWithV11BaselineCannotFormatOn8(String version) throws Exception { assertThatExceptionOfType(ContainerLaunchException.class) - .isThrownBy(() -> runFormatter(JavaBaseline.V11, version)); + .isThrownBy(() -> runFormatter(JavaBaseline.V17, version)); } private void runFormatter(JavaBaseline baseline, String version) throws IOException, Exception { diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt new file mode 100644 index 00000000..157ea11b --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt @@ -0,0 +1,8 @@ +/** + * This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. + * @formatter:off + * @formatter:on + */ +public class Format { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt new file mode 100644 index 00000000..dbdb1f45 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt @@ -0,0 +1,23 @@ +package example; + +import com.example.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable + String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt new file mode 100644 index 00000000..053cbc13 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt @@ -0,0 +1,22 @@ +package example; + +import org.jspecify.annotations.*; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt new file mode 100644 index 00000000..b3e8f925 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt @@ -0,0 +1,29 @@ +package example; + +import org.jspecify.annotations.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable ... varargs); + + default Object inBody() { + @Nullable Object[] args = new Object[length]; + @Nullable List<@Nullable Object> list = new Object[length]; + Object @Nullable [] moreArgs = new Object[length]; + return args; + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v11/record-with-generic.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v17/record-with-generic.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v11/record-with-generic.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v17/record-with-generic.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt new file mode 100644 index 00000000..dbfef5c0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt @@ -0,0 +1,7 @@ +/** + * This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. + * @formatter:off + * @formatter:on + */ +public class Format { +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt new file mode 100644 index 00000000..011a2189 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt @@ -0,0 +1,20 @@ +package example; + +import com.example.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt new file mode 100644 index 00000000..11c65198 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt @@ -0,0 +1,20 @@ +package example; + +import org.jspecify.annotations.*; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt new file mode 100644 index 00000000..acbefead --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt @@ -0,0 +1,27 @@ +package example; + +import org.jspecify.annotations.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + + default Object inBody() { + @Nullable Object[] args = new Object[length]; + @Nullable List<@Nullable Object> list = new Object[length]; + Object @Nullable [] moreArgs = new Object[length]; + return args; + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/pom.xml b/spring-javaformat/spring-javaformat-formatter/pom.xml index fc5611c1..24b89552 100644 --- a/spring-javaformat/spring-javaformat-formatter/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.40-SNAPSHOT + 0.0.47-SNAPSHOT spring-javaformat-formatter Spring JavaFormat Formatter @@ -27,7 +27,7 @@ io.spring.javaformat - spring-javaformat-formatter-eclipse-jdt-jdk11 + spring-javaformat-formatter-eclipse-jdt-jdk17 ${project.version} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java index 53415a7a..dd87b20c 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import io.spring.javaformat.config.JavaBaseline; import io.spring.javaformat.config.JavaFormatConfig; import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter; -import io.spring.javaformat.formatter.jdk11.eclipse.EclipseJdk11CodeFormatter; +import io.spring.javaformat.formatter.jdk17.eclipse.EclipseJdk17CodeFormatter; import io.spring.javaformat.formatter.jdk8.eclipse.EclipseJdk8CodeFormatter; /** @@ -76,7 +76,7 @@ public Formatter() { */ public Formatter(JavaFormatConfig javaFormatConfig) { this.delegate = javaFormatConfig.getJavaBaseline() == JavaBaseline.V8 - ? new EclipseJdk8CodeFormatter(javaFormatConfig) : new EclipseJdk11CodeFormatter(javaFormatConfig); + ? new EclipseJdk8CodeFormatter(javaFormatConfig) : new EclipseJdk17CodeFormatter(javaFormatConfig); } /** diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/CodeLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java similarity index 77% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/CodeLineBreakPreparator.java rename to spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java index 15057474..51c98b52 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/CodeLineBreakPreparator.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,21 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.jdk11.eclipse; +package io.spring.javaformat.formatter.jdk17.eclipse; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.ASTNode; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.ASTVisitor; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.AbstractTypeDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.AnnotationTypeDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.EnumDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.FieldDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.SimpleName; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.TypeDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.formatter.CodeFormatter; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.compiler.parser.TerminalTokens; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.Preparator; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.Token; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.TokenManager; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AnnotationTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.EnumDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.FieldDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.SimpleName; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; /** * {@link Preparator} to finetune curly-brace line breaks. diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/EclipseJdk11CodeFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java similarity index 68% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/EclipseJdk11CodeFormatter.java rename to spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java index e4d57dc5..b902e3f3 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/EclipseJdk11CodeFormatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,35 +14,36 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.jdk11.eclipse; +package io.spring.javaformat.formatter.jdk17.eclipse; import java.util.Map; import io.spring.javaformat.config.JavaFormatConfig; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.ExtendedCodeFormatter; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.ExtendedCodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter; import io.spring.javaformat.formatter.eclipse.Options; /** - * Internal delegate JDK 11 baseline {@link EclipseCodeFormatter} to apply Spring + * Internal delegate JDK 17 baseline {@link EclipseCodeFormatter} to apply Spring * {@literal formatter.prefs} and add {@link Preparator Preparators}. * * @author Phillip Webb */ -public class EclipseJdk11CodeFormatter extends ExtendedCodeFormatter implements EclipseCodeFormatter { +public class EclipseJdk17CodeFormatter extends ExtendedCodeFormatter implements EclipseCodeFormatter { private final Map appliedOptions; - public EclipseJdk11CodeFormatter(JavaFormatConfig javaFormatConfig) { - this(new Options("io.spring.javaformat.eclipse.jdt.jdk11").load(javaFormatConfig)); + public EclipseJdk17CodeFormatter(JavaFormatConfig javaFormatConfig) { + this(new Options("io.spring.javaformat.eclipse.jdt.jdk17").load(javaFormatConfig)); } - EclipseJdk11CodeFormatter(Map options) { + EclipseJdk17CodeFormatter(Map options) { super(options); this.appliedOptions = options; addPreparator(new JavadocLineBreakPreparator()); addPreparator(new CodeLineBreakPreparator()); + addPreparator(new JSpecifyPreparator()); } @Override diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java new file mode 100644 index 00000000..645bf75d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java @@ -0,0 +1,140 @@ +/* + * Copyright 2017-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk17.eclipse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Annotation; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.IExtendedModifier; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ImportDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.MethodDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.SingleVariableDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.VariableDeclarationStatement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; + +public class JSpecifyPreparator implements Preparator { + + private static final String PACKAGE_NAME = "org.jspecify.annotations"; + + private static final Set ANNOTATION_NAMES = new HashSet<>( + Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked")); + + private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream() + .map((annotationName) -> PACKAGE_NAME + "." + annotationName) + .collect(Collectors.toSet()); + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + astRoot.accept(visitor); + } + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + private final Map fullyQualified = new HashMap<>(); + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(CompilationUnit node) { + this.fullyQualified.clear(); + return super.visit(node); + } + + @Override + public boolean visit(ImportDeclaration node) { + String name = node.getName().toString(); + if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) { + Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES + : Collections.singleton(name.substring(name.lastIndexOf(".") + 1)); + for (String annotationName : annotationNames) { + this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName); + } + } + return super.visit(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public void endVisit(SingleVariableDeclaration node) { + if (node.isVarargs()) { + List annotations = node.varargsAnnotations(); + Annotation lastAnnotation = getLastAnnotation(annotations); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).spaceAfter(); + } + } + } + + @SuppressWarnings("unchecked") + private void clearLineBreaksIfHasJSpecifyAnnotation(List modifiers) { + Annotation lastAnnotation = getLastAnnotation((List) modifiers); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter(); + } + } + + private Annotation getLastAnnotation(List modifiers) { + Annotation annotation = null; + for (IExtendedModifier modifier : modifiers) { + if (!modifier.isAnnotation()) { + return annotation; + } + annotation = (Annotation) modifier; + } + return annotation; + } + + private boolean isJSpecifyAnnotation(Annotation annotation) { + String fullyQualifiedName = (annotation != null) + ? this.fullyQualified.get(annotation.getTypeName().toString()) : null; + return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/JavadocLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java similarity index 74% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/JavadocLineBreakPreparator.java rename to spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java index e367de90..b66efa27 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk11/eclipse/JavadocLineBreakPreparator.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,25 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.jdk11.eclipse; +package io.spring.javaformat.formatter.jdk17.eclipse; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.ASTNode; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.ASTVisitor; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.AbstractTypeDeclaration; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.Comment; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.CompilationUnit; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.Javadoc; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.TagElement; -import io.spring.javaformat.eclipse.jdt.jdk11.core.dom.TextElement; -import io.spring.javaformat.eclipse.jdt.jdk11.core.formatter.CodeFormatter; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.compiler.parser.TerminalTokens; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.Preparator; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.Token; -import io.spring.javaformat.eclipse.jdt.jdk11.internal.formatter.TokenManager; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Comment; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Javadoc; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TagElement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TextElement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; /** * {@link Preparator} to finetune Javadoc whitespace. @@ -93,7 +93,8 @@ private static class Vistor extends ASTVisitor { public boolean visit(Javadoc node) { int commentIndex = this.tokenManager.firstIndexIn(node, TerminalTokens.TokenNameCOMMENT_JAVADOC); Token commentToken = this.tokenManager.get(commentIndex); - this.commentTokenManager = new TokenManager(commentToken.getInternalStructure(), this.tokenManager); + this.commentTokenManager = (commentToken.getInternalStructure() != null) + ? new TokenManager(commentToken.getInternalStructure(), this.tokenManager) : null; this.declaration = node.getParent(); this.firstTagElement = true; this.hasText = false; @@ -108,7 +109,7 @@ public boolean visit(TextElement node) { @Override public boolean visit(TagElement node) { - if (isSquashRequired(node, this.declaration)) { + if (this.commentTokenManager != null && isSquashRequired(node, this.declaration)) { int startIndex = this.commentTokenManager.findIndex(node.getStartPosition(), -1, false); Token token = this.commentTokenManager.get(startIndex); token.clearLineBreaksBefore(); diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java index 7b747cd2..fa365db4 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import io.spring.javaformat.formatter.eclipse.Options; /** - * Internal delegate JDK 11 baseline {@link EclipseCodeFormatter} to apply Spring + * Internal delegate JDK 8 baseline {@link EclipseCodeFormatter} to apply Spring * {@literal formatter.prefs} and add {@link Preparator Preparators}. * * @author Phillip Webb @@ -43,6 +43,7 @@ public EclipseJdk8CodeFormatter(JavaFormatConfig javaFormatConfig) { this.appliedOptions = options; addPreparator(new JavadocLineBreakPreparator()); addPreparator(new CodeLineBreakPreparator()); + addPreparator(new JSpecifyPreparator()); } @Override diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java new file mode 100644 index 00000000..4bc1aa0e --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java @@ -0,0 +1,140 @@ +/* + * Copyright 2017-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk8.eclipse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.Annotation; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.IExtendedModifier; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ImportDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.MethodDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.SingleVariableDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.VariableDeclarationStatement; +import io.spring.javaformat.eclipse.jdt.jdk8.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.TokenManager; + +public class JSpecifyPreparator implements Preparator { + + private static final String PACKAGE_NAME = "org.jspecify.annotations"; + + private static final Set ANNOTATION_NAMES = new HashSet<>( + Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked")); + + private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream() + .map((annotationName) -> PACKAGE_NAME + "." + annotationName) + .collect(Collectors.toSet()); + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + astRoot.accept(visitor); + } + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + private final Map fullyQualified = new HashMap<>(); + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(CompilationUnit node) { + this.fullyQualified.clear(); + return super.visit(node); + } + + @Override + public boolean visit(ImportDeclaration node) { + String name = node.getName().toString(); + if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) { + Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES + : Collections.singleton(name.substring(name.lastIndexOf(".") + 1)); + for (String annotationName : annotationNames) { + this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName); + } + } + return super.visit(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public void endVisit(SingleVariableDeclaration node) { + if (node.isVarargs()) { + List annotations = node.varargsAnnotations(); + Annotation lastAnnotation = getLastAnnotation(annotations); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).spaceAfter(); + } + } + } + + @SuppressWarnings("unchecked") + private void clearLineBreaksIfHasJSpecifyAnnotation(List modifiers) { + Annotation lastAnnotation = getLastAnnotation((List) modifiers); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter(); + } + } + + private Annotation getLastAnnotation(List modifiers) { + Annotation annotation = null; + for (IExtendedModifier modifier : modifiers) { + if (!modifier.isAnnotation()) { + return annotation; + } + annotation = (Annotation) modifier; + } + return annotation; + } + + private boolean isJSpecifyAnnotation(Annotation annotation) { + String fullyQualifiedName = (annotation != null) + ? this.fullyQualified.get(annotation.getTypeName().toString()) : null; + return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java index 68723201..3a4a5f41 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 the original author or authors. + * Copyright 2017-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -93,7 +93,8 @@ private static class Vistor extends ASTVisitor { public boolean visit(Javadoc node) { int commentIndex = this.tokenManager.firstIndexIn(node, TerminalTokens.TokenNameCOMMENT_JAVADOC); Token commentToken = this.tokenManager.get(commentIndex); - this.commentTokenManager = new TokenManager(commentToken.getInternalStructure(), this.tokenManager); + this.commentTokenManager = (commentToken.getInternalStructure() != null) + ? new TokenManager(commentToken.getInternalStructure(), this.tokenManager) : null; this.declaration = node.getParent(); this.firstTagElement = true; this.hasText = false; @@ -108,7 +109,7 @@ public boolean visit(TextElement node) { @Override public boolean visit(TagElement node) { - if (isSquashRequired(node, this.declaration)) { + if (this.commentTokenManager != null && isSquashRequired(node, this.declaration)) { int startIndex = this.commentTokenManager.findIndex(node.getStartPosition(), -1, false); Token token = this.commentTokenManager.get(startIndex); token.clearLineBreaksBefore(); diff --git a/src/checkstyle/checkstyle.xml b/src/checkstyle/checkstyle.xml index 0c6b5e96..c13faf85 100644 --- a/src/checkstyle/checkstyle.xml +++ b/src/checkstyle/checkstyle.xml @@ -65,6 +65,7 @@ +