Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ var veleroCommandPattern = regexp.MustCompile(`(?m)(?:^|[\s\x60])velero\s+(?:` +
`(?:version|install|uninstall|plugin|snapshot-location|backup-location|restic|repo|client|completion|bug|debug|datamover)` +
`)`)

// veleroCreateVerbFirstPattern matches upstream Velero's "velero create <resource>" example
// text (verb-first), which some commands hardcode instead of the actual resource-first
// invocation. For example, velero's schedule create command is invoked as
// "velero schedule create NAME", but its upstream Example text says "velero create schedule
// NAME". veleroCommandPattern above doesn't catch this ordering, so it's normalized to
// resource-first form here before the general replacement runs.
var veleroCreateVerbFirstPattern = regexp.MustCompile(`(^|[\s\x60\n])velero\s+create\s+(backup|restore|schedule)\b`)

// replaceVeleroCommandWithOADP performs context-aware replacement of "velero" with "oadp".
// It only replaces "velero" when it's being used as a CLI command, not when referring to
// the Velero project, server, or components.
Expand All @@ -186,6 +194,11 @@ func replaceVeleroCommandWithOADP(text string) string {
// Use "oc" as the CLI prefix since OADP is primarily used on OpenShift
cliPrefix := "oc"

// Normalize verb-first "velero create <resource>" examples to resource-first
// "oc oadp <resource> create" before the general pattern runs, since the actual
// command is always invoked resource-first.
text = veleroCreateVerbFirstPattern.ReplaceAllString(text, "${1}"+cliPrefix+" oadp ${2} create")

// Replace "velero <command>" patterns with "oc/kubectl oadp <command>"
result := veleroCommandPattern.ReplaceAllStringFunc(text, func(match string) string {
// Preserve leading whitespace or backtick
Expand Down
28 changes: 28 additions & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,34 @@ Use velero backup logs to check status`,
}
}

// TestReplaceVeleroWithOADP_ScheduleCreateVerbFirst tests that upstream Velero's
// verb-first "velero create schedule NAME" example text (a known upstream quirk in
// schedule/create.go) is normalized to the resource-first form that actually matches
// how the command is invoked, consistent with "backup create" and "restore create".
func TestReplaceVeleroWithOADP_ScheduleCreateVerbFirst(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
Example: ` # Create a backup every 6 hours.
velero create schedule NAME --schedule="0 */6 * * *"

# Create a backup every 6 hours with the @every notation.
velero create schedule NAME --schedule="@every 6h"`,
}

replaceVeleroWithOADP(cmd)

if strings.Contains(cmd.Example, "velero create schedule") {
t.Errorf("Expected verb-first 'velero create schedule' to be normalized, got: %s", cmd.Example)
}
if strings.Contains(cmd.Example, "velero") {
t.Errorf("Expected 'velero' to be fully replaced, got: %s", cmd.Example)
}
wantCount := strings.Count(cmd.Example, "oc oadp schedule create NAME")
if wantCount != 2 {
t.Errorf("Expected 2 occurrences of 'oc oadp schedule create NAME', got %d\nActual output:\n%s", wantCount, cmd.Example)
}
}

// TestReplaceVeleroWithOADP_RunFunctionWrapper tests stdout capture and replacement
func TestReplaceVeleroWithOADP_RunFunctionWrapper(t *testing.T) {
outputCaptured := false
Expand Down
Loading