Skip to content

Commit ad2eb27

Browse files
committed
fix: search result for selector is template labels (#642)
1 parent 1bcfbe4 commit ad2eb27

File tree

6 files changed

+120
-29
lines changed

6 files changed

+120
-29
lines changed

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/usage/LabelsFilter.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
package com.redhat.devtools.intellij.kubernetes.usage
1212

1313
import com.intellij.psi.PsiElement
14-
import com.intellij.psi.util.PsiElementFilter
1514
import com.redhat.devtools.intellij.common.validation.KubernetesTypeInfo
1615
import com.redhat.devtools.intellij.kubernetes.editor.util.areMatchingMatchExpressions
1716
import com.redhat.devtools.intellij.kubernetes.editor.util.areMatchingMatchLabels
@@ -38,7 +37,7 @@ import com.redhat.devtools.intellij.kubernetes.editor.util.isStatefulSet
3837
/**
3938
* A filter that accepts labels, that are matching a given selector.
4039
*/
41-
class LabelsFilter(selector: PsiElement): PsiElementFilter {
40+
class LabelsFilter(selector: PsiElement): PsiElementMappingsFilter {
4241

4342
private val selectorResource: PsiElement? by lazy {
4443
selector.getResource()
@@ -129,6 +128,11 @@ class LabelsFilter(selector: PsiElement): PsiElementFilter {
129128
}
130129
}
131130

131+
override fun getMatchingElement(element: PsiElement): PsiElement? {
132+
val labeledType = element.getKubernetesTypeInfo() ?: return null
133+
return getLabels(labeledType, element, selectorResourceType)
134+
}
135+
132136
private fun getLabels(
133137
labeledType: KubernetesTypeInfo,
134138
labeledResource: PsiElement,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Red Hat, Inc.
3+
* Distributed under license by Red Hat, Inc. All rights reserved.
4+
* This program is made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution,
6+
* and is available at http://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* Red Hat, Inc. - initial API and implementation
10+
******************************************************************************/
11+
package com.redhat.devtools.intellij.kubernetes.usage
12+
13+
import com.intellij.psi.PsiElement
14+
import com.intellij.psi.util.PsiElementFilter
15+
16+
interface PsiElementMappingsFilter: PsiElementFilter {
17+
fun getMatchingElement(element: PsiElement): PsiElement?
18+
}

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/usage/SelectorUsageSearcher.kt

+5-17
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import com.intellij.usages.Usage
2020
import com.intellij.usages.UsageInfo2UsageAdapter
2121
import com.intellij.util.Processor
2222
import com.redhat.devtools.intellij.kubernetes.editor.util.PsiElements
23-
import com.redhat.devtools.intellij.kubernetes.editor.util.getLabels
2423
import com.redhat.devtools.intellij.kubernetes.editor.util.getResource
25-
import com.redhat.devtools.intellij.kubernetes.editor.util.getSelector
2624
import com.redhat.devtools.intellij.kubernetes.editor.util.isLabels
2725
import com.redhat.devtools.intellij.kubernetes.editor.util.isSelector
2826

@@ -53,9 +51,10 @@ class SelectorUsageSearcher : CustomUsageSearcher() {
5351
**/
5452
//val searchScope = options.searchScope
5553
//if (searchScope.contains(file.virtualFile)) {
56-
getAllMatching(searchParameter)
54+
val filter = getFilter(searchParameter) ?: return@run
55+
getAllMatching(searchParameter, filter)
5756
.forEach { matchingElement ->
58-
val searchResult = getMatchingAttribute(searchParameter, matchingElement)
57+
val searchResult = filter.getMatchingElement(matchingElement)?.parent
5958
if (searchResult != null) {
6059
processor.process(
6160
UsageInfo2UsageAdapter(UsageInfo(searchResult))
@@ -65,15 +64,14 @@ class SelectorUsageSearcher : CustomUsageSearcher() {
6564
}
6665
}
6766

68-
private fun getAllMatching(searchParameter: PsiElement): Collection<PsiElement> {
67+
private fun getAllMatching(searchParameter: PsiElement, filter: PsiElementFilter): Collection<PsiElement> {
6968
val fileType = searchParameter.containingFile.fileType
7069
val project = searchParameter.project
71-
val filter = getFilter(searchParameter) ?: return emptyList()
7270
return PsiElements.getAllNoExclusions(fileType, project)
7371
.filter(filter::isAccepted)
7472
}
7573

76-
private fun getFilter(searchParameter: PsiElement): PsiElementFilter? {
74+
private fun getFilter(searchParameter: PsiElement): PsiElementMappingsFilter? {
7775
val resource = searchParameter.getResource() ?: return null
7876
return when {
7977
searchParameter.isSelector() ->
@@ -87,14 +85,4 @@ class SelectorUsageSearcher : CustomUsageSearcher() {
8785
}
8886
}
8987

90-
private fun getMatchingAttribute(searchParameter: PsiElement, matchingElement: PsiElement): PsiElement? {
91-
return when {
92-
searchParameter.isSelector() ->
93-
matchingElement.getLabels()?.parent // beginning of labels block/property
94-
searchParameter.isLabels() ->
95-
matchingElement.getSelector()?.parent // beginning of selector block/property
96-
else ->
97-
null
98-
}
99-
}
10088
}

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/usage/SelectorsFilter.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ import com.intellij.psi.PsiElement
1414
import com.intellij.psi.util.PsiElementFilter
1515
import com.redhat.devtools.intellij.common.validation.KubernetesTypeInfo
1616
import com.redhat.devtools.intellij.kubernetes.editor.util.getKubernetesTypeInfo
17+
import com.redhat.devtools.intellij.kubernetes.editor.util.getSelector
1718
import com.redhat.devtools.intellij.kubernetes.editor.util.hasLabels
1819
import com.redhat.devtools.intellij.kubernetes.editor.util.hasSelector
1920
import com.redhat.devtools.intellij.kubernetes.editor.util.hasTemplateLabels
2021

2122
/**
2223
* A filter that accepts selectors that are matching a given label
2324
*/
24-
class SelectorsFilter(private val labeledResource: PsiElement): PsiElementFilter {
25+
class SelectorsFilter(private val labeledResource: PsiElement): PsiElementMappingsFilter {
2526

2627
private val labeledResourceType: KubernetesTypeInfo? by lazy {
2728
labeledResource.getKubernetesTypeInfo()
@@ -32,6 +33,10 @@ class SelectorsFilter(private val labeledResource: PsiElement): PsiElementFilter
3233
|| labeledResource.hasTemplateLabels()
3334
}
3435

36+
override fun getMatchingElement(element: PsiElement): PsiElement? {
37+
return element.getSelector()
38+
}
39+
3540
override fun isAccepted(toAccept: PsiElement): Boolean {
3641
if (labeledResourceType == null
3742
|| !hasLabels

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/usage/LabelsFilterTest.kt

+39-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class LabelsFilterTest {
3535

3636
private lateinit var hasMatchLabelsAndExpressions: YAMLMapping
3737
private lateinit var matchingPod: YAMLMapping
38+
private lateinit var matchingPodLabels: YAMLMapping
3839

3940
@Before
4041
fun before() {
@@ -59,11 +60,11 @@ class LabelsFilterTest {
5960
this.matchingPod = createYAMLMapping(listOf(
6061
createYAMLKeyValue("kind", "Pod")
6162
))
62-
matchingPod.createLabels(
63+
this.matchingPodLabels = matchingPod.createLabels(
6364
createYAMLMapping(listOf(
6465
createYAMLKeyValue(LABEL_KEY, LABEL_VALUE)
6566
))
66-
)
67+
).value as YAMLMapping
6768

6869
this.filter = LabelsFilter(hasMatchLabelsAndExpressions)
6970
}
@@ -213,4 +214,40 @@ class LabelsFilterTest {
213214
assertThat(isAccepted).isTrue()
214215
}
215216

217+
@Test
218+
fun `#getMatchingElement returns pod labels that match given deployment selector`() {
219+
// given
220+
// when
221+
val matchingElement = filter.getMatchingElement(matchingPod)
222+
// then
223+
assertThat(matchingElement).isEqualTo(matchingPodLabels)
224+
}
225+
226+
@Test
227+
fun `#getMatchingElement returns deployment template labels that match given deployment selector`() {
228+
// given
229+
val matchingTemplateLabels = createYAMLMapping(listOf(
230+
createYAMLKeyValue("kind", "Deployment")
231+
))
232+
val templateLabels = createYAMLMapping(listOf(
233+
createYAMLKeyValue(LABEL_KEY, LABEL_VALUE) // matching labels in spec>template
234+
))
235+
matchingTemplateLabels.createTemplate(
236+
createYAMLMapping(listOf(
237+
createYAMLKeyValue(
238+
"metadata",
239+
createYAMLMapping(listOf(
240+
createYAMLKeyValue(
241+
"labels",
242+
templateLabels
243+
)
244+
))
245+
)
246+
))
247+
)
248+
// when
249+
val matchingElement = filter.getMatchingElement(matchingTemplateLabels)
250+
// then
251+
assertThat(matchingElement).isEqualTo(templateLabels)
252+
}
216253
}

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/usage/SelectorsFilterTest.kt

+46-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import com.redhat.devtools.intellij.kubernetes.editor.mocks.createTemplate
1919
import com.redhat.devtools.intellij.kubernetes.editor.mocks.createYAMLSequenceItem
2020
import com.redhat.devtools.intellij.kubernetes.editor.mocks.createYAMLMapping
2121
import com.redhat.devtools.intellij.kubernetes.editor.mocks.createYAMLSequence
22+
import com.redhat.devtools.intellij.kubernetes.editor.util.getLabels
23+
import com.redhat.devtools.intellij.kubernetes.editor.util.getSelector
24+
import com.redhat.devtools.intellij.kubernetes.editor.util.getTemplateLabels
2225
import org.assertj.core.api.Assertions.assertThat
2326
import org.jetbrains.yaml.psi.YAMLMapping
2427
import org.junit.Before
@@ -34,7 +37,7 @@ class SelectorsFilterTest {
3437
private lateinit var filter: SelectorsFilter
3538

3639
private lateinit var pod: YAMLMapping
37-
private lateinit var podMatchingSelector: YAMLMapping
40+
private lateinit var deploymentMatchingPod: YAMLMapping
3841

3942
@Before
4043
fun before() {
@@ -45,10 +48,10 @@ class SelectorsFilterTest {
4548
createYAMLMapping(listOf(createYAMLKeyValue(LABEL_KEY, LABEL_VALUE)))
4649
)
4750

48-
this.podMatchingSelector = createYAMLMapping(listOf(
51+
this.deploymentMatchingPod = createYAMLMapping(listOf(
4952
createYAMLKeyValue("kind", "Deployment")
5053
))
51-
this.podMatchingSelector.createSelector(
54+
this.deploymentMatchingPod.createSelector(
5255
createYAMLMapping(listOf(
5356
createYAMLKeyValue(
5457
"matchLabels",
@@ -75,7 +78,7 @@ class SelectorsFilterTest {
7578
fun `#isAccepted returns true if filtered element labels matching all selector labels and expressions`() {
7679
// given
7780
// when
78-
val isAccepted = filter.isAccepted(podMatchingSelector)
81+
val isAccepted = filter.isAccepted(deploymentMatchingPod)
7982
// then
8083
assertThat(isAccepted).isTrue()
8184
}
@@ -221,7 +224,7 @@ class SelectorsFilterTest {
221224
@Test
222225
fun `#isAccepted returns true if filtering is deployment with template labels and filtered is deployment with matching labels`() {
223226
// given
224-
podMatchingSelector.createTemplate(
227+
deploymentMatchingPod.createTemplate(
225228
createYAMLMapping(listOf(
226229
createYAMLKeyValue(
227230
"metadata",
@@ -236,10 +239,46 @@ class SelectorsFilterTest {
236239
)
237240
))
238241
)
239-
val filter = SelectorsFilter(podMatchingSelector)
242+
val filter = SelectorsFilter(pod)
240243
// when
241-
val isAccepted = filter.isAccepted(podMatchingSelector)
244+
val isAccepted = filter.isAccepted(deploymentMatchingPod)
242245
// then
243246
assertThat(isAccepted).isTrue()
244247
}
248+
249+
@Test
250+
fun `#getMatchingElement returns deployment selector that matches given pod labels`() {
251+
// given
252+
val filter = SelectorsFilter(deploymentMatchingPod)
253+
// when
254+
val matchingElement = filter.getMatchingElement(deploymentMatchingPod)
255+
// then
256+
assertThat(matchingElement).isEqualTo(deploymentMatchingPod.getSelector())
257+
}
258+
259+
@Test
260+
fun `#getMatchingElement returns deployment selector that matches given deployment template labels`() {
261+
// given
262+
deploymentMatchingPod.createTemplate(
263+
createYAMLMapping(listOf(
264+
createYAMLKeyValue(
265+
"metadata",
266+
createYAMLMapping(listOf(
267+
createYAMLKeyValue(
268+
"labels",
269+
createYAMLMapping(listOf(
270+
createYAMLKeyValue(LABEL_KEY, LABEL_VALUE) // matching labels in spec>template
271+
))
272+
)
273+
))
274+
)
275+
))
276+
)
277+
val filter = SelectorsFilter(deploymentMatchingPod)
278+
// when
279+
val matchingElement = filter.getMatchingElement(deploymentMatchingPod)
280+
// then
281+
assertThat(matchingElement).isEqualTo(deploymentMatchingPod.getSelector())
282+
}
283+
245284
}

0 commit comments

Comments
 (0)