Skip to content

SANDBOX1318: update filter function to accept runtimeclient object/runtimeobject#489

Closed
fbm3307 wants to merge 3 commits intocodeready-toolchain:masterfrom
fbm3307:ks143process
Closed

SANDBOX1318: update filter function to accept runtimeclient object/runtimeobject#489
fbm3307 wants to merge 3 commits intocodeready-toolchain:masterfrom
fbm3307:ks143process

Conversation

@fbm3307
Copy link
Contributor

@fbm3307 fbm3307 commented Aug 19, 2025

This PR is related to the discussion codeready-toolchain/member-operator#680 (comment)
to improve the filter function

related PR
Member-operator: codeready-toolchain/member-operator#692

Summary by CodeRabbit

  • New Features

    • Filtering now accepts multiple object-slice types (in addition to the previous format), broadening compatibility with Kubernetes object representations while preserving prior behavior.
    • Unsupported input types produce a clear, descriptive error.
  • Tests

    • Added table-driven tests covering all supported input representations and error cases, improving coverage and consistency.

…ntimeobject

Signed-off-by: Feny Mehta <fbm3307@gmail.com>
@coderabbitai
Copy link

coderabbitai bot commented Aug 19, 2025

Walkthrough

Filter now accepts interface{} and normalizes supported slice types ([]runtime.RawExtension, []runtime.Object, []runtimeclient.Object) into []runtime.RawExtension, applies FilterFunc(s) uniformly, and panics for unsupported input types. Tests expanded to cover all three input shapes and panic behavior.

Changes

Cohort / File(s) Summary
Template filter generalization
pkg/template/filter.go
Changed Filter signature to objs interface{}; added type-switch to normalize []runtime.RawExtension, []runtime.Object, and []runtimeclient.Object into []runtime.RawExtension; unified filtering loop with label for early continue; preallocated result slice; added imports fmt and runtimeclient; panic on unsupported types.
Filter tests for multiple input types
pkg/template/filter_test.go
Rewrote tests into table-driven suite covering inputs as []runtime.RawExtension, []runtime.Object, and []runtimeclient.Object; added shared unstructured fixtures; added TestFilterUnsupportedType to assert panic on unsupported types (e.g., []string); imported runtimeclient.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant Filter as template.Filter
  participant TS as TypeSwitch/Normalizer
  participant FL as FilterFuncs
  participant Result as ResultSlice

  Caller->>Filter: Filter(objs:any, filters...)
  Filter->>TS: Inspect and normalize objs
  alt Supported type -> normalized []RawExtension
    TS-->>Filter: normalized slice
    loop per object
      Filter->>FL: Apply FilterFunc(s)
      alt any returns false
        Note right of Filter: continue to next object
      else all true
        Filter->>Result: append object
      end
    end
    Filter-->>Caller: return []runtime.RawExtension
  else Unsupported type
    TS-->>Filter: unsupported
    Filter-->>Caller: panic(fmt.Sprintf(...))
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop through lists of objects bright,
Three roads converge into one sight.
I nudge the noisy, keep the fine,
Skip what's wrong and mark the line.
A twitch, a filter—carrots right! 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Aug 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.82%. Comparing base (76384e2) to head (b62c5d1).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #489      +/-   ##
==========================================
+ Coverage   78.62%   78.82%   +0.20%     
==========================================
  Files          52       52              
  Lines        2638     2663      +25     
==========================================
+ Hits         2074     2099      +25     
  Misses        502      502              
  Partials       62       62              
Files with missing lines Coverage Δ
pkg/template/filter.go 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: Feny Mehta <fbm3307@gmail.com>
@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
pkg/template/filter.go (3)

27-29: Document the panic behavior in the exported function comment

Since the function now panics on unsupported input types, the doc should state this explicitly to set caller expectations and improve godoc.

-// Filter filters the given objs to return only those matching the given filters (if any)
-// Accepts []runtime.RawExtension, []runtime.Object, or []runtimeclient.Object
+// Filter filters the given objs to return only those matching the given filters (if any).
+// Accepts []runtime.RawExtension, []runtime.Object, or []runtimeclient.Object.
+// Panics on unsupported input types.
 func Filter(objs interface{}, filters ...FilterFunc) []runtime.RawExtension {

30-32: Handle nil input gracefully to avoid surprising panic on Filter(nil)

With the new interface{} signature, it’s easy to accidentally pass a nil interface (e.g., Filter(nil)). Today that will fall through to default and panic. Returning an empty slice is safer and aligns with common Go conventions.

 	// Convert input to []runtime.RawExtension
 	var rawExtensions []runtime.RawExtension
+	// Gracefully handle a nil interface input
+	if objs == nil {
+		return nil
+	}

33-57: Remove redundant type assertions and an extra allocation

You can split the combined case into two distinct cases. This removes the second type assertion and the temporary []runtime.Object allocation for the []runtimeclient.Object path, improving clarity and shaving an allocation.

-	switch v := objs.(type) {
-	case []runtime.RawExtension:
-		rawExtensions = v
-	case []runtime.Object, []runtimeclient.Object:
-		// Handle both runtime.Object and runtimeclient.Object the same way
-		// since runtimeclient.Object embeds runtime.Object
-		var objects []runtime.Object
-		if runtimeObjs, ok := v.([]runtime.Object); ok {
-			objects = runtimeObjs
-		} else {
-			// Convert []runtimeclient.Object to []runtime.Object
-			clientObjs := v.([]runtimeclient.Object)
-			objects = make([]runtime.Object, len(clientObjs))
-			for i, obj := range clientObjs {
-				objects[i] = obj
-			}
-		}
-
-		rawExtensions = make([]runtime.RawExtension, len(objects))
-		for i, obj := range objects {
-			rawExtensions[i] = runtime.RawExtension{Object: obj}
-		}
-	default:
-		panic(fmt.Sprintf("unsupported type %T for Filter function. Supported types: []runtime.RawExtension, []runtime.Object, []runtimeclient.Object", objs))
-	}
+	switch v := objs.(type) {
+	case []runtime.RawExtension:
+		rawExtensions = v
+	case []runtime.Object:
+		rawExtensions = make([]runtime.RawExtension, len(v))
+		for i, obj := range v {
+			rawExtensions[i] = runtime.RawExtension{Object: obj}
+		}
+	case []runtimeclient.Object:
+		rawExtensions = make([]runtime.RawExtension, len(v))
+		for i, obj := range v {
+			rawExtensions[i] = runtime.RawExtension{Object: obj}
+		}
+	default:
+		panic(fmt.Sprintf("unsupported type %T for Filter function. Supported types: []runtime.RawExtension, []runtime.Object, []runtimeclient.Object", objs))
+	}
pkg/template/filter_test.go (1)

373-383: Optionally assert the panic message to harden the contract

Current test asserts a panic occurs, which is fine. If you want to pin the contract further, assert the message (or at least that it contains "unsupported type"). This is optional but can prevent accidental behavior changes.

-		assert.Panics(t, func() {
-			template.Filter(unsupportedSlice)
-		})
+		assert.PanicsWithValue(t,
+			"unsupported type []string for Filter function. Supported types: []runtime.RawExtension, []runtime.Object, []runtimeclient.Object",
+			func() {
+				template.Filter(unsupportedSlice)
+			},
+		)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 76384e2 and 413fb36.

📒 Files selected for processing (2)
  • pkg/template/filter.go (2 hunks)
  • pkg/template/filter_test.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
pkg/template/filter_test.go (2)
pkg/test/testing_t.go (1)
  • T (4-11)
pkg/template/filter.go (3)
  • Filter (29-72)
  • RetainNamespaces (12-15)
  • RetainAllButNamespaces (18-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Verify Dependencies
🔇 Additional comments (6)
pkg/template/filter.go (3)

3-8: Imports look good

New imports are minimal and justified by the added functionality.


59-70: Filtering loop is clear and preserves order

Label-based early-continue is succinct, avoids extra flags, and keeps the original order intact. Capacity preallocation is a nice touch.


28-29: All template.Filter call sites use only supported slice types
I’ve reviewed every template.Filter invocation across the codebase—all are passed one of the three allowed slice types ([]runtime.RawExtension, []runtime.Object, or []runtimeclient.Object), and there’s even a dedicated test that panics on an unsupported slice. No unexpected argument types found; this change is safe as-is.

pkg/template/filter_test.go (3)

12-12: Import for runtimeclient is appropriate

Needed for exercising the []runtimeclient.Object path.


221-295: Good coverage for []runtime.Object input

Validates no-filter behavior and both filter predicates with order preservation. Solid.


297-371: Good coverage for []runtimeclient.Object input

Mirrors runtime.Object tests and confirms the normalized path behaves identically.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
pkg/template/filter_test.go (5)

17-49: Set apiVersion in unstructured fixtures to ensure robust kind/GVK detection

Right now the fixtures only set "kind". If any filtering logic consults GroupVersionKind (common via GetObjectKind().GroupVersionKind()), Namespaces and RoleBindings may resolve to zero values and cause false negatives. Add apiVersion to each object to avoid brittle behavior.

Apply this diff to include apiVersion in the fixtures:

 ns1 = &unstructured.Unstructured{
   Object: map[string]interface{}{
-      "kind": "Namespace",
+      "apiVersion": "v1",
+      "kind": "Namespace",
       "metadata": map[string]interface{}{
         "name": "ns1",
       },
   },
 }
 ns2 = &unstructured.Unstructured{
   Object: map[string]interface{}{
-      "kind": "Namespace",
+      "apiVersion": "v1",
+      "kind": "Namespace",
       "metadata": map[string]interface{}{
         "name": "ns2",
       },
   },
 }
 rb1 = &unstructured.Unstructured{
   Object: map[string]interface{}{
-      "kind": "RoleBinding",
+      "apiVersion": "rbac.authorization.k8s.io/v1",
+      "kind": "RoleBinding",
       "metadata": map[string]interface{}{
         "name": "rb1",
       },
   },
 }
 rb2 = &unstructured.Unstructured{
   Object: map[string]interface{}{
-      "kind": "RoleBinding",
+      "apiVersion": "rbac.authorization.k8s.io/v1",
+      "kind": "RoleBinding",
       "metadata": map[string]interface{}{
         "name": "rb2",
       },
   },
 }

51-58: Avoid duplicating expectedCount; derive it from expectedObjects

expectedCount duplicates len(expectedObjects) and risks drift. Consider removing expectedCount and using len(expectedObjects) in assertions to keep tests DRY.

I can provide a follow-up diff to remove the field and update assertions if you want to simplify in this PR.


91-94: Guard the type assertion to runtimeclient.Object to avoid incidental panics

If a future test case includes an object that doesn’t implement runtimeclient.Object, this will panic before the filter is even exercised. Use a checked assertion and fail fast with a clear message.

Apply this diff:

-                clientObjects := make([]runtimeclient.Object, len(tc.objects))
-                for i, obj := range tc.objects {
-                    clientObjects[i] = obj.(runtimeclient.Object)
-                }
+                clientObjects := make([]runtimeclient.Object, len(tc.objects))
+                for i, obj := range tc.objects {
+                    co, ok := obj.(runtimeclient.Object)
+                    require.True(t, ok, "object at index %d does not implement runtimeclient.Object", i)
+                    clientObjects[i] = co
+                }

73-76: Consider asserting on stable identifiers (kind/name) versus whole-object equality

Asserting deep equality of entire objects tightly couples tests to representation details. Comparing Kind and metadata.name reduces brittleness while still validating correctness.

Example within each loop:

  • Cast both expected and actual to *unstructured.Unstructured and compare GetKind()/GetName().

If you want, I can push a concrete diff that switches these three loops to compare Kind/Name and adds a small helper.

Also applies to: 83-86, 98-101


170-180: Unsupported type panic test is spot on

This guards the new interface{} entry-point well. Optional: assert the panic message to lock down error clarity if you standardize it in implementation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 413fb36 and b62c5d1.

📒 Files selected for processing (1)
  • pkg/template/filter_test.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Verify Dependencies
🔇 Additional comments (3)
pkg/template/filter_test.go (3)

12-13: Importing controller-runtime client is appropriate

Good call adding the controller-runtime client import to exercise the new []runtimeclient.Object input shape.


60-106: Table-driven harness exercising all supported input shapes — nice

The helper cleanly validates behavior across []runtime.RawExtension, []runtime.Object, and []runtimeclient.Object while preserving order. Good structure and reuse.


107-168: Good coverage of filter semantics and ordering

  • Verifies no-op with no filters.
  • Conflicting filters produce empty set (AND semantics).
  • Covers both RetainNamespaces and RetainAllButNamespaces with single/multiple/empty results.

@fbm3307 fbm3307 changed the title KUBESAW-143: update filter function to accept runtimeclient object/runtimeobject SANDBOX1318: update filter function to accept runtimeclient object/runtimeobject Aug 20, 2025
Comment on lines +28 to +41
// Accepts []runtime.RawExtension, []runtime.Object, or []runtimeclient.Object
func Filter(objs interface{}, filters ...FilterFunc) []runtime.RawExtension {
// Convert input to []runtime.RawExtension
var rawExtensions []runtime.RawExtension

switch v := objs.(type) {
case []runtime.RawExtension:
rawExtensions = v
case []runtime.Object, []runtimeclient.Object:
// Handle both runtime.Object and runtimeclient.Object the same way
// since runtimeclient.Object embeds runtime.Object
var objects []runtime.Object
if runtimeObjs, ok := v.([]runtime.Object); ok {
objects = runtimeObjs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using interface{} looks like an overkill and similar to a python code - let's stay with Golang code and the standard approach to keep the code sane.
Also, based on the latest changes changes in the other PR, do we actually need to support the Object types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea i was actually thinking the same, this PR is now not needed , closing it

@fbm3307
Copy link
Contributor Author

fbm3307 commented Aug 20, 2025

closing this PR since now the support for different object types is not required

@fbm3307 fbm3307 closed this Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants