diff --git a/.github/workflows/IJ-latest.yml b/.github/workflows/IJ-latest.yml index 19614ee12..720f0404a 100644 --- a/.github/workflows/IJ-latest.yml +++ b/.github/workflows/IJ-latest.yml @@ -23,7 +23,7 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build --continue -PideaVersion=IU-LATEST-EAP-SNAPSHOT + run: ./gradlew build --continue -PplatformVersion=LATEST-EAP-SNAPSHOT - uses: actions/upload-artifact@v4 if: always() with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 779ad9ec6..c7e7007bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build --continue --no-daemon + run: ./gradlew build --continue - uses: actions/upload-artifact@v4 if: always() with: @@ -91,7 +91,7 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Play integration tests - run: ./gradlew integrationTest --continue --no-daemon + run: ./gradlew integrationTest --continue - uses: actions/upload-artifact@v4 if: always() with: diff --git a/.github/workflows/cluster_integration_ui_tests.yml b/.github/workflows/cluster_integration_ui_tests.yml index adb6e0d5e..e5081d4c3 100644 --- a/.github/workflows/cluster_integration_ui_tests.yml +++ b/.github/workflows/cluster_integration_ui_tests.yml @@ -1,13 +1,15 @@ -name: Cluster Integration UI Tests +name: Integration UI Tests with Local Kind Cluster Context on: workflow_run: workflows: [ "Java CI with Gradle" ] types: - completed jobs: - kubernetes-integration-ui-tests: + cluster-integration-ui-tests: runs-on: ubuntu-latest steps: + - name: Create more disk space + run: sudo rm -rf /usr/share/dotnet && sudo rm -rf /opt/ghc && sudo rm -rf "/usr/local/share/boost" && sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 @@ -36,18 +38,28 @@ jobs: sleep 1 nb=`kubectl get pods -n operators --no-headers --ignore-not-found | grep Running | wc -l` done + # TODO remove locally building common-ui-test-library after new release of common-ui-test-library + - name: 'Clone common-ui-test-library to Maven Local repository' + run: | + git clone --branch ghabranch https://github.com/martinszuc/intellij-common-ui-test-library.git ../common-ui-test-library + - uses: burrunan/gradle-cache-action@3bf23b8dd95e7d2bacf2470132454fe893a178a1 #v1 + name: Build common-ui-test-library + with: + build-root-directory: ../common-ui-test-library + arguments: publishToMavenLocal - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Play cluster integration UI tests env: GPG_PASSPHRASE: ${{ secrets.IDEA_KEY_PASSPHRASE }} CLUSTER_ALREADY_LOGGED_IN: 'true' + RUN_CLUSTER_TESTS: 'true' run: | echo -n "$GPG_PASSPHRASE" | gpg --decrypt --passphrase-fd 0 --pinentry-mode loopback --output idea_license_token/idea.key idea_license_token/idea.key.gpg export DISPLAY=:99.0 Xvfb -ac :99 -screen 0 1920x1080x16 & sleep 10 - ./gradlew clusterIntegrationUITest --continue --no-daemon --info + ./gradlew integrationUITest --continue --no-daemon --info - name: Publish tests reports if: always() uses: scacap/action-surefire-report@a2911bd1a4412ec18dde2d93b1758b3e56d2a880 #v1.8.0 diff --git a/.github/workflows/public_integration_ui_tests.yml b/.github/workflows/no_context_integration_ui_tests.yml similarity index 61% rename from .github/workflows/public_integration_ui_tests.yml rename to .github/workflows/no_context_integration_ui_tests.yml index 650fcc874..0a07625f6 100644 --- a/.github/workflows/public_integration_ui_tests.yml +++ b/.github/workflows/no_context_integration_ui_tests.yml @@ -1,13 +1,15 @@ -name: Public Integration UI Tests +name: Integration UI Tests with No Context on: workflow_run: workflows: [ "Java CI with Gradle" ] types: - completed jobs: - public-integration-ui-tests: + no-context-integration-ui-tests: runs-on: ubuntu-latest steps: + - name: Create more disk space + run: sudo rm -rf /usr/share/dotnet && sudo rm -rf /opt/ghc && sudo rm -rf "/usr/local/share/boost" && sudo rm -rf "$AGENT_TOOLSDIRECTORY" - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 @@ -21,9 +23,18 @@ jobs: add-job-summary: 'on-failure' add-job-summary-as-pr-comment: 'on-failure' validate-wrappers: true + # TODO remove locally building common-ui-test-library after new release of common-ui-test-library + - name: 'Clone common-ui-test-library to Maven Local repository' + run: | + git clone --branch ghabranch https://github.com/martinszuc/intellij-common-ui-test-library.git ../common-ui-test-library + - uses: burrunan/gradle-cache-action@3bf23b8dd95e7d2bacf2470132454fe893a178a1 #v1 + name: Build common-ui-test-library + with: + build-root-directory: ../common-ui-test-library + arguments: publishToMavenLocal - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Play public integration UI tests + - name: Play integration UI tests env: GPG_PASSPHRASE: ${{ secrets.IDEA_KEY_PASSPHRASE }} run: | @@ -31,7 +42,7 @@ jobs: export DISPLAY=:99.0 Xvfb -ac :99 -screen 0 1920x1080x16 & sleep 10 - ./gradlew publicIntegrationUITest --continue --no-daemon + ./gradlew integrationUITest --continue --no-daemon --info - name: Publish tests reports if: always() uses: scacap/action-surefire-report@a2911bd1a4412ec18dde2d93b1758b3e56d2a880 #v1.8.0 @@ -39,7 +50,7 @@ jobs: github_token: ${{secrets.GITHUB_TOKEN}} report_paths: '${{github.workspace}}/build/test-results/**/TEST-*.xml' commit: ${{github.event.workflow_run.head_sha}} - check_name: Public Integration UI Tests Report + check_name: Integration UI Tests with No Context Report - name: Publish screenshots as artifacts if: failure() uses: actions/upload-artifact@v4 diff --git a/.github/workflows/validate_IJ_versions.yml b/.github/workflows/validate_IJ_versions.yml index 773534272..f053dd4de 100644 --- a/.github/workflows/validate_IJ_versions.yml +++ b/.github/workflows/validate_IJ_versions.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - IJ: [ IU-2022.3, IU-2023.1, IU-2023.2, IU-2023.3, IU-2024.1 ] + IJ: [ 2022.3, 2023.1, 2023.2, 2023.3, 2024.1, 2024.2 ] steps: - name: Checkout Code @@ -23,12 +23,13 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build -PideaVersion=${{ matrix.IJ }} + run: ./gradlew build -PplatformVersion=${{ matrix.IJ }} - name: Verify with Gradle - run: ./gradlew runPluginVerifier -PideaVersion=${{ matrix.IJ }} + run: ./gradlew verifyPlugin -PplatformVersion=${{ matrix.IJ }} - name: Upload report uses: actions/upload-artifact@v4 if: always() with: name: ${{ matrix.IJ }}-verifier-report path: build/reports/pluginVerifier + if-no-files-found: ignore diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index a454ef298..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env groovy - -node('rhel7'){ - def recipientList = 'jbosstools-builds@lists.jboss.org' - def javaHome = tool 'openjdk-17' - env.JAVA_HOME = "${javaHome}" - - try { - stage('Checkout repo') { - deleteDir() - git url: 'https://github.com/redhat-developer/intellij-openshift-connector', - branch: "${sha1}" - } - - def props = readProperties file: 'gradle.properties' - def isSnapshot = props['projectVersion'].contains('-SNAPSHOT') - def version = isSnapshot?props['projectVersion'].replace('-SNAPSHOT', ".${env.BUILD_NUMBER}"):props['projectVersion'] + ".${env.BUILD_NUMBER}" - - stage('Build') { - sh "./gradlew assemble -PprojectVersion=${version}" - } - - stage('Package') { - sh "./gradlew buildPlugin -PprojectVersion=${version}" - } - - if(params.UPLOAD_LOCATION) { - stage('Upload') { - def filesToPush = findFiles(glob: '**/*.zip') - sh "sftp -C ${UPLOAD_LOCATION}/snapshots/intellij-openshift-connector/ <<< \$'put -p ${filesToPush[0].path}'" - stash name:'zip', includes:filesToPush[0].path - } - } - - if(publishToMarketPlace.equals('true')){ - timeout(time:5, unit:'DAYS') { - input message:'Approve deployment?', submitter: 'jmaury,adietish,sbouchet' - } - - def channel = isSnapshot?"nightly":"stable" - - stage("Publish to Marketplace") { - unstash 'zip' - withCredentials([[$class: 'StringBinding', credentialsId: 'JetBrains marketplace token', variable: 'TOKEN']]) { - sh "./gradlew publishPlugin -PjetBrainsToken=${TOKEN} -PprojectVersion=${version} -PjetBrainsChannel=${channel}" - } - archive includes:"**.zip" - - if (!isSnapshot) { - stage("Promote the build to stable") { - def zip = findFiles(glob: '**/*.zip') - sh "sftp -C ${UPLOAD_LOCATION}/stable/intellij-openshift-connector/ <<< \$'put -p ${zip[0].path}'" - currentBuild.keepLog = true - currentBuild.description = "${version}" - } - } - } - } - } catch (any) { - currentBuild.result = 'FAILURE' - step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: "${recipientList}", sendToIndividuals: true]) - throw any - } -} diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 827a32110..000000000 --- a/build.gradle +++ /dev/null @@ -1,237 +0,0 @@ -buildscript { - ext.java_version = "17" -} - -plugins { - id 'org.jetbrains.intellij' version '1.17.4' - id 'com.adarshr.test-logger' version '4.0.0' - id 'idea' - id 'java' - id 'jacoco' - id 'org.sonarqube' version '5.1.0.4882' -} - -repositories { - mavenLocal() - maven { url 'https://repository.jboss.org' } - mavenCentral() - maven { url 'https://www.jetbrains.com/intellij-repository/snapshots' } - maven { url 'https://www.jetbrains.com/intellij-repository/releases' } - maven { url 'https://cache-redirector.jetbrains.com/intellij-dependencies' } -} - -configurations { - compileOptions { - sourceCompatibility = java_version - targetCompatibility = java_version - } -} - -intellij { - version = ideaVersion //for a full list of IntelliJ IDEA releases please see https://www.jetbrains.com/intellij-repository/releases - pluginName = 'org.jboss.tools.intellij.openshift' - // use '/build/idea-sandbox/plugins/' if working from source - plugins = [ - 'java', - 'terminal', - 'JavaScriptDebugger', - 'JavaScript', - 'com.intellij.css', - 'yaml', - 'com.redhat.devtools.intellij.telemetry:1.2.0.59', - 'com.redhat.devtools.intellij.kubernetes:1.3.0' - ] - updateSinceUntilBuild = false -} - -//with this option enabled, build will fail about IDEA expiration builds -buildSearchableOptions.enabled = false - -runPluginVerifier { - ideVersions = [ideaVersion] -} - -publishPlugin { - token = jetBrainsToken - channels = [jetBrainsChannel] -} - -configurations { - implementation { - exclude group: 'org.slf4j', module: 'slf4j-api' - } - integrationTestImplementation.extendsFrom testImplementation - integrationTestRuntimeOnly.extendsFrom testRuntimeOnly -} - -sourceSets { - integrationTest { - java.srcDir file('src/it/java') - resources.srcDir file('src/it/resources') - compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - runtimeClasspath += output + compileClasspath - } -} - -test { - // Discover and execute JUnit4-based tests - useJUnit() - systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'disabled' - jvmArgs "-Djava.awt.headless=true" - jacoco { - includeNoLocationClasses = true - excludes = ["jdk.internal.*"] - } -} - -tasks.register('integrationTest', Test) { - systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'disabled' - description = 'Runs the integration tests.' - group = 'verification' - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath - outputs.upToDateWhen { false } - testlogger { - showStandardStreams true - showPassedStandardStreams false - showSkippedStandardStreams false - showFailedStandardStreams true - showFullStackTraces true - } - jvmArgs "-Djava.awt.headless=true" - jacoco { - includeNoLocationClasses = true - excludes = ["jdk.internal.*"] - } -} -classpathIndexCleanup { - dependsOn compileIntegrationTestJava -} - -tasks.register('clusterIntegrationUITest', Test) { - dependsOn copyKey - useJUnitPlatform { - includeTags 'ui-test' - } - systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'disabled' - systemProperties['CLUSTER_ALREADY_LOGGED_IN'] = System.getenv('CLUSTER_ALREADY_LOGGED_IN') ?: 'false' - description = 'Runs the cluster integration UI tests.' - group = 'verification' - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath - outputs.upToDateWhen { true } - testlogger { - showStandardStreams true - showPassedStandardStreams false - showSkippedStandardStreams false - showFailedStandardStreams true - showFullStackTraces true - } - jvmArgs "-Djava.awt.headless=false" // use of clipboard in AboutPublicTest, set to false - jacoco { - includeNoLocationClasses = true - excludes = ["jdk.internal.*"] - } - include '**/ClusterTestsSuite.class' -} - -tasks.register('publicIntegrationUITest', Test) { - dependsOn copyKey - useJUnitPlatform { - includeTags 'ui-test' - } - systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'disabled' - description = 'Runs the public integration UI tests.' - group = 'verification' - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath - outputs.upToDateWhen { true } - testlogger { - showStandardStreams true - showPassedStandardStreams false - showSkippedStandardStreams false - showFailedStandardStreams true - showFullStackTraces true - } - jvmArgs "-Djava.awt.headless=false" // use of clipboard in AboutPublicTest, set to false - jacoco { - includeNoLocationClasses = true - excludes = ["jdk.internal.*"] - } - include '**/PublicTestsSuite.class' - -} - -tasks.register('copyKey', Copy) { - from "idea_license_token/idea.key" - into "build/idea-sandbox/config-uiTest" -} - -dependencies { - implementation( - 'io.fabric8:openshift-client:6.12.0', - 'org.apache.commons:commons-compress:1.26.2', - 'org.apache.commons:commons-exec:1.4.0', - 'com.redhat.devtools.intellij:intellij-common:1.9.6', - 'io.jsonwebtoken:jjwt-impl:0.12.6', - 'io.jsonwebtoken:jjwt-jackson:0.12.6', - 'org.keycloak:keycloak-installed-adapter:24.0.5', - 'com.squareup.retrofit2:converter-jackson:2.11.0', - 'com.google.code.gson:gson:2.11.0') - testImplementation( - 'org.junit.platform:junit-platform-launcher:1.10.3', - 'org.mockito:mockito-core:5.12.0', - 'org.easytesting:fest-assert:1.4', - 'com.redhat.devtools.intellij:intellij-common:1.9.6:test', - 'org.awaitility:awaitility:4.2.2', - 'org.mock-server:mockserver-client-java:5.15.0', - 'org.mock-server:mockserver-netty:5.15.0', - 'com.redhat.devtools.intellij:intellij-common-ui-test-library:0.4.1', - 'org.junit.jupiter:junit-jupiter-engine:5.10.3', - 'org.junit.jupiter:junit-jupiter-api:5.10.3', - 'org.junit.jupiter:junit-jupiter:5.10.3', - 'org.junit.platform:junit-platform-suite:1.10.3') - constraints { - implementation('io.undertow:undertow-core:2.3.15.Final') { //keycloak - because 'https://security.snyk.io/vuln/SNYK-JAVA-IOUNDERTOW-6567186' - } - implementation('org.bouncycastle:bcprov-jdk18on:1.78.1') { //keycloak - because 'https://app.snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-6612984' - } - implementation('com.squareup.okhttp3:okhttp:4.12.0') { //retrofit - because 'https://security.snyk.io/vuln/SNYK-JAVA-COMSQUAREUPOKHTTP3-2958044' - } - } -} - -sonar { - properties { - property "sonar.projectKey", "redhat-developer_intellij-openshift-connector" - property "sonar.organization", "redhat-developer" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.junit.reportsPath", layout.buildDirectory.dir("test-results").get().asFile.absolutePath - property "sonar.gradle.skipCompile", "true" - } -} - -jacocoTestReport { - getExecutionData().setFrom(fileTree(layout.buildDirectory).include("/jacoco/*.exec")) - reports { - xml.required = true - } -} - -runIde { - systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'debug' - //systemProperties['jboss.sandbox.api.endpoint'] = 'http://localhost:3000' -} - -tasks.register('runSandbox', JavaExec) { - group = "Execution" - description = "Run the Sandbox registration server in port 3000" - classpath = sourceSets.test.runtimeClasspath - getMainClass().set 'org.jboss.tools.intellij.openshift.ui.sandbox.SandboxRegistrationServerMock' -} - -group 'org.jboss.tools.intellij' -version projectVersion // Plugin version diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..295a20c06 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,288 @@ +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType +import org.jetbrains.intellij.platform.gradle.TestFrameworkType + +plugins { + id("java") // Java support + alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin + alias(libs.plugins.testLogger) // Nice test logs + id("jacoco") // Code coverage + alias(libs.plugins.sonarqube) // SonarQube +} + +group = "org.jboss.tools.intellij" +version = providers.gradleProperty("projectVersion").get() // Plugin version +val ideaVersion = providers.gradleProperty("platformVersion").get() +val devtoolsCommonForTests = "com.redhat.devtools.intellij:intellij-common:" + libs.devtools.common + ":test" + +// Set the JVM language level used to build the project. +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +repositories { + mavenLocal() + maven { url = uri("https://repository.jboss.org") } + mavenCentral() + intellijPlatform { + defaultRepositories() + } +} + +dependencies { + intellijPlatform { + create(IntelliJPlatformType.IntellijIdeaUltimate, ideaVersion) + + // Bundled Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins. + bundledPlugins(providers.gradleProperty("platformBundledPlugins").map { it.split(',') }) + + // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace. + plugins(providers.gradleProperty("platformPlugins").map { it.split(',') }) + + // for local plugin -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin-faq.html#how-to-add-a-dependency-on-a-plugin-available-in-the-file-system + //plugins.set(listOf(file("/path/to/plugin/"))) + + pluginVerifier() + + instrumentationTools() + + testFramework(TestFrameworkType.Platform) + } + + implementation(libs.openshift.client) + implementation(libs.devtools.common) + implementation(libs.keycloak) + implementation(libs.jjwt.impl) + implementation(libs.jjwt.jackson) + implementation(libs.converter.jackson) + implementation(libs.annotations) // to build against platform <= 2023.2 + + // for unit tests + testImplementation(libs.junit) + testImplementation(libs.mockito) + testImplementation(libs.easytesting) + testImplementation(libs.mockserver.client) + testImplementation(libs.mockserver.netty) + + constraints { + implementation("io.undertow:undertow-core:2.3.15.Final") { // keycloak + because("https://security.snyk.io/vuln/SNYK-JAVA-IOUNDERTOW-6567186") + } + implementation("org.bouncycastle:bcprov-jdk18on:1.78.1") { // keycloak + because("https://security.snyk.io/vuln/SNYK-JAVA-ORGBOUNCYCASTLE-6612984") + } + implementation("com.squareup.okhttp3:okhttp:4.12.0") { // converter.jackson/retrofit + because("https://security.snyk.io/vuln/SNYK-JAVA-COMSQUAREUPOKHTTP3-2958044") + } + } +} + +intellijPlatform { + buildSearchableOptions = false + + pluginConfiguration { + ideaVersion { + sinceBuild = providers.gradleProperty("pluginSinceBuild") + untilBuild = provider { null } + } + } + + publishing { + token = providers.gradleProperty("jetBrainsToken") + channels = providers.gradleProperty("jetBrainsChannel").map { listOf(it) } + } + + pluginVerification { + ides { + ide(IntelliJPlatformType.IntellijIdeaUltimate, ideaVersion) + } + freeArgs = listOf( + "-mute", + "TemplateWordInPluginId,TemplateWordInPluginName" + ) + } +} + +tasks { + wrapper { + gradleVersion = providers.gradleProperty("gradleVersion").get() + } + + runIde { + systemProperty("com.redhat.devtools.intellij.telemetry.mode", "debug") + findProperty("tools.dl.path")?.let { systemProperty("tools.dl.path", it) } + //systemProperty("jboss.sandbox.api.endpoint", "http://localhost:3000") // enable when running sandbox locally, see below + } + + test { + systemProperty("com.redhat.devtools.intellij.telemetry.mode", "disabled") + jvmArgs("-Djava.awt.headless=true") + } + + withType { + configure { + isIncludeNoLocationClasses = true + excludes = listOf("jdk.internal.*") + } + } + + jacocoTestReport { + executionData.setFrom(fileTree(layout.buildDirectory).include("/jacoco/*.exec")) + classDirectories.setFrom(instrumentCode) + reports { + xml.required = true + } + } + + jacocoTestCoverageVerification { + classDirectories.setFrom(instrumentCode) + } + + sonar { + properties { + property("sonar.projectKey", "redhat-developer_intellij-openshift-connector") + property("sonar.organization", "redhat-developer") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.junit.reportsPath", layout.buildDirectory.dir("test-results").get().asFile.absolutePath) + property("sonar.gradle.skipCompile", "true") + } + } + + register("runSandbox", JavaExec::class.java) { + group = "Execution" + description = "Run the Sandbox registration server in port 3000" + classpath = sourceSets.test.get().runtimeClasspath + mainClass.set("org.jboss.tools.intellij.openshift.ui.sandbox.SandboxRegistrationServerMock") + } + + register("copyKey", Copy::class.java) { + from("idea_license_token/idea.key") + into("build/idea-sandbox/config-uiTest") + } + +} + +sourceSets { + create("it") { + description = "integrationTest" + compileClasspath += sourceSets.main.get().compileClasspath + sourceSets.test.get().compileClasspath + runtimeClasspath += output + compileClasspath + } +} + +configurations.all { + exclude(group = "org.slf4j", module = "slf4j-api") + exclude(group = "bundledPlugin", module = "Docker") // suppress multiple SLF4J providers +} + +configurations["itRuntimeOnly"].extendsFrom(configurations.testRuntimeOnly.get()) +configurations["itImplementation"].extendsFrom(configurations.testImplementation.get()) + +val integrationTest by intellijPlatformTesting.testIde.registering { + task { + systemProperty("com.redhat.devtools.intellij.telemetry.mode", "disabled") + findProperty("tools.dl.path")?.let { systemProperty("tools.dl.path", it) } + description = "Runs the integration tests." + group = "verification" + testClassesDirs = sourceSets["it"].output.classesDirs + classpath = sourceSets["it"].runtimeClasspath + testlogger { + showStandardStreams = true + showPassedStandardStreams = false + showSkippedStandardStreams = false + showFailedStandardStreams = true + showFullStackTraces = true + } + jvmArgs("-Djava.awt.headless=true") + shouldRunAfter(tasks["test"]) + } + + plugins { + robotServerPlugin() + } + + dependencies { + testImplementation(libs.junit.platform.launcher) + testImplementation(libs.junit.platform.suite) + testImplementation(libs.junit.jupiter) + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.engine) + testImplementation(devtoolsCommonForTests) + testImplementation(libs.devtools.common.ui.test) + testImplementation(libs.awaitility) + } +} + +val integrationUITest by intellijPlatformTesting.testIde.registering { + task { + systemProperty("com.redhat.devtools.intellij.telemetry.mode", "disabled") + findProperty("tools.dl.path")?.let { systemProperty("tools.dl.path", it) } + findProperty("testProjectLocation")?.let { systemProperty("testProjectLocation", it) } + systemProperties["CLUSTER_ALREADY_LOGGED_IN"] = System.getenv("CLUSTER_ALREADY_LOGGED_IN") ?: false + systemProperties["RUN_CLUSTER_TESTS"] = System.getenv("RUN_CLUSTER_TESTS") ?: false + description = "Runs the cluster integration UI tests." + group = "verification" + testClassesDirs = sourceSets["it"].output.classesDirs + classpath = sourceSets["it"].runtimeClasspath + testlogger { + showStandardStreams = true + showPassedStandardStreams = false + showSkippedStandardStreams = false + showFailedStandardStreams = true + showFullStackTraces = true + } + jvmArgs("-Djava.awt.headless=false") // use of clipboard in AboutPublicTest, set to false + val includes = if (System.getenv("RUN_CLUSTER_TESTS") != null) {"**/ClusterTestsSuite.class"} else {"**/PublicTestsSuite.class"} + include(includes) + useJUnitPlatform { + includeTags("ui-test") + } + shouldRunAfter(tasks["test"]) + } + + plugins { + robotServerPlugin() + } + + dependencies { + testImplementation(libs.junit.platform.launcher) + testImplementation(libs.junit.platform.suite) + testImplementation(libs.junit.jupiter) + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.engine) + testImplementation(devtoolsCommonForTests) + testImplementation(libs.devtools.common.ui.test) + testImplementation(libs.awaitility) + } +} + +// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-tasks.html#runIdeForUiTests +val runIdeForUiTests by intellijPlatformTesting.runIde.registering { + task { + jvmArgs("-Djava.awt.headless=false") + jvmArgumentProviders += CommandLineArgumentProvider { + listOf( + "-Dide.mac.message.dialogs.as.sheets=false", + "-Djb.privacy.policy.text=", + "-Djb.consents.confirmation.enabled=false", + ) + } + doFirst { + val configDir = sandboxConfigDirectory.get().asFile + project.copy { + from("idea_license_token/idea.key") + into(configDir) + } + } + } + plugins { + robotServerPlugin() + } +} + +// below is only to correctly configure IDEA project settings +idea { + module { + testSources.from(sourceSets["it"].java.srcDirs) + } +} diff --git a/gradle.properties b/gradle.properties index 87cc792b3..75a322868 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,28 @@ -ideaVersion=IU-2024.1 projectVersion=1.10.2-SNAPSHOT jetBrainsToken=invalid jetBrainsChannel=stable + +# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension +# platformType = IU (not needed as hard-coded in gradle build directly) +platformVersion=2024.2 + +# Gradle Releases -> https://github.com/gradle/gradle/releases +gradleVersion = 8.5 + +# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html +platformBundledPlugins = com.intellij.java, JavaScriptDebugger, org.jetbrains.plugins.yaml +platformPlugins = com.redhat.devtools.intellij.telemetry:1.2.0.59, com.redhat.devtools.intellij.kubernetes:1.3.0 + +# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html +pluginSinceBuild = 223 + +# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib +kotlin.stdlib.default.dependency = false + +# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html +org.gradle.configuration-cache = true + +# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html +org.gradle.caching = true + +org.gradle.jvmargs=-XX\:MaxHeapSize\=512m -Xmx4g -Xms1g \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..bc625dc50 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,47 @@ +[versions] +# libraries +junit = "4.13.2" +openshift-client = "6.12.0" +devtools-common = "1.9.6" +keycloak = "24.0.5" +jsonwebtoken = "0.12.6" +retrofit2 = "2.11.0" +mockito = "5.12.0" +easytesting = "1.4" +mockserver = "5.15.0" +junit-platform = "1.10.3" +junit-jupiter = "5.10.3" +devtools-common-ui-test = "0.4.2-SNAPSHOT" +awaitility = "4.2.2" +annotations = "24.0.0" + +# plugins +gradleIntelliJPlugin = "2.0.1" +testlogger = "4.0.0" +sonarqube = "5.1.0.4882" + +[libraries] +junit = { group = "junit", name = "junit", version.ref = "junit" } +openshift-client = { group = "io.fabric8", name = "openshift-client", version.ref = "openshift-client" } +devtools-common = { group = "com.redhat.devtools.intellij", name = "intellij-common", version.ref = "devtools-common" } +keycloak = { group = "org.keycloak", name = "keycloak-installed-adapter", version.ref = "keycloak" } +jjwt-impl = { group = "io.jsonwebtoken", name = "jjwt-impl", version.ref = "jsonwebtoken" } +jjwt-jackson = { group = "io.jsonwebtoken", name = "jjwt-jackson", version.ref = "jsonwebtoken" } +converter-jackson = { group = "com.squareup.retrofit2", name = "converter-jackson", version.ref = "retrofit2" } +mockito = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +easytesting = { group = "org.easytesting", name = "fest-assert", version.ref = "easytesting" } +mockserver-client = { group = "org.mock-server", name = "mockserver-client-java", version.ref = "mockserver" } +mockserver-netty = { group = "org.mock-server", name = "mockserver-netty", version.ref = "mockserver" } +junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit-platform" } +junit-platform-suite = { group = "org.junit.platform", name = "junit-platform-suite", version.ref = "junit-platform" } +junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter" } +junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" } +devtools-common-ui-test = { group = "com.redhat.devtools.intellij", name = "intellij-common-ui-test-library", version.ref = "devtools-common-ui-test" } +awaitility = { group = "org.awaitility", name = "awaitility", version.ref = "awaitility" } +annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } + +[plugins] +gradleIntelliJPlugin = { id = "org.jetbrains.intellij.platform", version.ref = "gradleIntelliJPlugin" } +testLogger = { id = "com.adarshr.test-logger", version.ref = "testlogger" } +sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" } \ No newline at end of file diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/AbstractBaseTest.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/AbstractBaseTest.java index 3b0fd7567..dfcf61d29 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/AbstractBaseTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/AbstractBaseTest.java @@ -51,8 +51,8 @@ public abstract class AbstractBaseTest { public static final String DEFAULT_CLUSTER_URL = "no (current) context/cluster set"; protected static String currentClusterUrl = DEFAULT_CLUSTER_URL; - @RegisterExtension - TestWatcher testWatcher = new TestWatcherImpl(); +// @RegisterExtension +// TestWatcher testWatcher = new TestWatcherImpl(); @BeforeAll public static void setUpProject() { @@ -64,13 +64,15 @@ public static void setUpProject() { flatWelcomeFrame.disableNotifications(); flatWelcomeFrame.preventTipDialogFromOpening(); + captureScreenshot("before_project"); + CreateCloseUtils.createNewProject(robot, "test-project", CreateCloseUtils.NewProjectType.PLAIN_JAVA); ProjectStructureDialog.cancelProjectStructureDialogIfItAppears(robot); ProjectUtility.closeGotItPopup(robot); IdeStatusBar ideStatusBar = robot.find(IdeStatusBar.class, Duration.ofSeconds(5)); ideStatusBar.waitUntilAllBgTasksFinish(); - + captureScreenshot("after_project_created"); isProjectCreatedAndOpened = true; } } @@ -151,11 +153,11 @@ protected static void captureScreenshot(String comment) { LOGGER.error("Failed to capture screenshot: {}", e.getMessage(), e); } } - private static class TestWatcherImpl implements TestWatcher { - @Override - public void testFailed(ExtensionContext context, Throwable cause) { - captureScreenshot("test_failed_" + context.getDisplayName()); - CleanUpUtility.cleanUpAll(robot); - } +// private static class TestWatcherImpl implements TestWatcher { +// @Override +// public void testFailed(ExtensionContext context, Throwable cause) { +// captureScreenshot("test_failed_" + context.getDisplayName()); +// CleanUpUtility.cleanUpAll(robot); +// } } -} + diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/junit/TestRunnerExtension.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/junit/TestRunnerExtension.java index 52e290f2e..fe65df216 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/junit/TestRunnerExtension.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/junit/TestRunnerExtension.java @@ -30,7 +30,7 @@ public void beforeAll(ExtensionContext context) { System.out.println("Initialize IdeaRunner and start IDE"); // need to initialize store, so that close method will be called at the testing end context.getRoot().getStore(Namespace.GLOBAL).put("InitializeTest", this); - IdeaRunner.getInstance().startIDE(IntelliJVersion.ULTIMATE_V_2024_1, 8580); + IdeaRunner.getInstance().startIDE(IntelliJVersion.ULTIMATE_V_2024_2, 8580); } @Override diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/AboutClusterTest.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/AboutClusterTest.java index efd0fc804..2474463fa 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/AboutClusterTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/AboutClusterTest.java @@ -30,7 +30,7 @@ public class AboutClusterTest extends AbstractClusterTest { @Test public void aboutLoggedInTest() { LOGGER.info("aboutLoggedInTest: Start"); - + captureScreenshot("screen2"); AboutPublicTest.selectAboutAndGetClipboardContent(); AboutPublicTest.verifyClipboardContent("odo", "Server:", "Kubernetes:"); diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/CreateServiceTest.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/CreateServiceTest.java index 511cb9e4c..1c454d12e 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/CreateServiceTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/tests_cluster/CreateServiceTest.java @@ -3,6 +3,7 @@ import com.intellij.remoterobot.utils.WaitForConditionTimeoutException; import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.idestatusbar.IdeStatusBar; import org.jboss.tools.intellij.openshift.test.ui.dialogs.service.CreateNewServiceDialog; +import org.junit.Ignore; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -18,8 +19,9 @@ public class CreateServiceTest extends AbstractClusterTest { private static final String PROVIDER_NAME = "test-provider"; private static final String PROJECT_NAME = "newtestproject"; - @Test - @Order(1) + //@Test + //@Order(1) + @Ignore public void createServiceTest() { CreateNewServiceDialog createNewServiceDialog = CreateNewServiceDialog.open(robot); assertNotNull(createNewServiceDialog); diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/GettingStartedView.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/GettingStartedView.java index a684c7dbf..8745cebce 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/GettingStartedView.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/GettingStartedView.java @@ -14,7 +14,10 @@ import com.intellij.remoterobot.data.RemoteComponent; import com.intellij.remoterobot.fixtures.*; import com.intellij.remoterobot.utils.Keyboard; +import com.redhat.devtools.intellij.commonuitest.UITestRunner; +import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.toolwindowspane.ToolWindowLeftToolbar; import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.toolwindowspane.ToolWindowPane; +import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.toolwindowspane.ToolWindowRightToolbar; import org.jboss.tools.intellij.openshift.test.ui.utils.constants.XPathConstants; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -43,6 +46,10 @@ public GettingStartedView(@NotNull RemoteRobot remoteRobot, @NotNull RemoteCompo public void openView() { if (!isViewOpened()) { + if(UITestRunner.getIdeaVersion().toInt() > 20242) { + final ToolWindowRightToolbar toolWindowRightToolbar = find(ToolWindowRightToolbar.class); + toolWindowRightToolbar.clickStripeButton(GETTING_STARTED); + } final ToolWindowPane toolWindowPane = find(ToolWindowPane.class); toolWindowPane.button(byXpath(getToolWindowButton(GETTING_STARTED)), Duration.ofSeconds(2)).click(); LOGGER.info("Getting Started view opened"); @@ -51,6 +58,10 @@ public void openView() { public void closeView() { if (isViewOpened()) { + if(UITestRunner.getIdeaVersion().toInt() > 20242) { + final ToolWindowRightToolbar toolWindowRightToolbar = find(ToolWindowRightToolbar.class); + toolWindowRightToolbar.clickStripeButton(GETTING_STARTED); + } final ToolWindowPane toolWindowPane = find(ToolWindowPane.class); toolWindowPane.button(byXpath(getToolWindowButton(GETTING_STARTED)), Duration.ofSeconds(2)).click(); LOGGER.info("Getting Started view closed"); diff --git a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/OpenshiftView.java b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/OpenshiftView.java index f20ed1ad8..a0ca8c9c7 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/OpenshiftView.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/test/ui/views/OpenshiftView.java @@ -13,7 +13,10 @@ import com.intellij.remoterobot.RemoteRobot; import com.intellij.remoterobot.data.RemoteComponent; import com.intellij.remoterobot.fixtures.*; +import com.redhat.devtools.intellij.commonuitest.UITestRunner; +import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.toolwindowspane.ToolWindowLeftToolbar; import com.redhat.devtools.intellij.commonuitest.fixtures.mainidewindow.toolwindowspane.ToolWindowPane; +import org.jboss.tools.intellij.openshift.test.ui.runner.IdeaRunner; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,6 +45,10 @@ public OpenshiftView(@NotNull RemoteRobot remoteRobot, @NotNull RemoteComponent public void openView() { if (!isViewOpened()) { + if(UITestRunner.getIdeaVersion().toInt() > 20242) { + final ToolWindowLeftToolbar toolWindowLeftToolbar = find(ToolWindowLeftToolbar.class); + toolWindowLeftToolbar.clickStripeButton(OPENSHIFT); + } final ToolWindowPane toolWindowPane = find(ToolWindowPane.class); toolWindowPane.button(byXpath(getToolWindowButton(OPENSHIFT)), Duration.ofSeconds(2)).click(); LOGGER.info("Openshift view opened"); @@ -50,6 +57,10 @@ public void openView() { public void closeView() { if (isViewOpened()) { + if(UITestRunner.getIdeaVersion().toInt() > 20242) { + final ToolWindowLeftToolbar toolWindowLeftToolbar = find(ToolWindowLeftToolbar.class); + toolWindowLeftToolbar.clickStripeButton(OPENSHIFT); + } final ToolWindowPane toolWindowPane = find(ToolWindowPane.class); toolWindowPane.button(byXpath(getToolWindowButton(OPENSHIFT)), Duration.ofSeconds(2)).click(); LOGGER.info("Openshift view closed"); diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliComponentTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliComponentTest.java index 295fe963d..6147e5e6d 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliComponentTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliComponentTest.java @@ -11,6 +11,7 @@ package org.jboss.tools.intellij.openshift.utils.odo; import com.intellij.util.io.ZipUtil; +import com.intellij.openapi.util.io.FileUtil; import com.redhat.devtools.intellij.common.utils.ExecHelper; import org.apache.commons.io.FileUtils; import org.junit.After; @@ -204,8 +205,9 @@ public void checkCreateComponentAndDebug() throws IOException, ExecutionExceptio @Test public void checkCreateComponentStarter() throws IOException, ExecutionException, InterruptedException { - createComponent(project, component, "go-starter", projectPath); - List descriptors = odo.discover(projectPath); + String starterPath = FileUtil.createTempDirectory("go-starter", "").getPath(); + createComponent(project, component, "go-starter", starterPath); + List descriptors = odo.discover(starterPath); assertNotNull(descriptors); assertEquals(1, descriptors.size()); } diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliServiceTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliServiceTest.java index ae5760af1..a56e1cfba 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliServiceTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliServiceTest.java @@ -19,6 +19,12 @@ public class OdoCliServiceTest extends OdoCliTest { private final String projectPath = new File("src/it/projects/springboot-rest").getAbsolutePath(); + @Override + protected void tearDown() throws Exception { + cleanLocalProjectDirectory(projectPath); + super.tearDown(); + } + public void testCheckCreateService() throws IOException, ExecutionException, InterruptedException { String project = PROJECT_PREFIX + random.nextInt(); String service = SERVICE_PREFIX + random.nextInt(); @@ -54,6 +60,6 @@ private void createService(String project, String service) throws IOException, E ServiceTemplate serviceTemplate = getServiceTemplate(); OperatorCRD crd = getOperatorCRD(serviceTemplate); assertNotNull(crd); - createService(project, serviceTemplate, crd, service, projectPath); + createService(project, serviceTemplate, crd, service); } } diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java index 6733b4fd9..8ad5840ad 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java @@ -11,9 +11,9 @@ package org.jboss.tools.intellij.openshift.utils.odo; import com.intellij.openapi.ui.TestDialog; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.fixtures.BasePlatformTestCase; import com.redhat.devtools.intellij.common.utils.MessagesHelper; -import org.apache.commons.io.FileUtils; import org.jboss.tools.intellij.openshift.tree.application.ApplicationRootNodeOdo; import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode; import org.jboss.tools.intellij.openshift.utils.OdoCluster; @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import static org.awaitility.Awaitility.with; +import static org.jboss.tools.intellij.openshift.Constants.PLUGIN_FOLDER; import static org.mockito.Mockito.mock; @@ -101,9 +102,9 @@ protected void createComponent(String project, String component, String projectP } protected void cleanLocalProjectDirectory(String projectPath) throws IOException { - FileUtils.deleteDirectory(new File(projectPath, ".odo")); - FileUtils.deleteDirectory(new File(projectPath, "kubernetes")); - FileUtils.deleteQuietly(new File(projectPath + "/devfile.yaml")); + FileUtil.delete(new File(projectPath, PLUGIN_FOLDER).toPath()); + FileUtil.delete(new File(projectPath, "kubernetes").toPath()); + FileUtil.delete(new File(projectPath + "/devfile.yaml").toPath()); } protected OperatorCRD getOperatorCRD(ServiceTemplate serviceTemplate) { @@ -116,8 +117,7 @@ protected ServiceTemplate getServiceTemplate() throws IOException { return odo.getServiceTemplates().stream().filter(s -> s.getName().equals(SERVICE_TEMPLATE + "." + (odo.isOpenShift() ? SERVICE_OPENSHIFT_VERSION : SERVICE_KUBE_VERSION))).findFirst().orElse(null); } - protected void createService(String project, ServiceTemplate serviceTemplate, OperatorCRD crd, String service, String projectPath) throws IOException { - cleanLocalProjectDirectory(projectPath); + protected void createService(String project, ServiceTemplate serviceTemplate, OperatorCRD crd, String service) throws IOException { odo.createService(project, serviceTemplate, crd, service, null, false); } } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java index 71d52a797..cffe5379a 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java @@ -14,8 +14,8 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; import com.redhat.devtools.intellij.common.utils.UIHelper; -import org.apache.commons.lang3.StringUtils; import org.jboss.tools.intellij.openshift.Constants; import org.jboss.tools.intellij.openshift.actions.ActionUtils; import org.jboss.tools.intellij.openshift.actions.NodeUtils; @@ -141,10 +141,10 @@ protected CreateComponentModel getModel(Project project, Odo odo, Predicate doGetOdo() { if (odoFuture == null) { - this.odoFuture = ToolFactory.getInstance() - .createOdo(project) - .thenApply(tool -> { - ApplicationRootNodeOdo odo = new ApplicationRootNodeOdo(tool.get(), tool.isDownloaded(), this, processHelper); - loadProjectModel(odo, project); - return odo; - }); + this.odoFuture = + ReadAction.compute(() -> ToolFactory.getInstance() + .createOdo(project) + .thenApply(tool -> { + ApplicationRootNodeOdo odo = new ApplicationRootNodeOdo(tool.get(), tool.isDownloaded(), this, processHelper); + loadProjectModel(odo, project); + return odo; + })); } return odoFuture; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java index 7ae2064bb..c9ddfe772 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java @@ -18,6 +18,7 @@ import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.Strings; import com.intellij.util.messages.MessageBus; import com.redhat.devtools.intellij.common.utils.ExecHelper; @@ -36,12 +37,20 @@ import io.fabric8.openshift.client.OpenShiftClient; import io.fabric8.openshift.client.dsl.OpenShiftOperatorHubAPIGroupDSL; import io.fabric8.openshift.client.impl.OpenShiftOperatorHubAPIGroupClient; +import org.jboss.tools.intellij.openshift.KubernetesLabels; +import org.jboss.tools.intellij.openshift.utils.Cli; +import org.jboss.tools.intellij.openshift.utils.KubernetesClientExceptionUtils; +import org.jboss.tools.intellij.openshift.utils.Serialization; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.net.HttpURLConnection; -import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -469,8 +478,8 @@ public void deleteComponent(String project, String context, String component, } catch (IOException e) { LOGGER.warn(e.getLocalizedMessage(), e); } - Files.delete(new File(dir, "devfile.yaml").toPath()); - FileUtils.deleteQuietly(new File(dir, PLUGIN_FOLDER)); + FileUtil.delete(new File(dir, "devfile.yaml").toPath()); + FileUtil.delete(new File(dir, PLUGIN_FOLDER).toPath()); } else { args.add("--namespace"); args.add(project); diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/SchemaHelper.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/SchemaHelper.java index 91265b56e..7025c2e9c 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/SchemaHelper.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/SchemaHelper.java @@ -11,80 +11,80 @@ package org.jboss.tools.intellij.openshift.utils.odo; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.commons.lang3.StringUtils; +import com.intellij.openapi.util.text.StringUtil; import java.util.List; import java.util.StringTokenizer; public class SchemaHelper { - private static final String POD_COUNT_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:podCount"; - private static final String BOOLEAN_SWITCH_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:booleanSwitch"; - private static final String CHECKBOX_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:checkbox"; - private static final String NUMBER_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:number"; - private static final String SELECT_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:select:"; + private static final String POD_COUNT_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:podCount"; + private static final String BOOLEAN_SWITCH_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:booleanSwitch"; + private static final String CHECKBOX_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:checkbox"; + private static final String NUMBER_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:number"; + private static final String SELECT_DESCRIPTOR = "urn:alm:descriptor:com.tectonic.ui:select:"; - public static ObjectNode getAnnotatedSchema(ObjectNode schema, List descriptors) { - if (!schema.has("properties")) { - schema.set("properties", schema.objectNode()); - } - if (!schema.get("properties").has("spec")) { - ObjectNode spec = schema.objectNode(); - spec.set("type", spec.textNode("object")); - ((ObjectNode)schema.get("properties")).set("spec", spec); - } - ObjectNode spec = (ObjectNode) schema.get("properties").get("spec"); - for(OperatorCRDSpecDescriptor descriptor : descriptors) { - ObjectNode node = getSchema(spec, descriptor.getPath()); - if (StringUtils.isNotBlank(descriptor.getDisplayName())) { - node.set("displayName", node.textNode(descriptor.getDisplayName())); - } - if (StringUtils.isNotBlank(descriptor.getDisplayName())) { - node.set("description", node.textNode(descriptor.getDescription())); - } - annotateType(node, descriptor); - } - return schema; + public static ObjectNode getAnnotatedSchema(ObjectNode schema, List descriptors) { + if (!schema.has("properties")) { + schema.set("properties", schema.objectNode()); + } + if (!schema.get("properties").has("spec")) { + ObjectNode spec = schema.objectNode(); + spec.set("type", spec.textNode("object")); + ((ObjectNode) schema.get("properties")).set("spec", spec); + } + ObjectNode spec = (ObjectNode) schema.get("properties").get("spec"); + for (OperatorCRDSpecDescriptor descriptor : descriptors) { + ObjectNode node = getSchema(spec, descriptor.getPath()); + if (!StringUtil.isEmptyOrSpaces(descriptor.getDisplayName())) { + node.set("displayName", node.textNode(descriptor.getDisplayName())); + } + if (!StringUtil.isEmptyOrSpaces(descriptor.getDisplayName())) { + node.set("description", node.textNode(descriptor.getDescription())); + } + annotateType(node, descriptor); } + return schema; + } - private static void annotateType(ObjectNode node, OperatorCRDSpecDescriptor crdDescriptor) { - for(String descriptor : crdDescriptor.getDescriptors()) { - if (POD_COUNT_DESCRIPTOR.equals(descriptor)) { - node.set("type", node.textNode("integer")); - } else if (BOOLEAN_SWITCH_DESCRIPTOR.equals(descriptor) || CHECKBOX_DESCRIPTOR.equals(descriptor)) { - node.set("type", node.textNode("boolean")); - } else if (NUMBER_DESCRIPTOR.equals(descriptor)) { - node.set("type", node.textNode("number")); - } else if (descriptor.startsWith(SELECT_DESCRIPTOR)) { - if (!node.has("enum")) { - node.set("enum", node.arrayNode()); - } - String select = descriptor.substring(SELECT_DESCRIPTOR.length()); - node.withArray("enum").add(select); - } + private static void annotateType(ObjectNode node, OperatorCRDSpecDescriptor crdDescriptor) { + for (String descriptor : crdDescriptor.getDescriptors()) { + if (POD_COUNT_DESCRIPTOR.equals(descriptor)) { + node.set("type", node.textNode("integer")); + } else if (BOOLEAN_SWITCH_DESCRIPTOR.equals(descriptor) || CHECKBOX_DESCRIPTOR.equals(descriptor)) { + node.set("type", node.textNode("boolean")); + } else if (NUMBER_DESCRIPTOR.equals(descriptor)) { + node.set("type", node.textNode("number")); + } else if (descriptor.startsWith(SELECT_DESCRIPTOR)) { + if (!node.has("enum")) { + node.set("enum", node.arrayNode()); } + String select = descriptor.substring(SELECT_DESCRIPTOR.length()); + node.withArray("enum").add(select); + } } + } - private static ObjectNode getSchema(ObjectNode schema, String path) { - ObjectNode parent = schema; - StringTokenizer st = new StringTokenizer(path, "."); - while (st.hasMoreTokens()) { - String p = st.nextToken(); - if (!parent.has("properties")) { - parent.set("properties", parent.objectNode()); - } - if (parent.get("properties").has(p)) { - parent = (ObjectNode) parent.get("properties").get(p); - } else { - ObjectNode node = parent.objectNode(); - ((ObjectNode)parent.get("properties")).set(p, node); - if (st.hasMoreTokens()) { - node.set("type", node.textNode("object")); - } else { - node.set("type", node.textNode("string")); - } - parent = node; - } + private static ObjectNode getSchema(ObjectNode schema, String path) { + ObjectNode parent = schema; + StringTokenizer st = new StringTokenizer(path, "."); + while (st.hasMoreTokens()) { + String p = st.nextToken(); + if (!parent.has("properties")) { + parent.set("properties", parent.objectNode()); + } + if (parent.get("properties").has(p)) { + parent = (ObjectNode) parent.get("properties").get(p); + } else { + ObjectNode node = parent.objectNode(); + ((ObjectNode) parent.get("properties")).set(p, node); + if (st.hasMoreTokens()) { + node.set("type", node.textNode("object")); + } else { + node.set("type", node.textNode("string")); } - return parent; + parent = node; + } } + return parent; + } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b13a89d02..5b860d3aa 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -254,9 +254,6 @@ ]]> - - - com.intellij.modules.lang diff --git a/src/test/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationRootNodeOdoTest.java b/src/test/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationRootNodeOdoTest.java index 03646216f..44ca7586b 100644 --- a/src/test/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationRootNodeOdoTest.java +++ b/src/test/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationRootNodeOdoTest.java @@ -10,7 +10,7 @@ ******************************************************************************/ package org.jboss.tools.intellij.openshift.tree.application; -import org.apache.commons.io.FileUtils; +import com.intellij.openapi.util.io.FileUtil; import org.jboss.tools.intellij.openshift.utils.odo.Component; import org.jboss.tools.intellij.openshift.utils.odo.ComponentDescriptor; import org.jboss.tools.intellij.openshift.utils.odo.ComponentFeatures; @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -48,8 +49,8 @@ public class ApplicationRootNodeOdoTest { new ComponentFeatures(), "path2", null); - private static final File tempDir = FileUtils.getTempDirectory(); - private static final File destinationDir = FileUtils.getUserDirectory(); + private File tempDir; + private final File destinationDir = new File(System.getProperty("user.home")); private OdoDelegate odo; private ApplicationsRootNode rootNode; private ApplicationRootNodeOdo rootNodeOdo; @@ -57,6 +58,7 @@ public class ApplicationRootNodeOdoTest { @Before public void before() throws IOException { + tempDir = FileUtil.createTempDirectory("odo-test", ""); this.odo = mock(OdoDelegate.class); this.rootNode = mock(ApplicationsRootNode.class); this.fileOperations = mockFileOperations(); @@ -96,7 +98,7 @@ public void createComponent_should_create_files_copy_and_refresh_them_if_starter // then verify(odo).createComponent(componentType, registryName, component, tempDir.getAbsolutePath(), devfile, starter); verify(fileOperations).createTempDir(any()); - verify(fileOperations).copyTo(tempDir.getAbsoluteFile(), source); + verify(fileOperations).copyTo(tempDir, Path.of(source)); verify(fileOperations).refresh(destinationDir); } diff --git a/src/test/java/org/jboss/tools/intellij/openshift/ui/sandbox/SandboxRegistrationServerMock.java b/src/test/java/org/jboss/tools/intellij/openshift/ui/sandbox/SandboxRegistrationServerMock.java index 1b13f0b18..3499d6a5a 100644 --- a/src/test/java/org/jboss/tools/intellij/openshift/ui/sandbox/SandboxRegistrationServerMock.java +++ b/src/test/java/org/jboss/tools/intellij/openshift/ui/sandbox/SandboxRegistrationServerMock.java @@ -19,131 +19,133 @@ import java.util.concurrent.TimeUnit; public class SandboxRegistrationServerMock { - private static final java.util.concurrent.ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); - private final HttpServer server; + private static final java.util.concurrent.ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); + private final HttpServer server; - private String currentSignupResponse; + private String currentSignupResponse; - private static final String initialSignupResponse = "{\n" + - " \"apiEndpoint\": \"https://api.crc.testing:6443\",\n" + - " \"cheDashboardURL\": \"\",\n" + - " \"clusterName\": \"\",\n" + - " \"company\": \"\",\n" + - " \"compliantUsername\": \"\",\n" + - " \"consoleURL\": \"\",\n" + - " \"familyName\": \"\",\n" + - " \"givenName\": \"\",\n" + - " \"status\": {\n" + - " \"ready\": false,\n" + - " \"reason\": \"PendingApproval\",\n" + - " \"verificationRequired\": true\n" + - " },\n" + - " \"username\": \"\"\n" + - " }"; + private static final String initialSignupResponse = """ + { + "apiEndpoint": "https://api.crc.testing:6443", + "cheDashboardURL": "", + "clusterName": "", + "company": "", + "compliantUsername": "", + "consoleURL": "", + "familyName": "", + "givenName": "", + "status": { + "ready": false, + "reason": "PendingApproval", + "verificationRequired": true + }, + "username": "" + }"""; - private static final String afterVerificationSignupResponse = "{\n" + - " \"apiEndpoint\": \"https://api.crc.testing:6443\",\n" + - " \"cheDashboardURL\": \"\",\n" + - " \"clusterName\": \"\",\n" + - " \"company\": \"\",\n" + - " \"compliantUsername\": \"\",\n" + - " \"consoleURL\": \"\",\n" + - " \"familyName\": \"\",\n" + - " \"givenName\": \"\",\n" + - " \"status\": {\n" + - " \"ready\": false,\n" + - " \"reason\": \"PendingApproval\",\n" + - " \"verificationRequired\": false\n" + - " },\n" + - " \"username\": \"\"\n" + - " }"; + private static final String afterVerificationSignupResponse = """ + { + "apiEndpoint": "https://api.crc.testing:6443", + "cheDashboardURL": "", + "clusterName": "", + "company": "", + "compliantUsername": "", + "consoleURL": "", + "familyName": "", + "givenName": "", + "status": { + "ready": false, + "reason": "PendingApproval", + "verificationRequired": false + }, + "username": "" + }"""; - private static final String afterVerification1SignupResponse = "{\n" + - " \"apiEndpoint\": \"https://api.crc.testing:6443\",\n" + - " \"cheDashboardURL\": \"\",\n" + - " \"clusterName\": \"\",\n" + - " \"company\": \"\",\n" + - " \"compliantUsername\": \"\",\n" + - " \"consoleURL\": \"\",\n" + - " \"familyName\": \"\",\n" + - " \"givenName\": \"\",\n" + - " \"status\": {\n" + - " \"ready\": false,\n" + - " \"reason\": \"\",\n" + - " \"verificationRequired\": false\n" + - " },\n" + - " \"username\": \"\"\n" + - " }"; + private static final String afterVerification1SignupResponse = """ + { + "apiEndpoint": "https://api.crc.testing:6443", + "cheDashboardURL": "", + "clusterName": "", + "company": "", + "compliantUsername": "", + "consoleURL": "", + "familyName": "", + "givenName": "", + "status": { + "ready": false, + "reason": "", + "verificationRequired": false + }, + "username": "" + }"""; - private static final String afterVerification2SignupResponse = "{\n" + - " \"apiEndpoint\": \"https://api.crc.testing:6443\",\n" + - " \"cheDashboardURL\": \"\",\n" + - " \"clusterName\": \"\",\n" + - " \"company\": \"\",\n" + - " \"compliantUsername\": \"\",\n" + - " \"consoleURL\": \"\",\n" + - " \"familyName\": \"\",\n" + - " \"givenName\": \"\",\n" + - " \"status\": {\n" + - " \"ready\": true,\n" + - " \"reason\": \"\",\n" + - " \"verificationRequired\": false\n" + - " },\n" + - " \"username\": \"\"\n" + - " }"; + private static final String afterVerification2SignupResponse = """ + { + "apiEndpoint": "https://api.crc.testing:6443", + "cheDashboardURL": "", + "clusterName": "", + "company": "", + "compliantUsername": "", + "consoleURL": "", + "familyName": "", + "givenName": "", + "status": { + "ready": true, + "reason": "", + "verificationRequired": false + }, + "username": "" + }"""; - public SandboxRegistrationServerMock(int port) throws IOException { - server = HttpServer.create(new InetSocketAddress(InetAddress.getByName(null), port), 0); + public SandboxRegistrationServerMock(int port) throws IOException { + server = HttpServer.create(new InetSocketAddress(InetAddress.getByName(null), port), 0); - server.createContext("/api/v1/signup", exchange -> { - if (exchange.getRequestMethod().equals("GET")) { - if (currentSignupResponse == null) { - exchange.sendResponseHeaders(404, 0); - exchange.getResponseBody().close(); - } else { - exchange.sendResponseHeaders(200, currentSignupResponse.getBytes().length); - exchange.getResponseBody().write(currentSignupResponse.getBytes()); - exchange.getResponseBody().close(); - } - } else if (exchange.getRequestMethod().equals("POST")) { - currentSignupResponse = initialSignupResponse; - exchange.sendResponseHeaders(200, 0); - exchange.getResponseBody().close(); - } - }); + server.createContext("/api/v1/signup", exchange -> { + if (exchange.getRequestMethod().equals("GET")) { + if (currentSignupResponse == null) { + exchange.sendResponseHeaders(404, 0); + exchange.getResponseBody().close(); + } else { + exchange.sendResponseHeaders(200, currentSignupResponse.getBytes().length); + exchange.getResponseBody().write(currentSignupResponse.getBytes()); + exchange.getResponseBody().close(); + } + } else if (exchange.getRequestMethod().equals("POST")) { + currentSignupResponse = initialSignupResponse; + exchange.sendResponseHeaders(200, 0); + exchange.getResponseBody().close(); + } + }); - server.createContext("/api/v1/signup/verification", exchange -> { - if (exchange.getRequestMethod().equals("PUT")) { - exchange.sendResponseHeaders(204, 0); - exchange.getResponseBody().close(); - } else if (exchange.getRequestMethod().equals("GET")) { - currentSignupResponse = afterVerificationSignupResponse; - SCHEDULED_EXECUTOR_SERVICE.schedule(() -> { - currentSignupResponse = afterVerification1SignupResponse; - SCHEDULED_EXECUTOR_SERVICE.schedule(() -> { - currentSignupResponse = afterVerification2SignupResponse; - }, 10, TimeUnit.SECONDS); - }, 10, TimeUnit.SECONDS); - exchange.sendResponseHeaders(200, 0); - exchange.getResponseBody().close(); - } - }); - } + server.createContext("/api/v1/signup/verification", exchange -> { + if (exchange.getRequestMethod().equals("PUT")) { + exchange.sendResponseHeaders(204, 0); + exchange.getResponseBody().close(); + } else if (exchange.getRequestMethod().equals("GET")) { + currentSignupResponse = afterVerificationSignupResponse; + SCHEDULED_EXECUTOR_SERVICE.schedule(() -> { + currentSignupResponse = afterVerification1SignupResponse; + SCHEDULED_EXECUTOR_SERVICE.schedule(() -> { + currentSignupResponse = afterVerification2SignupResponse; + }, 10, TimeUnit.SECONDS); + }, 10, TimeUnit.SECONDS); + exchange.sendResponseHeaders(200, 0); + exchange.getResponseBody().close(); + } + }); + } - public SandboxRegistrationServerMock() throws IOException { - this(3000); - } + public SandboxRegistrationServerMock() throws IOException { + this(3000); + } - public void start() { - server.start(); - } + public void start() { + server.start(); + System.out.println("listening on port 3000....."); + System.out.println("Hit CTRL+C to stop process."); + } - public void stop() { - server.stop(0); - } - - public static void main(String[] args) throws IOException { - SandboxRegistrationServerMock server = new SandboxRegistrationServerMock(); - server.start(); - } + public static void main(String[] args) throws IOException { + SandboxRegistrationServerMock server = new SandboxRegistrationServerMock(); + server.start(); + } }