From 717174e1c252e7ef239c9d5f96bf0ac89d489440 Mon Sep 17 00:00:00 2001 From: Alexey Merkulov Date: Wed, 13 Jun 2018 17:10:00 +0300 Subject: [PATCH] RUBY-19094 Reworked existed Kubernetes-Yaml inspection IDEA-CR-33445 --- plugins/yaml/resources/META-INF/plugin.xml | 5 ++ .../YAMLDuplicatedKeys.html | 6 ++ .../resources/messages/YAMLBundle.properties | 5 +- .../YAMLDuplicatedKeysInspection.java} | 30 ++++---- .../highlighting/YAMLHighlightingTest.java | 6 ++ .../yaml/highlighting/data/duplicatedKeys.yml | 10 +++ .../yaml/intention/YAMLIntentionTest.java | 41 +++++++++++ .../intention/data/deleteDuplicatedKey.txt | 67 ++++++++++++++++++ .../intention/data/deleteDuplicatedKey.yml | 68 +++++++++++++++++++ 9 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 plugins/yaml/resources/inspectionDescriptions/YAMLDuplicatedKeys.html rename plugins/yaml/src/org/jetbrains/yaml/{meta/impl/YamlDuplicatedKeysInspectionBase.java => inspections/YAMLDuplicatedKeysInspection.java} (73%) create mode 100644 plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/data/duplicatedKeys.yml create mode 100644 plugins/yaml/testSrc/org/jetbrains/yaml/intention/YAMLIntentionTest.java create mode 100644 plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.txt create mode 100644 plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.yml diff --git a/plugins/yaml/resources/META-INF/plugin.xml b/plugins/yaml/resources/META-INF/plugin.xml index ad9cb6939fa9..3da6e351d351 100644 --- a/plugins/yaml/resources/META-INF/plugin.xml +++ b/plugins/yaml/resources/META-INF/plugin.xml @@ -44,6 +44,11 @@ key="inspections.recursive.alias.name" level="ERROR" groupKey="inspections.group.name" enabledByDefault="true" implementationClass="org.jetbrains.yaml.inspections.YAMLRecursiveAliasInspection"/> + diff --git a/plugins/yaml/resources/inspectionDescriptions/YAMLDuplicatedKeys.html b/plugins/yaml/resources/inspectionDescriptions/YAMLDuplicatedKeys.html new file mode 100644 index 000000000000..258a76ce753a --- /dev/null +++ b/plugins/yaml/resources/inspectionDescriptions/YAMLDuplicatedKeys.html @@ -0,0 +1,6 @@ + + +This inspection detects duplicated keys in YAML files and highlights them in the editor. +
+ + \ No newline at end of file diff --git a/plugins/yaml/resources/messages/YAMLBundle.properties b/plugins/yaml/resources/messages/YAMLBundle.properties index 5aac709b4fe8..9564a3f1083a 100644 --- a/plugins/yaml/resources/messages/YAMLBundle.properties +++ b/plugins/yaml/resources/messages/YAMLBundle.properties @@ -23,8 +23,8 @@ YamlMissingKeysInspectionBase.add.missing.keys.quickfix.name=Add missing keys YamlNonEditableKeysInspectionBase.noneditable.key=Key ''{0}'' is not modifiable by user YamlDeprecatedKeysInspectionBase.deprecated.key=Key ''{0}'' is deprecated -YamlDuplicatedKeysInspectionBase.duplicated.key=Key ''{0}'' is duplicated -YamlDuplicatedKeysInspectionBase.remove.key.quickfix.name=Remove key +YAMLDuplicatedKeysInspection.duplicated.key=Key ''{0}'' is duplicated +YAMLDuplicatedKeysInspection.remove.key.quickfix.name=Remove key YamlNonEditableKeyInspectionBase.strip.noneditable.keys.quickfix.name=Remove all non-editable keys from the file YamlUnknownValuesInspectionBase.error.value.is.required=Value is required @@ -69,3 +69,4 @@ inspections.unresolved.alias.name=Unresolved alias inspections.unresolved.alias.message=Can''t resolve alias {0} inspections.recursive.alias.name=Recursive alias inspections.recursive.alias.message=Alias can't be recursive +inspections.duplicated.keys.name=Duplicated YAML keys \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/meta/impl/YamlDuplicatedKeysInspectionBase.java b/plugins/yaml/src/org/jetbrains/yaml/inspections/YAMLDuplicatedKeysInspection.java similarity index 73% rename from plugins/yaml/src/org/jetbrains/yaml/meta/impl/YamlDuplicatedKeysInspectionBase.java rename to plugins/yaml/src/org/jetbrains/yaml/inspections/YAMLDuplicatedKeysInspection.java index cbac7ba6d29f..acd66c6a9fc7 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/meta/impl/YamlDuplicatedKeysInspectionBase.java +++ b/plugins/yaml/src/org/jetbrains/yaml/inspections/YAMLDuplicatedKeysInspection.java @@ -1,43 +1,37 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.yaml.meta.impl; +package org.jetbrains.yaml.inspections; import com.intellij.codeInspection.*; -import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; import com.intellij.util.containers.MultiMap; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.yaml.YAMLBundle; import org.jetbrains.yaml.psi.YAMLKeyValue; import org.jetbrains.yaml.psi.YAMLMapping; +import org.jetbrains.yaml.psi.YamlPsiElementVisitor; import java.util.Collection; import java.util.Map; -@ApiStatus.Experimental -public abstract class YamlDuplicatedKeysInspectionBase extends LocalInspectionTool { - +public class YAMLDuplicatedKeysInspection extends LocalInspectionTool { @NotNull @Override public final PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { - return new PsiElementVisitor() { + return new YamlPsiElementVisitor() { @Override - public void visitElement(PsiElement element) { - ProgressIndicatorProvider.checkCanceled(); - - if (!(element instanceof YAMLMapping)) { - return; - } - + public void visitMapping(@NotNull YAMLMapping mapping) { MultiMap occurrences = new MultiMap<>(); - for (YAMLKeyValue keyValue : ((YAMLMapping)element).getKeyValues()) { + for (YAMLKeyValue keyValue : mapping.getKeyValues()) { final String keyName = keyValue.getKeyText().trim(); + // http://yaml.org/type/merge.html + if (keyName.equals("<<")) { + continue; + } if (!keyName.isEmpty()) { occurrences.putValue(keyName, keyValue); } @@ -48,7 +42,7 @@ public abstract class YamlDuplicatedKeysInspectionBase extends LocalInspectionTo entry.getValue().forEach((duplicatedKey) -> { assert duplicatedKey.getKey() != null; holder.registerProblem(duplicatedKey.getKey(), - YAMLBundle.message("YamlDuplicatedKeysInspectionBase.duplicated.key", entry.getKey()), + YAMLBundle.message("YAMLDuplicatedKeysInspection.duplicated.key", entry.getKey()), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveDuplicatedKeyQuickFix(duplicatedKey)); }); } @@ -68,7 +62,7 @@ public abstract class YamlDuplicatedKeysInspectionBase extends LocalInspectionTo @NotNull @Override public String getFamilyName() { - return YAMLBundle.message("YamlDuplicatedKeysInspectionBase.remove.key.quickfix.name"); + return YAMLBundle.message("YAMLDuplicatedKeysInspection.remove.key.quickfix.name"); } @Override diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/YAMLHighlightingTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/YAMLHighlightingTest.java index a7b31ee700cf..3d2adcba47d5 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/YAMLHighlightingTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/YAMLHighlightingTest.java @@ -3,6 +3,7 @@ package org.jetbrains.yaml.highlighting; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import org.jetbrains.yaml.inspections.YAMLDuplicatedKeysInspection; import org.jetbrains.yaml.inspections.YAMLRecursiveAliasInspection; import org.jetbrains.yaml.inspections.YAMLUnresolvedAliasInspection; @@ -34,6 +35,11 @@ public class YAMLHighlightingTest extends LightPlatformCodeInsightFixtureTestCas doTest(); } + public void testDuplicatedKeys() { + myFixture.enableInspections(YAMLDuplicatedKeysInspection.class); + doTest(); + } + private void doTest() { myFixture.testHighlighting(true, false, false, getTestName(true) + ".yml"); } diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/data/duplicatedKeys.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/data/duplicatedKeys.yml new file mode 100644 index 000000000000..0778da02ae0e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/highlighting/data/duplicatedKeys.yml @@ -0,0 +1,10 @@ +map1: &an1 + testKey: hello + anotherKey: world + testKey: duplicate +map2: &an2 + someKey: some value from map 2 +map3: + <<: *an1 + <<: *an2 + ownKey: some value from map 3 \ No newline at end of file diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/intention/YAMLIntentionTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/YAMLIntentionTest.java new file mode 100644 index 000000000000..d07f31d7b8c7 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/YAMLIntentionTest.java @@ -0,0 +1,41 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.yaml.intention; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.yaml.inspections.YAMLDuplicatedKeysInspection; + +import java.util.List; +import java.util.Optional; + +public class YAMLIntentionTest extends LightPlatformCodeInsightFixtureTestCase { + @Override + protected String getTestDataPath() { + return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/"; + } + + public void testDeleteDuplicatedKey() { + myFixture.enableInspections(YAMLDuplicatedKeysInspection.class); + doTest("Remove key"); + } + + @SuppressWarnings("SameParameterValue") + private void doTest(@NotNull String intentionName) { + String testName = getTestName(true); + myFixture.configureByFile(testName + ".yml"); + IntentionAction quickFix = findIntention(intentionName); + myFixture.launchAction(quickFix); + myFixture.checkResultByFile(testName + ".txt"); + } + + @NotNull + private IntentionAction findIntention(@NotNull String name) { + List intentions = myFixture.getAvailableIntentions(); + Optional intention = + intentions.stream().filter(it -> it.getText().contains(name)).findFirst(); + assert intention.isPresent(); + return intention.get(); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.txt b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.txt new file mode 100644 index 000000000000..a9761163150f --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.txt @@ -0,0 +1,67 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" + labels: + app: psi-agent + version: 2017.2.2057 + name: psi-agent + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: psi-agent + version: 2017.2.2057 + strategy: + rollingUpdate: + maxSurge: abc + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + app: psi-agent + version: 2017.2.2057 + name: psi-agent + spec: + containers: + - image: jetbrains/upsource-psi-agent:2017.2.2057 + imagePullPolicy: IfNotPresent + name: psi-agent + resources: {} + securityContext: + privileged: false + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + env: + - name: HUB_URL + value: http://hub-service:8088/hub + - name: UPSOURCE_SERVICE_ID + value: d574afce-a315-4bb2-b2a7-6c726b3e1080 + - name: UPSOURCE_SERVICE_SECRET + value: lxnbMouMvGId + - name: UPSOURCE_URL + value: http://35.195.40.139 + - name: UPSOURCE_SERVICE_PORT + value: "10061" + - name: UPSOURCE_STATISTICS_UPLOAD + value: "false" + - name: CASSANDRA_HOSTS + value: cassandra + - name: CASSANDRA_PORT + value: "9042" + - name: UPSOURCE_DATABASE + value: datastax + - name: UPSOURCE_SUBNET + value: 10.60.0.0/16 + - name: UPSOURCE_PSI_BROKER_PORT + value: "11111" + - name: UPSOURCE_PSI_BROKER_HOST + value: psi-broker + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.yml b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.yml new file mode 100644 index 000000000000..211da8132303 --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/intention/data/deleteDuplicatedKey.yml @@ -0,0 +1,68 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" + labels: + app: psi-agent + version: 2017.2.2057 + name: psi-agent + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: psi-agent + version: 2017.2.2057 + strategy: + rollingUpdate: + maxSurge: abc + maxUnavailable: 1 + type: RollingUpdate + replicas : 2 + template: + metadata: + labels: + app: psi-agent + version: 2017.2.2057 + name: psi-agent + spec: + containers: + - image: jetbrains/upsource-psi-agent:2017.2.2057 + imagePullPolicy: IfNotPresent + name: psi-agent + resources: {} + securityContext: + privileged: false + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + env: + - name: HUB_URL + value: http://hub-service:8088/hub + - name: UPSOURCE_SERVICE_ID + value: d574afce-a315-4bb2-b2a7-6c726b3e1080 + - name: UPSOURCE_SERVICE_SECRET + value: lxnbMouMvGId + - name: UPSOURCE_URL + value: http://35.195.40.139 + - name: UPSOURCE_SERVICE_PORT + value: "10061" + - name: UPSOURCE_STATISTICS_UPLOAD + value: "false" + - name: CASSANDRA_HOSTS + value: cassandra + - name: CASSANDRA_PORT + value: "9042" + - name: UPSOURCE_DATABASE + value: datastax + - name: UPSOURCE_SUBNET + value: 10.60.0.0/16 + - name: UPSOURCE_PSI_BROKER_PORT + value: "11111" + - name: UPSOURCE_PSI_BROKER_HOST + value: psi-broker + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30