@@ -317,6 +317,65 @@ func getFromPrunerConfigResourceLevelwithSelector(namespacesSpec map[string]Name
317317 return nil , ""
318318}
319319
320+ // getMatchingSelectorFromConfig retrieves the ConfigMap's selector that matches a resource
321+ func getMatchingSelectorFromConfig (namespacesSpec map [string ]NamespaceSpec , namespace , name string , selector SelectorSpec , resourceType PrunerResourceType ) * SelectorSpec {
322+ prunerResourceSpec , found := namespacesSpec [namespace ]
323+ if ! found {
324+ return nil
325+ }
326+
327+ var resourceSpecs []ResourceSpec
328+ switch resourceType {
329+ case PrunerResourceTypePipelineRun :
330+ resourceSpecs = prunerResourceSpec .PipelineRuns
331+ case PrunerResourceTypeTaskRun :
332+ resourceSpecs = prunerResourceSpec .TaskRuns
333+ }
334+
335+ if len (selector .MatchAnnotations ) == 0 && len (selector .MatchLabels ) == 0 {
336+ return nil
337+ }
338+
339+ for _ , resourceSpec := range resourceSpecs {
340+ for _ , selectorSpec := range resourceSpec .Selector {
341+ annotationsMatch := true
342+ labelsMatch := true
343+
344+ if len (selectorSpec .MatchAnnotations ) > 0 {
345+ if len (selector .MatchAnnotations ) == 0 {
346+ annotationsMatch = false
347+ } else {
348+ for key , value := range selectorSpec .MatchAnnotations {
349+ if resourceAnnotationValue , exists := selector .MatchAnnotations [key ]; ! exists || resourceAnnotationValue != value {
350+ annotationsMatch = false
351+ break
352+ }
353+ }
354+ }
355+ }
356+
357+ if len (selectorSpec .MatchLabels ) > 0 {
358+ if len (selector .MatchLabels ) == 0 {
359+ labelsMatch = false
360+ } else {
361+ for key , value := range selectorSpec .MatchLabels {
362+ if resourceLabelValue , exists := selector .MatchLabels [key ]; ! exists || resourceLabelValue != value {
363+ labelsMatch = false
364+ break
365+ }
366+ }
367+ }
368+ }
369+
370+ if annotationsMatch && labelsMatch {
371+ return & selectorSpec
372+ }
373+ }
374+ }
375+
376+ return nil
377+ }
378+
320379// getResourceFieldData retrieves configuration field values based on enforcedConfigLevel
321380// Design principle: Selector support ONLY for namespace-level ConfigMaps, NOT global ConfigMaps
322381//
@@ -650,6 +709,20 @@ func (ps *prunerConfigStore) GetTaskFailedHistoryLimitCount(namespace, name stri
650709 return getResourceFieldData (ps .globalConfig , ps .namespaceConfig , namespace , name , selector , PrunerResourceTypeTaskRun , PrunerFieldTypeFailedHistoryLimit , enforcedConfigLevel )
651710}
652711
712+ // GetPipelineMatchingSelector returns the ConfigMap's selector that matches a PipelineRun.
713+ func (ps * prunerConfigStore ) GetPipelineMatchingSelector (namespace , name string , selector SelectorSpec ) * SelectorSpec {
714+ ps .mutex .RLock ()
715+ defer ps .mutex .RUnlock ()
716+ return getMatchingSelectorFromConfig (ps .namespaceConfig , namespace , name , selector , PrunerResourceTypePipelineRun )
717+ }
718+
719+ // GetTaskMatchingSelector returns the ConfigMap's selector that matches a TaskRun.
720+ func (ps * prunerConfigStore ) GetTaskMatchingSelector (namespace , name string , selector SelectorSpec ) * SelectorSpec {
721+ ps .mutex .RLock ()
722+ defer ps .mutex .RUnlock ()
723+ return getMatchingSelectorFromConfig (ps .namespaceConfig , namespace , name , selector , PrunerResourceTypeTaskRun )
724+ }
725+
653726// ValidateGlobalConfig validates a GlobalConfig struct directly without ConfigMap conversion
654727// This is a convenience function for validating global config and all nested namespace configs
655728// without the overhead of serialization/deserialization through ConfigMaps.
0 commit comments