Skip to content

verb-noun order bugfixes#118

Merged
Joeavaikath merged 5 commits into
migtools:oadp-devfrom
Joeavaikath:bugfixes
Feb 17, 2026
Merged

verb-noun order bugfixes#118
Joeavaikath merged 5 commits into
migtools:oadp-devfrom
Joeavaikath:bugfixes

Conversation

@Joeavaikath
Copy link
Copy Markdown
Contributor

@Joeavaikath Joeavaikath commented Feb 12, 2026

Why the changes were made

  • Fixes bug: --details flag value not being respected for nonadmin
  • Enhances verb-noun order for non-admin commands
  • Fixes -o yaml output parsing for nonadmin resources

How to test the changes made

oc oadp na backup describe <backup-name> should now respect --details

Summary by CodeRabbit

  • New Features

    • Describe now supports a --details option to show extended backup details on demand.
  • Improvements

    • Non-admin verb commands rebuilt to register noun subcommands directly; command usage and examples updated.
    • Create commands now use dynamic usage strings.
    • Added local non-admin output formatting for CRD-aware JSON/YAML display.
  • Tests

    • Added comprehensive output encoding/display tests; removed prior verb-delegation test suite.
  • Chores

    • .gitignore updated to ignore vendor/.

Signed-off-by: Joseph <jvaikath@redhat.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

Removed the dynamic non-admin verb builder/registry and replaced it with explicit Cobra verb commands; added a local non-admin output package; gated extended backup describe output behind a --details flag; adjusted BSL create usage and updated CLI help/examples and related tests; added vendor/ to .gitignore.

Changes

Cohort / File(s) Summary
Verb builder removed & replaced
cmd/non-admin/verbs/builder.go (deleted), cmd/non-admin/verbs/registry.go (deleted), cmd/non-admin/verbs/verbs.go
Deleted the NonAdminVerbBuilder and registry; introduced direct construction of top-level verb commands (get, create, delete, describe, logs) that explicitly AddCommand the noun subcommands (backup, restore, bsl).
Builder tests removed
cmd/non-admin/verbs/builder_test.go (deleted)
Removed comprehensive tests for the builder, including registration, delegation, flag propagation, and error scenarios.
Backup describe detail gating
cmd/non-admin/backup/describe.go
Changed printNonAdminBackupDetails signature to accept showDetails bool; describe command now conditionally fetches/displays the ResourceList and invokes detailed printing only when --details is provided.
Non-admin output package added
cmd/non-admin/output/output.go, cmd/non-admin/output/output_test.go
Added a local output utility that registers schemes, provides BindFlags/ClearOutputFlagDefault, and PrintWithFormat (yaml/json/table handling) with extensive tests for encoding and list handling.
BSL create usage made dynamic
cmd/non-admin/bsl/bsl.go, cmd/non-admin/bsl/create.go, cmd/non-admin/bsl/bsl_test.go
NewCreateCommand signature now accepts a use string; callers pass "create" and the Cobra Use string is assembled dynamically; tests updated accordingly.
Get commands switched to local output
cmd/non-admin/backup/get.go, cmd/non-admin/bsl/get.go, cmd/non-admin/restore/get.go
Replaced imports of Velero's output utility with the new internal cmd/non-admin/output package and now call output.PrintWithFormat.
Help/examples and delete examples added
cmd/non-admin/backup/backup_test.go, cmd/non-admin/backup/delete.go, cmd/non-admin/restore/delete.go, cmd/non-admin/restore/restore_test.go, cmd/non-admin/nonadmin_test.go
Updated many help strings and tests to reference "backups"/"restores", aligned example verb-noun ordering, and added Example sections to delete commands.
Miscellaneous repository change
.gitignore
Added vendor/ to .gitignore.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant User
    end
    rect rgba(200,255,200,0.5)
    participant CLI_Verb_Command
    participant Noun_Subcommand
    end
    rect rgba(255,230,200,0.5)
    participant Output_Package
    participant Kubernetes_API
    end

    User->>CLI_Verb_Command: run "oadp nonadmin <verb> <noun> [flags]"
    CLI_Verb_Command->>Noun_Subcommand: invoke specific noun subcommand (backup/restore/bsl)
    Noun_Subcommand->>Kubernetes_API: fetch resource(s) per args/flags
    Kubernetes_API-->>Noun_Subcommand: return resource object(s)
    alt --details flag set (describe)
        Noun_Subcommand->>Noun_Subcommand: fetch & format extended details
    end
    Noun_Subcommand->>Output_Package: PrintWithFormat(obj, formatFlags)
    Output_Package-->>User: formatted output (yaml/json/table)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I hopped through commands, flags in tow,
Builder gone, now verbs plainly show,
Details whisper only when you plea,
Output tidy, tests set free,
A tiny nibble — CLI ready to go. 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'verb-noun order bugfixes' directly addresses the main structural reorganization of non-admin commands from noun-first to verb-noun ordering, which is the primary architectural change across multiple files.
Description check ✅ Passed The description covers the key changes mentioned in the PR objectives, though it lacks testing instructions detail and omits the architectural changes around the builder pattern removal.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into oadp-dev

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In `@cmd/non-admin/verbs/builder_test.go`:
- Around line 408-410: The test currently only logs when err.Error() does not
contain "command not found" which means it never fails on unexpected error
messages; update the assertion in the test (in builder_test.go around the
strings.Contains(err.Error(), "command not found") check) to fail the test when
the error message is not what we expect by replacing the log with a test failure
(e.g., call t.Fatalf or t.Errorf) that includes the actual err.Error() so the
test fails and reports the unexpected message.
🧹 Nitpick comments (5)
cmd/non-admin/backup/describe.go (1)

325-344: Redundant context creation inside printNonAdminBackupDetails.

A new context with timeout is created at lines 327-328, but the caller at line 38 already creates a context with the same timeout. Consider passing the existing context as a parameter instead of creating a new one. This would:

  1. Avoid redundant timeout tracking
  2. Ensure proper cancellation propagation from parent context
  3. Follow the convention of accepting context as first parameter
♻️ Suggested approach

Pass ctx from the caller into printNonAdminBackupDetails instead of creating a new context:

-func printNonAdminBackupDetails(cmd *cobra.Command, nab *nacv1alpha1.NonAdminBackup, kbClient kbclient.Client, backupName string, userNamespace string, timeout time.Duration, showDetails bool) {
+func printNonAdminBackupDetails(ctx context.Context, cmd *cobra.Command, nab *nacv1alpha1.NonAdminBackup, kbClient kbclient.Client, backupName string, userNamespace string, timeout time.Duration, showDetails bool) {

Then in the showDetails block, use the passed context directly:

 		if showDetails {
-			ctx, cancel := context.WithTimeout(context.Background(), timeout)
-			defer cancel()
-
 			resourceList, err := shared.ProcessDownloadRequest(ctx, kbClient, shared.DownloadRequestOptions{

Update the call site at line 75:

-			printNonAdminBackupDetails(cmd, &nab, kbClient, backupName, userNamespace, effectiveTimeout, details)
+			printNonAdminBackupDetails(ctx, cmd, &nab, kbClient, backupName, userNamespace, effectiveTimeout, details)
cmd/non-admin/verbs/builder.go (1)

65-84: Consider using strings.Join and sorting for deterministic output.

The current implementation uses manual string concatenation and doesn't sort the resource types. While acceptable for error messages, this could produce inconsistent output order across runs.

♻️ Suggested improvement
+import (
+	"sort"
+	"strings"
+	...
+)

 func (vb *NonAdminVerbBuilder) getAvailableResourceTypes() string {
 	if len(vb.resourceRegistry) == 0 {
 		return "none"
 	}

 	var types []string
 	for resourceType := range vb.resourceRegistry {
 		types = append(types, resourceType)
 	}
+	sort.Strings(types)

-	result := ""
-	for i, t := range types {
-		if i > 0 {
-			result += ", "
-		}
-		result += t
-	}
-	return result
+	return strings.Join(types, ", ")
 }
cmd/non-admin/verbs/builder_test.go (2)

451-455: Consider asserting the duration value instead of just logging.

The test verifies the flag was received but doesn't assert the normalized value. If the duration normalization changes or breaks, the test would still pass while only logging the discrepancy.

Proposed fix for stricter validation
 	if !flagReceived {
 		t.Error("Expected duration flag --ttl to be passed to delegated command")
-	} else if receivedValue != "720h0m0s" {
-		t.Logf("Duration flag passed with value: %s (expected normalized form)", receivedValue)
+	} else if receivedValue != "720h0m0s" {
+		t.Errorf("Expected duration value '720h0m0s', got: %s", receivedValue)
+	} else {
+		t.Logf("Duration flag passed with expected value: %s", receivedValue)
 	}

498-505: Map contents not validated against expected values.

The test verifies the flag was received but doesn't assert that receivedMap contains the expected entries (region=us-east-1 and bucket=my-bucket). This reduces the test's ability to catch regressions in map flag parsing.

Proposed fix to validate map contents
 	if !flagReceived {
 		t.Error("Expected map flag --config to be passed to delegated command")
 	} else {
-		t.Logf("Map flag passed successfully with %d entries", len(receivedMap))
-		if len(receivedMap) > 0 {
-			t.Logf("Map contents: %v", receivedMap)
+		if len(receivedMap) != 2 {
+			t.Errorf("Expected 2 map entries, got %d: %v", len(receivedMap), receivedMap)
+		}
+		if receivedMap["region"] != "us-east-1" {
+			t.Errorf("Expected region=us-east-1, got region=%s", receivedMap["region"])
+		}
+		if receivedMap["bucket"] != "my-bucket" {
+			t.Errorf("Expected bucket=my-bucket, got bucket=%s", receivedMap["bucket"])
 		}
+		t.Logf("Map flag passed with expected contents: %v", receivedMap)
 	}
cmd/non-admin/README.md (1)

220-245: Add language specifier to fenced code blocks.

The ASCII flow diagrams should have a language specifier (e.g., text or plaintext) to satisfy markdown linting rules.

Proposed fix
-```
+```text
 User: kubectl oadp nonadmin backup create my-backup --storage-location aws
 
 Flow:
 1. NonadminCommand
 2. → BackupCommand
 3. → CreateCommand
 4. → Flags parsed directly on CreateCommand
 5. → CreateCommand.RunE() executes

```diff
-```
+```text
 User: kubectl oadp nonadmin create backup my-backup --storage-location aws
 
 Flow:
 1. NonadminCommand
 2. → CreateCommand (verb)
 3. → Extract resource type: "backup"
 4. → Create fresh backup command instance
 5. → Get "create" subcommand from backup
 6. → Convert verb flags to args
 7. → Parse args on fresh subcommand
 8. → Execute subcommand.RunE()
</details>

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread cmd/non-admin/verbs/builder_test.go Outdated
Copy link
Copy Markdown

@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: 2

🤖 Fix all issues with AI agents
In `@cmd/non-admin/verbs/builder.go`:
- Around line 168-172: The boolean branch only appends the flag when flagValue
== "true", so explicit false values (e.g. --details=false) are lost; update the
case "bool" in builder.go to always propagate the user's explicit value: if
flagValue == "true" append "--"+flag.Name (preserving shorthand form) otherwise
append "--"+flag.Name+"="+flagValue so that false (or any explicit boolean) is
passed through via remainingArgs.
- Around line 173-181: The stringArray/stringSlice branch currently appends the
entire bracketed String() output as one value causing a nested array on
re-parse; change the logic in the case "stringArray", "stringSlice" to detect
and handle bracket-enclosed values: if flagValue starts with "[" and ends with
"]", trim the brackets, split the inner string on commas, trim whitespace from
each item, and for each non-empty item append "--"+flag.Name and the item to
remainingArgs (so repeated flags are passed); otherwise keep the existing
single-value append behavior for non-bracket values. Ensure you continue to
check flagValue != "" && flagValue != "[]".
🧹 Nitpick comments (1)
cmd/non-admin/verbs/builder.go (1)

65-84: Consider using strings.Join and sorting for consistency.

The manual string concatenation can be simplified with strings.Join. Additionally, map iteration order in Go is non-deterministic, so error messages may show resource types in different orders across executions. Sorting provides consistent output.

♻️ Suggested refactor
+import (
+	"sort"
+	"strings"
+	...
+)

 func (vb *NonAdminVerbBuilder) getAvailableResourceTypes() string {
 	if len(vb.resourceRegistry) == 0 {
 		return "none"
 	}

 	var types []string
 	for resourceType := range vb.resourceRegistry {
 		types = append(types, resourceType)
 	}
-
-	result := ""
-	for i, t := range types {
-		if i > 0 {
-			result += ", "
-		}
-		result += t
-	}
-	return result
+	sort.Strings(types)
+	return strings.Join(types, ", ")
 }

Comment thread cmd/non-admin/verbs/builder.go Outdated
Comment thread cmd/non-admin/verbs/builder.go Outdated
Comment on lines +173 to +181
case "stringArray", "stringSlice":
// Handle string array/slice flags
remainingArgs = append(remainingArgs, "--"+flag.Name, flagValue)
// For array/slice flags, we need to preserve multiple values
// The String() representation might be comma-separated or bracket-enclosed
// For pflag arrays, each value should be passed with its own flag instance
// However, since we're re-parsing, the single string representation should work
// as pflag will handle splitting appropriately
if flagValue != "" && flagValue != "[]" {
remainingArgs = append(remainingArgs, "--"+flag.Name, flagValue)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and examine the actual code
find . -name "builder.go" -path "*/non-admin/verbs/*" | head -5

Repository: migtools/oadp-cli

Length of output: 93


🏁 Script executed:

# Check if the test file exists
find . -name "builder_test.go" -path "*/non-admin/verbs/*" | head -5

Repository: migtools/oadp-cli

Length of output: 98


🏁 Script executed:

# List the repository structure to understand the project
ls -la

Repository: migtools/oadp-cli

Length of output: 1272


🏁 Script executed:

# Examine the builder.go file around lines 173-181
cat -n cmd/non-admin/verbs/builder.go | sed -n '165,190p'

Repository: migtools/oadp-cli

Length of output: 1408


🏁 Script executed:

# Check the broader context to understand the addFlagsToArgs function
cat -n cmd/non-admin/verbs/builder.go | sed -n '140,200p'

Repository: migtools/oadp-cli

Length of output: 2881


🏁 Script executed:

# Look at the test file to see current test coverage
cat -n cmd/non-admin/verbs/builder_test.go | sed -n '70,185p'

Repository: migtools/oadp-cli

Length of output: 4188


🏁 Script executed:

# Create a test to verify how pflag actually parses stringArray with bracket-enclosed values
cd /tmp && cat > test_pflag_parse.go << 'EOF'
package main

import (
	"fmt"
	"strings"
	
	"github.com/spf13/pflag"
)

func main() {
	tests := []struct {
		name   string
		args   []string
		desc   string
	}{
		{
			name:   "bracket-enclosed",
			args:   []string{"--items", "[a,b,c]"},
			desc:   "pflag with bracket-enclosed string",
		},
		{
			name:   "unbracketed-comma",
			args:   []string{"--items", "a,b,c"},
			desc:   "pflag with unbracketed comma-separated",
		},
		{
			name:   "repeated-flags",
			args:   []string{"--items", "a", "--items", "b", "--items", "c"},
			desc:   "pflag with repeated flags",
		},
	}

	for _, test := range tests {
		fmt.Printf("\n=== Test: %s (%s) ===\n", test.name, test.desc)
		fmt.Printf("Input args: %v\n", test.args)
		
		fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
		var items []string
		fs.StringArrayVar(&items, "items", nil, "test items")
		
		err := fs.Parse(test.args)
		if err != nil {
			fmt.Printf("Parse error: %v\n", err)
			continue
		}
		
		fmt.Printf("Parsed array: %v\n", items)
		fmt.Printf("Array length: %d\n", len(items))
		
		// Simulate what String() returns and re-parse
		if len(items) > 0 {
			// Manually construct what String() would return
			stringRepr := "[" + strings.Join(items, ",") + "]"
			fmt.Printf("\nSimulating re-parse with String() output: %q\n", stringRepr)
			
			fs2 := pflag.NewFlagSet("test2", pflag.ContinueOnError)
			var items2 []string
			fs2.StringArrayVar(&items2, "items", nil, "test items")
			
			err2 := fs2.Parse([]string{"--items", stringRepr})
			if err2 != nil {
				fmt.Printf("Re-parse error: %v\n", err2)
			} else {
				fmt.Printf("Re-parsed array: %v\n", items2)
				fmt.Printf("Re-parsed length: %d\n", len(items2))
				if len(items2) == 1 && items2[0] == stringRepr {
					fmt.Printf("WARNING: Re-parse treated entire bracket string as single element!\n")
				}
			}
		}
	}
}
EOF

go mod init test 2>/dev/null
go mod edit -require=github.com/spf13/pflag@latest 2>/dev/null
go mod tidy 2>&1 | head -5
go run test_pflag_parse.go

Repository: migtools/oadp-cli

Length of output: 454


🏁 Script executed:

# Use the repo's go.mod to run our test
cat > cmd/non-admin/verbs/test_pflag_parse.go << 'EOF'
package verbs

import (
	"fmt"
	"strings"
	"testing"

	"github.com/spf13/pflag"
)

func TestPflagStringArrayParsing(t *testing.T) {
	tests := []struct {
		name   string
		args   []string
		desc   string
	}{
		{
			name:   "bracket-enclosed",
			args:   []string{"--items", "[a,b,c]"},
			desc:   "pflag with bracket-enclosed string",
		},
		{
			name:   "unbracketed-comma",
			args:   []string{"--items", "a,b,c"},
			desc:   "pflag with unbracketed comma-separated",
		},
		{
			name:   "repeated-flags",
			args:   []string{"--items", "a", "--items", "b", "--items", "c"},
			desc:   "pflag with repeated flags",
		},
	}

	for _, test := range tests {
		fmt.Printf("\n=== Test: %s (%s) ===\n", test.name, test.desc)
		fmt.Printf("Input args: %v\n", test.args)
		
		fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
		var items []string
		fs.StringArrayVar(&items, "items", nil, "test items")
		
		err := fs.Parse(test.args)
		if err != nil {
			fmt.Printf("Parse error: %v\n", err)
			continue
		}
		
		fmt.Printf("Parsed array: %v\n", items)
		fmt.Printf("Array length: %d\n", len(items))
		
		// Simulate what String() returns and re-parse
		if len(items) > 0 {
			// Manually construct what String() would return
			stringRepr := "[" + strings.Join(items, ",") + "]"
			fmt.Printf("\nSimulating re-parse with String() output: %q\n", stringRepr)
			
			fs2 := pflag.NewFlagSet("test2", pflag.ContinueOnError)
			var items2 []string
			fs2.StringArrayVar(&items2, "items", nil, "test items")
			
			err2 := fs2.Parse([]string{"--items", stringRepr})
			if err2 != nil {
				fmt.Printf("Re-parse error: %v\n", err2)
			} else {
				fmt.Printf("Re-parsed array: %v\n", items2)
				fmt.Printf("Re-parsed length: %d\n", len(items2))
				if len(items2) == 1 && items2[0] == stringRepr {
					fmt.Printf("WARNING: Re-parse treated entire bracket string as single element!\n")
				}
			}
		}
	}
}
EOF

# Now run the test from the repository root
cd . && go test -v -run TestPflagStringArrayParsing ./cmd/non-admin/verbs/

Repository: migtools/oadp-cli

Length of output: 5221


🏁 Script executed:

# Also let's check what the actual String() output looks like for stringArray flags in this codebase
grep -n "StringArray\|stringArray" cmd/non-admin/verbs/*.go | head -20

Repository: migtools/oadp-cli

Length of output: 789


🏁 Script executed:

# Let me create a simpler standalone test that can run directly
cat > /tmp/test_array_parse.go << 'EOF'
package main

import (
	"fmt"
	"strings"
	"github.com/spf13/pflag"
)

func main() {
	fmt.Println("Testing pflag stringArray parsing behavior:")
	fmt.Println("===========================================")
	
	// Test 1: What does String() return for a parsed stringArray?
	fmt.Println("\n[Test 1] Initial parse and String() output:")
	fs1 := pflag.NewFlagSet("test1", pflag.ContinueOnError)
	var items1 []string
	fs1.StringArrayVar(&items1, "items", nil, "test items")
	
	fs1.Parse([]string{"--items", "a", "--items", "b", "--items", "c"})
	fmt.Printf("  Parsed with repeated flags: %v\n", items1)
	
	// Get the flag and call String() on it
	flag1 := fs1.Lookup("items")
	stringRepr := flag1.Value.String()
	fmt.Printf("  String() output: %q\n", stringRepr)
	
	// Test 2: Re-parse the bracket-enclosed output
	fmt.Println("\n[Test 2] Re-parsing the String() output (bracket-enclosed):")
	fs2 := pflag.NewFlagSet("test2", pflag.ContinueOnError)
	var items2 []string
	fs2.StringArrayVar(&items2, "items", nil, "test items")
	
	err := fs2.Parse([]string{"--items", stringRepr})
	if err != nil {
		fmt.Printf("  Parse error: %v\n", err)
	} else {
		fmt.Printf("  Parsed result: %v\n", items2)
		fmt.Printf("  Array length: %d\n", len(items2))
		if len(items2) == 1 && strings.Contains(items2[0], "[") {
			fmt.Printf("  ❌ PROBLEM: Entire bracket string treated as single element!\n")
		} else if len(items2) == 3 {
			fmt.Printf("  ✓ OK: Array elements preserved correctly\n")
		}
	}
	
	// Test 3: What about unbracketed comma-separated?
	fmt.Println("\n[Test 3] Parsing unbracketed comma-separated string:")
	fs3 := pflag.NewFlagSet("test3", pflag.ContinueOnError)
	var items3 []string
	fs3.StringArrayVar(&items3, "items", nil, "test items")
	
	err = fs3.Parse([]string{"--items", "a,b,c"})
	if err != nil {
		fmt.Printf("  Parse error: %v\n", err)
	} else {
		fmt.Printf("  Parsed result: %v\n", items3)
		fmt.Printf("  Array length: %d\n", len(items3))
	}
}
EOF

cd . && go run /tmp/test_array_parse.go

Repository: migtools/oadp-cli

Length of output: 525


🏁 Script executed:

# Let me also verify what the actual test in builder_test.go checks
cat -n cmd/non-admin/verbs/builder_test.go | sed -n '115,125p'

Repository: migtools/oadp-cli

Length of output: 437


Fix stringArray round-trip parsing: remove bracket notation before passing to subcommand.

The String() representation of stringArray flags returns bracket-enclosed format ([a,b,c]), but when this is passed directly to the fresh subcommand's parser as --flag [a,b,c], pflag treats the entire bracket string as a single array element, resulting in [[a,b,c]] instead of [a,b,c]. The array elements are lost.

Verification result
[Test 1] Initial parse:        [a b c]
[Test 2] String() output:      "[a,b,c]"
[Test 3] Re-parse String():    [[a,b,c]]  ← entire bracket string becomes 1 element

Either strip the brackets before passing to the parser, or reconstruct using repeated flags (--flag a --flag b --flag c). The existing test only verifies flag.Changed and flag.Value.String() exist, but does not validate that array elements are correctly parsed by the delegated command.

🤖 Prompt for AI Agents
In `@cmd/non-admin/verbs/builder.go` around lines 173 - 181, The
stringArray/stringSlice branch currently appends the entire bracketed String()
output as one value causing a nested array on re-parse; change the logic in the
case "stringArray", "stringSlice" to detect and handle bracket-enclosed values:
if flagValue starts with "[" and ends with "]", trim the brackets, split the
inner string on commas, trim whitespace from each item, and for each non-empty
item append "--"+flag.Name and the item to remainingArgs (so repeated flags are
passed); otherwise keep the existing single-value append behavior for
non-bracket values. Ensure you continue to check flagValue != "" && flagValue !=
"[]".

Copy link
Copy Markdown

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/non-admin/verbs/builder_test.go (1)

267-275: ⚠️ Potential issue | 🟡 Minor

Avoid nil deref in error assertion.

If err is nil, the test continues and calls err.Error(), which will panic. Prefer t.Fatal to stop the test immediately.

Suggested fix
 	err := verbCmd.Execute()
 	if err == nil {
-		t.Error("Expected error for unknown resource type, got nil")
+		t.Fatal("Expected error for unknown resource type, got nil")
 	}
🤖 Fix all issues with AI agents
In `@cmd/non-admin/verbs/builder_test.go`:
- Around line 500-507: The test currently only checks flagReceived and
len(receivedMap); update it to assert the exact expected map contents by
defining an expected map (e.g., expectedMap) and comparing it to receivedMap
using a deep-equality check (reflect.DeepEqual or cmp.Diff) and failing the test
with a clear message if they differ; keep flagReceived check but replace the
loose len(receivedMap) branch with an equality assertion that verifies both keys
and values match, and include the mismatched contents in the error message so
failures show the expected vs actual maps (referencing flagReceived and
receivedMap in builder_test.go).
- Around line 453-457: The test currently only logs when the received duration
is not normalized, so change that log to a real assertion: replace the t.Logf in
the builder_test.go check that inspects flagReceived and receivedValue with
t.Fatalf or t.Errorf (e.g., t.Fatalf("Duration flag passed with value %q;
expected normalized form %q", receivedValue, "720h0m0s")) so the test fails on
regressions; keep the existing condition and variables (flagReceived,
receivedValue) and the expected string "720h0m0s".

Comment thread cmd/non-admin/verbs/builder_test.go Outdated
Comment on lines 453 to 457
if !flagReceived {
t.Error("Expected duration flag --ttl to be passed to delegated command")
} else if receivedValue != "720h0m0s" {
t.Logf("Duration flag passed with value: %s (expected normalized form)", receivedValue)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make duration normalization a real assertion.

The test logs when the value is unexpected but doesn’t fail, so regressions won’t be caught.

Suggested fix
-	if !flagReceived {
-		t.Error("Expected duration flag --ttl to be passed to delegated command")
-	} else if receivedValue != "720h0m0s" {
-		t.Logf("Duration flag passed with value: %s (expected normalized form)", receivedValue)
-	}
+	if !flagReceived {
+		t.Fatal("Expected duration flag --ttl to be passed to delegated command")
+	}
+	if receivedValue != "720h0m0s" {
+		t.Errorf("Expected normalized duration value %q, got %q", "720h0m0s", receivedValue)
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !flagReceived {
t.Error("Expected duration flag --ttl to be passed to delegated command")
} else if receivedValue != "720h0m0s" {
t.Logf("Duration flag passed with value: %s (expected normalized form)", receivedValue)
}
if !flagReceived {
t.Fatal("Expected duration flag --ttl to be passed to delegated command")
}
if receivedValue != "720h0m0s" {
t.Errorf("Expected normalized duration value %q, got %q", "720h0m0s", receivedValue)
}
🤖 Prompt for AI Agents
In `@cmd/non-admin/verbs/builder_test.go` around lines 453 - 457, The test
currently only logs when the received duration is not normalized, so change that
log to a real assertion: replace the t.Logf in the builder_test.go check that
inspects flagReceived and receivedValue with t.Fatalf or t.Errorf (e.g.,
t.Fatalf("Duration flag passed with value %q; expected normalized form %q",
receivedValue, "720h0m0s")) so the test fails on regressions; keep the existing
condition and variables (flagReceived, receivedValue) and the expected string
"720h0m0s".

Comment thread cmd/non-admin/verbs/builder_test.go Outdated
Comment on lines 500 to 507
if !flagReceived {
t.Error("Expected map flag --config to be passed to delegated command")
} else {
t.Logf("Map flag passed successfully with %d entries", len(receivedMap))
if len(receivedMap) > 0 {
t.Logf("Map contents: %v", receivedMap)
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Assert expected map contents, not just presence.

The test currently passes even if only one entry is parsed or values are wrong.

Suggested fix
 	if !flagReceived {
-		t.Error("Expected map flag --config to be passed to delegated command")
-	} else {
-		t.Logf("Map flag passed successfully with %d entries", len(receivedMap))
-		if len(receivedMap) > 0 {
-			t.Logf("Map contents: %v", receivedMap)
-		}
-	}
+		t.Fatal("Expected map flag --config to be passed to delegated command")
+	}
+	if len(receivedMap) != 2 || receivedMap["region"] != "us-east-1" || receivedMap["bucket"] != "my-bucket" {
+		t.Errorf("Expected map entries {region: us-east-1, bucket: my-bucket}, got: %v", receivedMap)
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if !flagReceived {
t.Error("Expected map flag --config to be passed to delegated command")
} else {
t.Logf("Map flag passed successfully with %d entries", len(receivedMap))
if len(receivedMap) > 0 {
t.Logf("Map contents: %v", receivedMap)
}
}
if !flagReceived {
t.Fatal("Expected map flag --config to be passed to delegated command")
}
if len(receivedMap) != 2 || receivedMap["region"] != "us-east-1" || receivedMap["bucket"] != "my-bucket" {
t.Errorf("Expected map entries {region: us-east-1, bucket: my-bucket}, got: %v", receivedMap)
}
🤖 Prompt for AI Agents
In `@cmd/non-admin/verbs/builder_test.go` around lines 500 - 507, The test
currently only checks flagReceived and len(receivedMap); update it to assert the
exact expected map contents by defining an expected map (e.g., expectedMap) and
comparing it to receivedMap using a deep-equality check (reflect.DeepEqual or
cmp.Diff) and failing the test with a clear message if they differ; keep
flagReceived check but replace the loose len(receivedMap) branch with an
equality assertion that verifies both keys and values match, and include the
mismatched contents in the error message so failures show the expected vs actual
maps (referencing flagReceived and receivedMap in builder_test.go).

Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In `@cmd/non-admin/verbs/builder.go`:
- Around line 140-153: The current flow in builder.go parses flags and then
directly calls subCmd.RunE, which bypasses any argument validators defined via
subCmd.Args and skips important checks (e.g., backup/delete.go). Before invoking
RunE, call the Args validator by executing subCmd.Args()(or
subCmd.Args()(parsedArgs) depending on signature) with parsedArgs and
handle/return any error; only if that succeeds proceed to call
subCmd.RunE(subCmd, parsedArgs). Ensure you reference the variables and
functions used here: subCmd, remainingArgs, parsedArgs, subCmd.ParseFlags,
subCmd.Flags().Args(), subCmd.Args(), and subCmd.RunE.
🧹 Nitpick comments (1)
cmd/non-admin/verbs/builder.go (1)

65-84: Optional: sort resource types for deterministic error messages.
Map iteration order is random, so sorting avoids noisy diffs and user‑facing variability.

♻️ Suggested tweak
 import (
 	"fmt"
+	"sort"
 	"strings"

@@
-	var types []string
-	for resourceType := range vb.resourceRegistry {
-		types = append(types, resourceType)
-	}
-
-	var builder strings.Builder
-	for i, t := range types {
-		if i > 0 {
-			builder.WriteString(", ")
-		}
-		builder.WriteString(t)
-	}
-	return builder.String()
+	types := make([]string, 0, len(vb.resourceRegistry))
+	for resourceType := range vb.resourceRegistry {
+		types = append(types, resourceType)
+	}
+	sort.Strings(types)
+	return strings.Join(types, ", ")

Comment thread cmd/non-admin/verbs/builder.go Outdated
@Joeavaikath Joeavaikath marked this pull request as draft February 12, 2026 18:37
Signed-off-by: Joseph <jvaikath@redhat.com>
@Joeavaikath Joeavaikath marked this pull request as ready for review February 12, 2026 19:37
@Joeavaikath
Copy link
Copy Markdown
Contributor Author

Joeavaikath commented Feb 12, 2026

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

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.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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.
  • You can also validate your configuration using the online YAML validator.
  • 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, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

Tip

For best results, initiate chat on the files or code changes.

@Joeavaikath Hello! 👋 I'm here to help. How can I assist you with PR #118?

I can help you with:

  • Reviewing the changes in this PR
  • Explaining specific code modifications
  • Running tests or analyzing the codebase
  • Answering questions about the verb-noun order bugfixes
  • Testing the --details flag behavior you mentioned
  • Anything else related to this pull request

What would you like me to do?

@Joeavaikath
Copy link
Copy Markdown
Contributor Author

Joeavaikath commented Feb 12, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Velero's output.PrintWithFormat uses an upstream scheme that doesn't include
NonAdmin CRD types, causing "no kind is registered" errors when using -o yaml
or -o json flags. Implemented custom output package with NonAdmin scheme
registration to enable proper serialization of downstream types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
@Joeavaikath
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

✅ Actions performed

Full review triggered.

@Joeavaikath
Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 12, 2026

✅ Actions performed

Reviews resumed.

@Joeavaikath Joeavaikath linked an issue Feb 13, 2026 that may be closed by this pull request
@weshayutin
Copy link
Copy Markdown
Contributor

@stillalearner please have a look

Comment thread cmd/non-admin/verbs/builder.go Outdated
Comment on lines +107 to +138
// Use the original subcommand directly (not a copy) and set its args
// This ensures the RunE closure uses the correct flag variables
subCmd.SetArgs(remainingArgs)

// Parse flags from the args we set
// IMPORTANT: We cannot use subCmd.Execute() here because it causes Cobra to
// re-parse os.Args from the root command, which results in incorrect command
// path parsing (e.g., "unknown command 'na' for 'backup'" error).
// Instead, we manually parse flags and execute the RunE function directly.
if err := subCmd.ParseFlags(remainingArgs); err != nil {
return err
}

// Validate arguments
if subCmd.Args != nil {
// Get the args after flag parsing
flags := subCmd.Flags()
argsList := flags.Args()
if err := subCmd.Args(subCmd, argsList); err != nil {
return err
}
}

// Execute the RunE function directly with parsed args
if subCmd.RunE != nil {
flags := subCmd.Flags()
return subCmd.RunE(subCmd, flags.Args())
} else if subCmd.Run != nil {
flags := subCmd.Flags()
subCmd.Run(subCmd, flags.Args())
return nil
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The new delegation bypasses Execute() and directly calls RunE/Run. This means any PreRunE, PersistentPreRunE, PostRunE, or PersistentPostRunE hooks on the subcommand or its parents will not execute. If any of the delegated commands (describe, get, create) rely on these hooks for setup (e.g., initializing clients, validation), they will silently break.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be worth checking whether any delegated commands use PreRunE hooks. If they do, those need to be invoked manually too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This builder pattern shouldn't have been used since cobra already does this when we use AddCommand
Testing locally that nothing has changed else should be good

Comment thread .gitignore
Comment on lines +51 to +52

vendor/ No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

any reason you vendored locally?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

inspecting the upstream velero implementations for some funcs that I'm using
eg the output format for -o yaml

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Copy link
Copy Markdown

@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.

🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@cmd/non-admin/output/output_test.go`:
- Around line 243-257: The os.Pipe() call currently ignores its returned error;
update the test helpers around PrintWithFormat (in TestPrintWithFormat and
TestPrintWithFormatList) to capture the two-value result (r, w, err :=
os.Pipe()), check err immediately, and call t.Fatalf("os.Pipe failed: %v", err)
(or t.Fatal) if non-nil so the test fails fast; keep the rest of the stdout
capture/restore logic the same and ensure you mirror this change in the second
occurrence referenced by TestPrintWithFormatList.

In `@cmd/non-admin/output/output.go`:
- Around line 35-50: NonAdminScheme currently allocates and registers a new
runtime.Scheme on every call (and is invoked frequently via encoderFor); change
it to return a package-level cached singleton by adding a package-scoped
variable (e.g., nonAdminScheme *runtime.Scheme) and a sync.Once (e.g.,
nonAdminSchemeOnce), move the creation and AddToScheme calls inside
nonAdminSchemeOnce.Do(...) in NonAdminScheme, and have NonAdminScheme simply
return the cached nonAdminScheme; ensure the init block is only run once to
preserve thread-safety and avoid re-registering types.
🧹 Nitpick comments (2)
🤖 Fix all nitpicks with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@cmd/non-admin/output/output_test.go`:
- Around line 243-257: The os.Pipe() call currently ignores its returned error;
update the test helpers around PrintWithFormat (in TestPrintWithFormat and
TestPrintWithFormatList) to capture the two-value result (r, w, err :=
os.Pipe()), check err immediately, and call t.Fatalf("os.Pipe failed: %v", err)
(or t.Fatal) if non-nil so the test fails fast; keep the rest of the stdout
capture/restore logic the same and ensure you mirror this change in the second
occurrence referenced by TestPrintWithFormatList.

In `@cmd/non-admin/output/output.go`:
- Around line 35-50: NonAdminScheme currently allocates and registers a new
runtime.Scheme on every call (and is invoked frequently via encoderFor); change
it to return a package-level cached singleton by adding a package-scoped
variable (e.g., nonAdminScheme *runtime.Scheme) and a sync.Once (e.g.,
nonAdminSchemeOnce), move the creation and AddToScheme calls inside
nonAdminSchemeOnce.Do(...) in NonAdminScheme, and have NonAdminScheme simply
return the cached nonAdminScheme; ensure the init block is only run once to
preserve thread-safety and avoid re-registering types.
cmd/non-admin/output/output_test.go (1)

243-257: Consider handling the os.Pipe() error.

The error from os.Pipe() is currently ignored. While unlikely to fail in test environments, handling it improves robustness.

🧹 Minor fix
 			// Capture stdout
 			oldStdout := os.Stdout
-			r, w, _ := os.Pipe()
+			r, w, err := os.Pipe()
+			if err != nil {
+				t.Fatalf("Failed to create pipe: %v", err)
+			}
 			os.Stdout = w

Note: The same pattern appears at lines 341-343 in TestPrintWithFormatList.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@cmd/non-admin/output/output_test.go` around lines 243 - 257, The os.Pipe()
call currently ignores its returned error; update the test helpers around
PrintWithFormat (in TestPrintWithFormat and TestPrintWithFormatList) to capture
the two-value result (r, w, err := os.Pipe()), check err immediately, and call
t.Fatalf("os.Pipe failed: %v", err) (or t.Fatal) if non-nil so the test fails
fast; keep the rest of the stdout capture/restore logic the same and ensure you
mirror this change in the second occurrence referenced by
TestPrintWithFormatList.
cmd/non-admin/output/output.go (1)

35-50: Consider caching the scheme as a package-level singleton.

NonAdminScheme() creates a new runtime.Scheme instance and registers types on every call. Since the scheme is immutable after creation, this function is called repeatedly in encoderFor() (line 127), creating unnecessary allocations during encoding operations.

♻️ Suggested refactor using sync.Once
+import "sync"
+
+var (
+	nonAdminScheme     *runtime.Scheme
+	nonAdminSchemeOnce sync.Once
+)
+
 // NonAdminScheme returns a runtime.Scheme with NonAdmin types registered
 func NonAdminScheme() *runtime.Scheme {
-	scheme := runtime.NewScheme()
-
-	// Add NonAdmin types
-	if err := nacv1alpha1.AddToScheme(scheme); err != nil {
-		panic(fmt.Sprintf("failed to add NonAdmin types to scheme: %v", err))
-	}
-
-	// Add Velero types for compatibility
-	if err := velerov1api.AddToScheme(scheme); err != nil {
-		panic(fmt.Sprintf("failed to add Velero types to scheme: %v", err))
-	}
-
-	return scheme
+	nonAdminSchemeOnce.Do(func() {
+		nonAdminScheme = runtime.NewScheme()
+
+		// Add NonAdmin types
+		if err := nacv1alpha1.AddToScheme(nonAdminScheme); err != nil {
+			panic(fmt.Sprintf("failed to add NonAdmin types to scheme: %v", err))
+		}
+
+		// Add Velero types for compatibility
+		if err := velerov1api.AddToScheme(nonAdminScheme); err != nil {
+			panic(fmt.Sprintf("failed to add Velero types to scheme: %v", err))
+		}
+	})
+	return nonAdminScheme
 }
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@cmd/non-admin/output/output.go` around lines 35 - 50, NonAdminScheme
currently allocates and registers a new runtime.Scheme on every call (and is
invoked frequently via encoderFor); change it to return a package-level cached
singleton by adding a package-scoped variable (e.g., nonAdminScheme
*runtime.Scheme) and a sync.Once (e.g., nonAdminSchemeOnce), move the creation
and AddToScheme calls inside nonAdminSchemeOnce.Do(...) in NonAdminScheme, and
have NonAdminScheme simply return the cached nonAdminScheme; ensure the init
block is only run once to preserve thread-safety and avoid re-registering types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
@Joeavaikath Joeavaikath merged commit b4d6566 into migtools:oadp-dev Feb 17, 2026
16 checks passed
This was referenced Feb 17, 2026
@Joeavaikath Joeavaikath deleted the bugfixes branch February 19, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nonadmin APIs are not supported with get -o yaml

3 participants