diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 844e5d0..b45bdbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,13 @@ ## JBIJPPTPL name: Build -on: [push, pull_request] +on: + # Trigger the workflow on pushes to only the 'master' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) + push: + branches: [master] + # Trigger the workflow on any pull request + pull_request: + jobs: # Run Gradle Wrapper Validation Action to verify the wrapper's checksum @@ -25,7 +31,7 @@ jobs: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 # Validate wrapper - name: Gradle Wrapper Validation @@ -38,39 +44,52 @@ jobs: runs-on: ubuntu-latest steps: + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v2.3.4 + # Setup Java 11 environment for the next steps - name: Setup Java uses: actions/setup-java@v2 with: - distribution: "temurin" + distribution: zulu java-version: 11 + cache: gradle - # Check out current repository - - name: Fetch Sources - uses: actions/checkout@v2 + # Set environment variables + - name: Export Properties + id: properties + shell: bash + run: | + PROPERTIES="$(./gradlew properties --console=plain -q)" + IDE_VERSIONS="$(echo "$PROPERTIES" | grep "^pluginVerifierIdeVersions:" | base64)" - # Cache Gradle dependencies - - name: Setup Gradle Dependencies Cache - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle', '**/*.gradle.kts', 'gradle.properties') }} + echo "::set-output name=ideVersions::$IDE_VERSIONS" + echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" - # Cache Gradle Wrapper - - name: Setup Gradle Wrapper Cache + # Cache Plugin Verifier IDEs + - name: Setup Plugin Verifier IDEs Cache uses: actions/cache@v2.1.6 with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides + key: ${{ runner.os }}-plugin-verifier-${{ steps.properties.outputs.ideVersions }} + + # Run Qodana inspections + - name: Qodana - Code Inspection + uses: JetBrains/qodana-action@v2.1-eap - # Run detekt, ktlint and tests - - name: Run Linters and Test - run: ./gradlew check + # Run tests + - name: Run Tests + run: ./gradlew test # Run verifyPlugin Gradle task - name: Verify Plugin run: ./gradlew verifyPlugin + # Run IntelliJ Plugin Verifier action using GitHub Action + - name: Run Plugin Verifier + run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} + # Build plugin with buildPlugin Gradle task and provide the artifact for the next workflow jobs # Requires test job to be passed build: @@ -78,35 +97,21 @@ jobs: needs: test runs-on: ubuntu-latest outputs: - name: ${{ steps.properties.outputs.name }} version: ${{ steps.properties.outputs.version }} changelog: ${{ steps.properties.outputs.changelog }} - artifact: ${{ steps.properties.outputs.artifact }} steps: - # Setup Java 11 environment for the next steps - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 11 - # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2 - - # Cache Gradle Dependencies - - name: Setup Gradle Dependencies Cache - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle', '**/*.gradle.kts', 'gradle.properties') }} + uses: actions/checkout@v2.3.4 - # Cache Gradle Wrapper - - name: Setup Gradle Wrapper Cache - uses: actions/cache@v2.1.6 + # Setup Java 11 environment for the next steps + - name: Setup Java + uses: actions/setup-java@v2 with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + distribution: zulu + java-version: 11 + cache: gradle # Set environment variables - name: Export Properties @@ -115,133 +120,55 @@ jobs: run: | PROPERTIES="$(./gradlew properties --console=plain -q)" VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" - NAME="$(echo "$PROPERTIES" | grep "^pluginName_:" | cut -f2- -d ' ')" + NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" CHANGELOG="${CHANGELOG//'%'/'%25'}" CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - ARTIFACT="${NAME}-${VERSION}.zip" echo "::set-output name=version::$VERSION" echo "::set-output name=name::$NAME" echo "::set-output name=changelog::$CHANGELOG" - echo "::set-output name=artifact::$ARTIFACT" # Build artifact using buildPlugin Gradle task - name: Build Plugin run: ./gradlew buildPlugin - # Upload plugin artifact to make it available in the next jobs - - name: Upload artifact + # Store built plugin as an artifact for downloading + - name: Upload artifacts uses: actions/upload-artifact@v2.2.4 with: - name: plugin-artifact - path: ./build/distributions/${{ needs.build.outputs.artifact }} - - # Verify built plugin using IntelliJ Plugin Verifier tool - # Requires build job to be passed - verify: - name: Verify - needs: build - runs-on: ubuntu-latest - steps: - - # Setup Java 11 environment for the next steps - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 11 - - # Check out current repository - - name: Fetch Sources - uses: actions/checkout@v2 - - # Cache Gradle Dependencies - - name: Setup Gradle Dependencies Cache - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle', '**/*.gradle.kts', 'gradle.properties') }} - - # Cache Gradle Wrapper - - name: Setup Gradle Wrapper Cache - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - # Set environment variables - - name: Export Properties - id: properties - shell: bash - run: | - PROPERTIES="$(./gradlew properties --console=plain -q)" - IDE_VERSIONS="$(echo "$PROPERTIES" | grep "^pluginVerifierIdeVersions:" | base64)" - - echo "::set-output name=ideVersions::$IDE_VERSIONS" - echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" - - # Cache Plugin Verifier IDEs - - name: Setup Plugin Verifier IDEs Cache - uses: actions/cache@v2.1.6 - with: - path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides - key: ${{ runner.os }}-plugin-verifier-${{ steps.properties.outputs.ideVersions }} - - # Run IntelliJ Plugin Verifier action using GitHub Action - - name: Verify Plugin - run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} + name: "${{ steps.properties.outputs.name }} - ${{ steps.properties.outputs.version }}" + path: ./build/distributions/* # Prepare a draft release for GitHub Releases page for the manual verification # If accepted and published, release workflow would be triggered releaseDraft: name: Release Draft if: github.event_name != 'pull_request' - needs: [build, verify] + needs: build runs-on: ubuntu-latest steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2 + uses: actions/checkout@v2.3.4 # Remove old release drafts by using the curl request for the available releases with draft flag - name: Remove Old Release Drafts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/repos/$GITHUB_REPOSITORY/releases \ - | tr '\r\n' ' ' \ - | jq '.[] | select(.draft == true) | .id' \ - | xargs -I '{}' \ - curl -X DELETE -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/repos/$GITHUB_REPOSITORY/releases/{} + gh api repos/{owner}/{repo}/releases \ + --jq '.[] | select(.draft == true) | .id' \ + | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} # Create new release draft - which is not publicly visible and requires manual acceptance - name: Create Release Draft - id: createDraft - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ needs.build.outputs.version }} - release_name: v${{ needs.build.outputs.version }} - body: ${{ needs.build.outputs.changelog }} - draft: true - - # Download plugin artifact provided by the previous job - - name: Download Artifact - uses: actions/download-artifact@v2 - with: - name: plugin-artifact - - # Upload artifact as a release asset - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.createDraft.outputs.upload_url }} - asset_path: ./${{ needs.build.outputs.artifact }} - asset_name: ${{ needs.build.outputs.artifact }} - asset_content_type: application/zip \ No newline at end of file + run: | + gh release create v${{ needs.build.outputs.version }} \ + --draft \ + --title "v${{ needs.build.outputs.version }}" \ + --notes "${{ needs.build.outputs.changelog }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 15112c0..bea6935 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,5 @@ # GitHub Actions Workflow created for handling the release process based on the draft release prepared -# with the Build workflow. Running the publishPlugin task requires the INTELLIJ_PUBLISH_TOKEN secret provided. +# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. name: Release on: @@ -14,57 +14,56 @@ jobs: runs-on: ubuntu-latest steps: + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v2.3.4 + with: + ref: ${{ github.event.release.tag_name }} + # Setup Java 11 environment for the next steps - name: Setup Java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: + distribution: zulu java-version: 11 + cache: gradle - # Check out current repository - - name: Fetch Sources - uses: actions/checkout@v2 - with: - ref: ${{ github.event.release.tag_name }} + # Update Unreleased section with the current release note + - name: Patch Changelog + run: | + ./gradlew patchChangelog --release-note="`cat << EOM + ${{ github.event.release.body }} + EOM`" # Publish the plugin to the Marketplace - name: Publish Plugin env: - PUBLISH_TOKEN: ${{ secrets.INTELLIJ_PUBLISH_TOKEN }} + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} run: ./gradlew publishPlugin - # Patch changelog, commit and push to the current repository - changelog: - name: Update Changelog - needs: release - runs-on: ubuntu-latest - steps: - - # Setup Java 11 environment for the next steps - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 11 + # Upload artifact as a release asset + - name: Upload Release Asset + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* - # Check out current repository - - name: Fetch Sources - uses: actions/checkout@v2 - with: - ref: ${{ github.event.release.tag_name }} + # Create pull request + - name: Create Pull Request + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${{ github.event.release.tag_name }}" + BRANCH="changelog-update-$VERSION" - # Update Unreleased section with the current version - - name: Patch Changelog - run: ./gradlew patchChangelog + git config user.email "action@github.com" + git config user.name "GitHub Action" - # Commit patched Changelog - - name: Commit files - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git commit -m "Update changelog" -a + git checkout -b $BRANCH + git commit -am "Changelog update - $VERSION" + git push --set-upstream origin $BRANCH - # Push changes - - name: Push changes - uses: ad-m/github-push-action@master - with: - branch: master - github_token: ${{ secrets.GITHUB_TOKEN }} + gh pr create \ + --title "Changelog update - \`$VERSION\`" \ + --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ + --base master \ + --head $BRANCH diff --git a/.github/workflows/run-ui-tests.yml b/.github/workflows/run-ui-tests.yml new file mode 100644 index 0000000..f549056 --- /dev/null +++ b/.github/workflows/run-ui-tests.yml @@ -0,0 +1,60 @@ +# GitHub Actions Workflow created for launching UI tests on Linux, Windows, and Mac in the following steps: +# - prepare and launch Idea with your plugin and robot-server plugin, which is need to interact with UI +# - wait for the Idea started +# - run UI tests with separate Gradle task +# +# Please check https://github.com/JetBrains/intellij-ui-test-robot for information about UI tests with IntelliJ IDEA. +# +# Workflow is triggered manually. + +name: Run UI Tests +on: + workflow_dispatch + +jobs: + + testUI: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + runIde: | + export DISPLAY=:99.0 + Xvfb -ac :99 -screen 0 1920x1080x16 & + gradle runIdeForUiTests & + - os: windows-latest + runIde: start gradlew.bat runIdeForUiTests + - os: macos-latest + runIde: ./gradlew runIdeForUiTests & + + steps: + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v2.3.4 + + # Setup Java 11 environment for the next steps + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: zulu + java-version: 11 + cache: gradle + + # Run IDEA prepared for UI testing + - name: Run IDE + run: ${{ matrix.runIde }} + + # Wait for IDEA to be started + - name: Health Check + uses: jtalk/url-health-check-action@v1.5 + with: + url: http://127.0.0.1:8082 + max-attempts: 15 + retry-delay: 30s + + # Run tests + - name: Tests + run: ./gradlew test diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ccc7b..9286215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,9 @@ # JCV Changelog ## [Unreleased] -### Added - -### Changed - -### Deprecated - -### Removed - ### Fixed +- Replacement suggestions popup appears now on IntelliJ Platform 2021.2 -### Security ## [3.0.1] ### Fixed - Remove "untilBuild" IntelliJ version from plugin description to extends compatibility with recent versions diff --git a/build.gradle.kts b/build.gradle.kts index b5a6e2a..1f287a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,48 +1,32 @@ -import io.gitlab.arturbosch.detekt.Detekt import org.jetbrains.changelog.markdownToHTML import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +fun properties(key: String) = project.findProperty(key).toString() + plugins { - kotlin("jvm") version "1.4.21" - // gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin - id("org.jetbrains.intellij") version "1.1.2" - // gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin - id("org.jetbrains.changelog") version "0.6.2" - // detekt linter - read more: https://detekt.github.io/detekt/gradle.html - id("io.gitlab.arturbosch.detekt") version "1.15.0" - // ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle - id("org.jlleitschuh.gradle.ktlint") version "9.4.1" + // Java support + id("java") + // Kotlin support + id("org.jetbrains.kotlin.jvm") version "1.5.30" + // Gradle IntelliJ Plugin + id("org.jetbrains.intellij") version "1.1.6" + // Gradle Changelog Plugin + id("org.jetbrains.changelog") version "1.3.0" + // Gradle Qodana Plugin + id("org.jetbrains.qodana") version "0.1.12" } -// Import variables from gradle.properties file -val pluginGroup: String by project -// `pluginName_` variable ends with `_` because of the collision with Kotlin magic getter in the `intellij` closure. -// Read more about the issue: https://github.com/JetBrains/intellij-platform-plugin-template/issues/29 -val pluginName_: String by project -val pluginDescription: String by project -val pluginVersion: String by project -val pluginSinceBuild: String by project -val pluginUntilBuild: String by project -val pluginVerifierIdeVersions: String by project - -val platformType: String by project -val platformVersion: String by project -val platformPlugins: String by project -val platformDownloadSources: String by project - -group = pluginGroup -description = pluginDescription -version = pluginVersion +group = properties("pluginGroup") +version = properties("pluginVersion") // Configure project's dependencies repositories { mavenCentral() - jcenter() + maven("https://repo1.maven.org/maven2/") + //jcenter() } dependencies { - detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:${property("detekt-formatting.version")}") - implementation("org.apache.commons:commons-text:${property("commons-text.version")}") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:${property("jackson-module-kotlin.version")}") @@ -54,108 +38,114 @@ dependencies { testRuntimeOnly("org.junit.vintage:junit-vintage-engine:${property("junit.version")}") } -// Configure gradle-intellij-plugin plugin. -// Read more: https://github.com/JetBrains/gradle-intellij-plugin +// Configure Gradle IntelliJ Plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin intellij { - pluginName.set(pluginName_) - version.set(platformVersion) - type.set(platformType) - downloadSources.set(platformDownloadSources.toBoolean()) + pluginName.set(properties("pluginName")) + version.set(properties("platformVersion")) + type.set(properties("platformType")) + downloadSources.set(properties("platformDownloadSources").toBoolean()) updateSinceUntilBuild.set(true) // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. - plugins.set(platformPlugins.split(',').map(String::trim).filter(String::isNotEmpty)) + plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty)) } sourceSets["main"].java.srcDirs("src/main/gen") -// Configure detekt plugin. -// Read more: https://detekt.github.io/detekt/kotlindsl.html -detekt { - config = files("./detekt-config.yml") - buildUponDefaultConfig = true +// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin +changelog { + version.set(properties("pluginVersion")) + groups.set(emptyList()) +} - reports { - html.enabled = false - xml.enabled = false - txt.enabled = false - } +// Configure Gradle Qodana Plugin - read more: https://github.com/JetBrains/gradle-qodana-plugin +qodana { + cachePath.set(projectDir.resolve(".qodana").canonicalPath) + reportPath.set(projectDir.resolve("build/reports/inspections").canonicalPath) + saveReport.set(true) + showReport.set(System.getenv("QODANA_SHOW_REPORT")?.toBoolean() ?: false) } tasks { - withType { - kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString() - kotlinOptions.apiVersion = "1.3" - } - - withType { - jvmTarget = JavaVersion.VERSION_11.toString() - } - - withType { - useJUnitPlatform { - includeEngines = setOf("junit-jupiter", "junit-vintage") + // Set the JVM compatibility versions + properties("javaVersion").let { + withType { + sourceCompatibility = it + targetCompatibility = it } - jvmArgs( - "-Djunit.jupiter.testinstance.lifecycle.default=per_class", - "-Duser.language=en" - ) - testLogging { - events("passed", "skipped", "failed") + withType { + kotlinOptions.jvmTarget = it } } + wrapper { + gradleVersion = properties("gradleVersion") + } + patchPluginXml { - version.set(pluginVersion) - sinceBuild.set(pluginSinceBuild) - untilBuild.set(pluginUntilBuild) + version.set(properties("pluginVersion")) + sinceBuild.set(properties("pluginSinceBuild")) + untilBuild.set(properties("pluginUntilBuild")) // Extract the section from README.md and provide for the plugin's manifest pluginDescription.set( - provider { - val gitHubContentBasePath = "https://raw.githubusercontent.com/ekino/jcv-idea-plugin" - val gitHubRef = when { - pluginVersion.endsWith("-SNAPSHOT") -> "master" - else -> "v$pluginVersion" - } - - File(projectDir, "README.md").readText().lines().run { - val start = "" - val end = "" + projectDir.resolve("README.md").readText().lines().run { + val start = "" + val end = "" - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") - } - subList(indexOf(start) + 1, indexOf(end)) + if (!containsAll(listOf(start, end))) { + throw GradleException("Plugin description section not found in README.md:\n$start ... $end") } - .joinToString("\n") - .run { markdownToHTML(this) } + subList(indexOf(start) + 1, indexOf(end)) + }.joinToString("\n").run { markdownToHTML(this) } + .let { + val pluginVersion = properties("pluginVersion") + val gitHubContentBasePath = "https://raw.githubusercontent.com/ekino/jcv-idea-plugin" + val gitHubRef = when { + pluginVersion.endsWith("-SNAPSHOT") -> "master" + else -> "v$pluginVersion" + } // Replace local url with GitHub base url and set width to 500px - .replace( + it.replace( """src="./""", """width="500" src="$gitHubContentBasePath/$gitHubRef/""" ) - } + } ) // Get the latest available change notes from the changelog file - changeNotes.set( - provider { - changelog.getLatest().toHTML() - } - ) + changeNotes.set(provider { + changelog.run { + getOrNull(properties("pluginVersion")) ?: getLatest() + }.toHTML() + }) } runPluginVerifier { - ideVersions.set(pluginVerifierIdeVersions.split(',').map(String::trim).filter(String::isNotEmpty)) + ideVersions.set(properties("pluginVerifierIdeVersions").split(',').map(String::trim).filter(String::isNotEmpty)) + } + + // Configure UI tests plugin + // Read more: https://github.com/JetBrains/intellij-ui-test-robot + runIdeForUiTests { + systemProperty("robot-server.port", "8082") + systemProperty("ide.mac.message.dialogs.as.sheets", "false") + systemProperty("jb.privacy.policy.text", "") + systemProperty("jb.consents.confirmation.enabled", "false") + } + + signPlugin { + certificateChain.set(System.getenv("CERTIFICATE_CHAIN")) + privateKey.set(System.getenv("PRIVATE_KEY")) + password.set(System.getenv("PRIVATE_KEY_PASSWORD")) } publishPlugin { dependsOn("patchChangelog") - token.set(provider { System.getenv("PUBLISH_TOKEN") }) + token.set(System.getenv("INTELLIJ_PUBLISH_TOKEN")) // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: - // https://jetbrains.org/intellij/sdk/docs/tutorials/build_system/deployment.html#specifying-a-release-channel - channels.set(provider { pluginVersion.split('-').getOrElse(1) { "default" }.split('.') }) + // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel + channels.set(listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first())) } } diff --git a/gradle.properties b/gradle.properties index 6d484cd..3cd611c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,24 +1,36 @@ -# -> https://www.jetbrains.org/intellij/sdk/docs/reference_guide/intellij_artifacts.html +# IntelliJ Platform Artifacts Repositories +# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup = com.ekino.oss.jcv-idea-plugin -pluginName_ = JCV +pluginName = JCV pluginDescription = JCV IDEA plugin -pluginVersion = 3.0.1 +pluginVersion = 3.0.2-SNAPSHOT + +# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html +# for insight into build numbers and IntelliJ Platform versions. pluginSinceBuild = 201 pluginUntilBuild = + # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl -# See https://jb.gg/intellij-platform-builds-list for available build versions -pluginVerifierIdeVersions = 2021.1, 2020.1.4 +# See https://jb.gg/intellij-platform-builds-list for available build versions. +pluginVerifierIdeVersions = 2020.3.4, 2021.1.3, 2021.2.2 platformType = IC -platformVersion = 2020.1 +platformVersion = 2021.2.2 platformDownloadSources = true -# Plugin Dependencies -> https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_dependencies.html + +# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 platformPlugins = +# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3 +javaVersion = 11 + +gradleVersion = 7.2 + # Opt-out flag for bundling Kotlin standard library. -# See https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library for details. +# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details. +# suppress inspection "UnusedProperty" kotlin.stdlib.default.dependency = false # Dependencies diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 12d38de..1f3299a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Generated by GNG distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7..4f906e0 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 62bd9b9..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/qodana.yml b/qodana.yml new file mode 100644 index 0000000..dac95d3 --- /dev/null +++ b/qodana.yml @@ -0,0 +1,6 @@ +# Qodana configuration: +# https://www.jetbrains.com/help/qodana/qodana-yaml.html + +version: 1.0 +profile: + name: qodana.recommended diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/definition/custom/JcvDefinitionLineMarkerProvider.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/definition/custom/JcvDefinitionLineMarkerProvider.kt index 82c3e76..3497e0c 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/definition/custom/JcvDefinitionLineMarkerProvider.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/definition/custom/JcvDefinitionLineMarkerProvider.kt @@ -17,7 +17,7 @@ class JcvDefinitionLineMarkerProvider : RelatedItemLineMarkerProvider() { @Suppress("ReturnCount") override fun collectNavigationMarkers( element: PsiElement, - result: MutableCollection> + result: MutableCollection> ) { val validatorId = (element as? com.ekino.oss.jcv.idea.plugin.language.psi.JcvValidator) ?.validatorId diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/inspection/JcvWhiteSpacesInspection.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/inspection/JcvWhiteSpacesInspection.kt index 8e5cbbc..8a7e255 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/inspection/JcvWhiteSpacesInspection.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/inspection/JcvWhiteSpacesInspection.kt @@ -10,7 +10,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.TokenType -import com.intellij.psi.util.collectDescendantsOfType +import com.intellij.psi.util.descendantsOfType import com.intellij.psi.util.elementType import com.intellij.refactoring.suggested.endOffset import com.intellij.refactoring.suggested.startOffset @@ -23,7 +23,7 @@ class JcvWhiteSpacesInspection : JcvInspectionBase() { val whiteSpaces = (element as? JcvFile) ?.let { jcvFile -> - jcvFile.collectDescendantsOfType { it.elementType == TokenType.WHITE_SPACE } + jcvFile.descendantsOfType().filter { it.elementType == TokenType.WHITE_SPACE } } ?: return diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/JcvReplacementIntention.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/JcvReplacementIntention.kt index 43ac7da..56b716e 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/JcvReplacementIntention.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/JcvReplacementIntention.kt @@ -24,6 +24,8 @@ class JcvReplacementIntention : JcvBaseIntentionAction() { ?.takeUnless { JcvUtil.isJcvValidatorCandidate(it) } .let { it != null } + override fun startInWriteAction(): Boolean = false + override fun invoke(project: Project, editor: Editor?, element: PsiElement) { SuggestJcvReplacementAction().also { action -> /** @@ -32,7 +34,7 @@ class JcvReplacementIntention : JcvBaseIntentionAction() { val dataContext = DataManager.getInstance().getDataContext(editor?.contentComponent) action.actionPerformed( AnActionEvent.createFromDataContext( - ActionPlaces.UNKNOWN, + ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, action.templatePresentation, dataContext ) diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestJcvReplacementAction.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestJcvReplacementAction.kt index 6df3996..52ff6bf 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestJcvReplacementAction.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestJcvReplacementAction.kt @@ -7,13 +7,7 @@ import com.intellij.json.JsonLanguage import com.intellij.json.psi.JsonElementGenerator import com.intellij.json.psi.JsonProperty import com.intellij.json.psi.JsonValue -import com.intellij.openapi.actionSystem.ActionGroup -import com.intellij.openapi.actionSystem.ActionManager -import com.intellij.openapi.actionSystem.ActionPlaces -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.actionSystem.Separator +import com.intellij.openapi.actionSystem.* import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.ui.popup.JBPopupFactory @@ -51,7 +45,7 @@ class SuggestJcvReplacementAction : AnAction() { } val actionGroupMenu = ActionManager.getInstance().createActionPopupMenu( - ActionPlaces.UNKNOWN, + ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION, object : ActionGroup() { override fun isPopup(): Boolean = true diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestionReplacementUtil.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestionReplacementUtil.kt index 3a7a4f5..2e1e0fe 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestionReplacementUtil.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/intention/SuggestionReplacementUtil.kt @@ -3,12 +3,7 @@ package com.ekino.oss.jcv.idea.plugin.language.intention import com.ekino.oss.jcv.idea.plugin.definition.JcvValidatorRegistry import com.ekino.oss.jcv.idea.plugin.definition.existsInModule import com.ekino.oss.jcv.idea.plugin.language.JcvBundle -import com.intellij.json.psi.JsonArray -import com.intellij.json.psi.JsonBooleanLiteral -import com.intellij.json.psi.JsonNumberLiteral -import com.intellij.json.psi.JsonObject -import com.intellij.json.psi.JsonStringLiteral -import com.intellij.json.psi.JsonValue +import com.intellij.json.psi.* import com.intellij.openapi.module.Module import com.intellij.psi.PsiElement import org.apache.commons.text.StringEscapeUtils @@ -41,7 +36,6 @@ private val DATE_FORMATTERS by lazy { ) } -@OptIn(ExperimentalStdlibApi::class) fun findReplacementSuggestions(module: Module?, jsonValueElements: List) = jsonValueElements .map { it to suggestReplacements(it) } .let { suggestionsByJsonValueElt -> diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvElementType.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvElementType.kt index 5ee5ba7..f3a5ea2 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvElementType.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvElementType.kt @@ -2,12 +2,13 @@ package com.ekino.oss.jcv.idea.plugin.language.psi import com.ekino.oss.jcv.idea.plugin.language.JcvLanguage import com.intellij.psi.tree.IElementType +import java.util.* class JcvElementType(debugName: String) : IElementType(debugName, JcvLanguage) { private val printableName = debugName.replace("_", " ") - .toLowerCase() - .capitalize() + .lowercase() + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } override fun toString(): String = printableName } diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvTokenType.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvTokenType.kt index 289cdfd..c315e28 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvTokenType.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/JcvTokenType.kt @@ -2,12 +2,13 @@ package com.ekino.oss.jcv.idea.plugin.language.psi import com.ekino.oss.jcv.idea.plugin.language.JcvLanguage import com.intellij.psi.tree.IElementType +import java.util.* class JcvTokenType(debugName: String) : IElementType(debugName, JcvLanguage) { private val printableName = debugName.replace("_", " ") - .toLowerCase() - .capitalize() + .lowercase() + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } override fun toString(): String = printableName } diff --git a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/impl/JcvPsiImplUtil.kt b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/impl/JcvPsiImplUtil.kt index e10910b..3bf13ed 100644 --- a/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/impl/JcvPsiImplUtil.kt +++ b/src/main/kotlin/com/ekino/oss/jcv/idea/plugin/language/psi/impl/JcvPsiImplUtil.kt @@ -4,15 +4,13 @@ import com.ekino.oss.jcv.idea.plugin.language.JcvIcons import com.ekino.oss.jcv.idea.plugin.language.psi.JcvElementFactory import com.ekino.oss.jcv.idea.plugin.language.psi.JcvParameterEntry import com.ekino.oss.jcv.idea.plugin.language.psi.JcvParameters -import com.ekino.oss.jcv.idea.plugin.language.psi.JcvTypes.PARAMETER -import com.ekino.oss.jcv.idea.plugin.language.psi.JcvTypes.PARAMETER_SEPARATOR -import com.ekino.oss.jcv.idea.plugin.language.psi.JcvTypes.VALIDATOR_ID +import com.ekino.oss.jcv.idea.plugin.language.psi.JcvTypes.* import com.ekino.oss.jcv.idea.plugin.language.psi.JcvValidator import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiElement -import com.intellij.psi.util.collectDescendantsOfType +import com.intellij.psi.util.descendants +import com.intellij.psi.util.descendantsOfType import com.intellij.psi.util.elementType -import com.intellij.psi.util.findDescendantOfType import com.intellij.psi.util.parentOfType import javax.swing.Icon @@ -65,11 +63,11 @@ object JcvPsiImplUtil { @JvmStatic fun getParameterValue(element: JcvParameterEntry) = - element.findDescendantOfType { it.elementType == PARAMETER } + element.descendantsOfType().filter { it.elementType == PARAMETER }.firstOrNull() @JvmStatic fun getIndexedParameters(element: JcvParameters): List> { - val paramEntries = element.collectDescendantsOfType() + val paramEntries = element.descendantsOfType() // Manage the following use case : "{#validator:;param2#}" -> param 2 should be index 1 val firstParamDelta = paramEntries.firstOrNull()?.separator?.let { listOf(null) } ?: emptyList() @@ -87,10 +85,8 @@ object JcvPsiImplUtil { @JvmStatic fun getSeparator(element: JcvParameterEntry) = - element.findDescendantOfType { - it.elementType == PARAMETER_SEPARATOR - } + element.descendantsOfType().filter { it.elementType == PARAMETER_SEPARATOR }.firstOrNull() private fun PsiElement.findValidatorIdElement() = - findDescendantOfType { it.elementType == VALIDATOR_ID } + descendantsOfType().filter { it.elementType == VALIDATOR_ID }.firstOrNull() } diff --git a/src/test/kotlin/com/ekino/oss/jcv/idea/plugin/language/JcvBasePlatformTestCase.kt b/src/test/kotlin/com/ekino/oss/jcv/idea/plugin/language/JcvBasePlatformTestCase.kt index 799eb9c..d0dda12 100644 --- a/src/test/kotlin/com/ekino/oss/jcv/idea/plugin/language/JcvBasePlatformTestCase.kt +++ b/src/test/kotlin/com/ekino/oss/jcv/idea/plugin/language/JcvBasePlatformTestCase.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.fixtures.BasePlatformTestCase +import java.nio.file.Path const val LAST_JCV_CORE_VERSION = "1.5.0" @@ -20,8 +21,8 @@ abstract class JcvBasePlatformTestCase : BasePlatformTestCase() { super.setUpProject(project, handler) } - override fun createModule(project: Project, moduleFilePath: String): Module { - return super.createModule(project, moduleFilePath) + override fun createModule(project: Project, moduleFile: Path): Module { + return super.createModule(project, moduleFile) .also { configureModule(it) } } }