Skip to content

Add completion install command for shell autocompletion#148

Merged
Joeavaikath merged 11 commits intomigtools:oadp-devfrom
Joeavaikath:issue-139-autocomplete
Mar 10, 2026
Merged

Add completion install command for shell autocompletion#148
Joeavaikath merged 11 commits intomigtools:oadp-devfrom
Joeavaikath:issue-139-autocomplete

Conversation

@Joeavaikath
Copy link
Copy Markdown
Contributor

@Joeavaikath Joeavaikath commented Mar 9, 2026

Why the changes were made

fixes #139

Completion Install Command (issue #139):

  • Implements kubectl-oadp completion install to automate shell completion setup
  • Auto-detects user's shell (bash/zsh/fish) from $SHELL environment variable
  • Generates completion files in parallel for both oc and kubectl-oadp commands
  • Places files in shell-specific directories with correct naming conventions
  • For bash: validates bash-completion package is installed (hard requirement), shows install instructions if missing
  • Idempotent design: won't modify existing setup unless --force flag used
  • Provides clear, shell-specific setup instructions after installation

Documentation Refactor:

  • Moves design docs from design/ to docs/design/ for better organization
  • Adds comprehensive design document at docs/design/139-COMPLETION_INSTALL_DESIGN.md
  • Documents shell-specific requirements, directory structures, and gotchas

Linter Upgrade:

  • Upgrades golangci-lint from v1.63.4 → v2.11.0 for Go 1.25 support
  • Changes installation method to binary download script (v2.x requirement)
  • Adds .golangci.yml config to disable errcheck linter (appropriate for CLI tools where output errors are unrecoverable)
  • Applies auto-fixes from new linter: simplified time formatting and variable declarations

How to test the changes made

Build:

make build

Test auto-detection and idempotency:

./kubectl-oadp completion install
# ✓ Auto-detects current shell, generates files
./kubectl-oadp completion install
# ✓ Shows "already installed" message
./kubectl-oadp completion install --force
# ✓ Regenerates files

Test bash (with dependency check):

./kubectl-oadp completion install --shell bash
# ✓ If bash-completion missing: shows OS-specific install instructions
# ✓ If installed: generates files in ~/.local/share/bash-completion/completions/

Test zsh:

./kubectl-oadp completion install --shell zsh
# ✓ Generates _oc and _kubectl-oadp in ~/.zsh/completions/
# ✓ Shows .zshrc setup instructions if needed

Test fish:

./kubectl-oadp completion install --shell fish
# ✓ Generates files in ~/.config/fish/completions/
# ✓ Shows "auto-loads completions" message

Verify completions work (restart shell first):

oc oadp <TAB>
kubectl-oadp <TAB>
# ✓ Shows available subcommands

Verify linter upgrade:

make lint-fix
# ✓ Runs with golangci-lint v2.11.0
# ✓ No errcheck failures

Summary by CodeRabbit

  • New Features

    • Added a new completion install subcommand to auto-install shell completions for bash, zsh, and fish with shell detection and force-reinstall.
  • Bug Fixes

    • Improved timestamp formatting and duration calculations in several command outputs for more accurate display.
  • Documentation

    • Added design docs for the completion install feature.
    • Removed legacy CLI completion setup guide.
  • Chores

    • Upgraded Go toolchain to 1.25 and updated golangci-lint configuration and install flow.

Signed-off-by: Joseph <jvaikath@redhat.com>
Implements 'kubectl-oadp completion install' subcommand that automatically
sets up shell completions for both oc and kubectl-oadp commands.

Features:
- Auto-detects shell type (bash/zsh/fish) from $SHELL
- Generates completion files in parallel using errgroup
- Validates bash-completion package presence for bash shells
- Provides shell-specific setup instructions with smart RC file detection
- Supports --shell flag to override detection
- Supports --force flag to reinstall existing completions
- Idempotent (safe to run multiple times)

Implementation details:
- Skips output wrapping for completion command to preserve stdout
- Uses shellConfig map to eliminate duplicate shell-specific logic
- Adds timeout protection for external commands (brew, completion generation)
- Includes comprehensive design documentation

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

coderabbitai bot commented Mar 9, 2026

Warning

Rate limit exceeded

@Joeavaikath has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d69a1548-0be4-4c1a-9b2a-eab925fb0b36

📥 Commits

Reviewing files that changed from the base of the PR and between dfdac43 and 14aff5b.

📒 Files selected for processing (1)
  • go.mod
📝 Walkthrough

Walkthrough

Deleted COMPLETION.md and added a new kubectl-oadp completion install subcommand (with shell auto-detection, idempotency/--force, bash-completion checks, parallel generation of oc and kubectl-oadp completion scripts). Included design doc, Go toolchain/lint updates, Makefile/CI adjustments, and small timestamp/formatting tweaks across CLI commands.

Changes

Cohort / File(s) Summary
Doc removal
COMPLETION.md
Removed the user-facing manual for OADP CLI tab completion (setup, tests, troubleshooting, uninstall, advanced notes).
Completion command files
cmd/completion/completion.go, cmd/completion/install.go
Added new completion command and install subcommand implementing shell detection, per-shell configs (bash/zsh/fish), idempotency and --force, bash-completion validation, parallel generation/writing of oc and kubectl-oadp completion scripts, file IO and user setup instructions.
Root integration
cmd/root.go
Imported local completion package and excluded completion commands from Velero→oadp output replacement in command wrapping logic.
Design doc
docs/design/139-COMPLETION_INSTALL_DESIGN.md
New design document describing install flow, RC-file marker strategy, ordering nuances, testing checklist, and troubleshooting for the install subcommand.
Tooling & CI changes
go.mod, .golangci.yml, Makefile, .github/workflows/lint.yml, Containerfile.download
Bumped Go toolchain to 1.25; added indirect golang.org/x/sync; added golangci-lint config and installer change in Makefile; CI action versions and Go version updated; builder image bumped to Go 1.25.
Minor CLI formatting/timestamp fixes
cmd/nabsl-request/describe.go, cmd/nabsl-request/get.go, cmd/non-admin/backup/..., cmd/non-admin/restore/...
Switched timestamp formatting to call Format on timestamp objects instead of .Time, small fmt.Fprintf formatting changes, and minor var declaration style tweaks.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as "kubectl-oadp completion install"
    participant ShellDetect as "Shell Detection"
    participant Validator as "Validation (bash-completion check)"
    participant Generator as "Completion Generation"
    participant FS as "File System"

    User->>CLI: run install [--shell <opt>] 
    CLI->>ShellDetect: detect or use provided shell
    ShellDetect-->>CLI: shell (bash | zsh | fish)
    CLI->>Validator: check existing installation & requirements
    alt already installed && not --force
        Validator-->>CLI: skip install
        CLI->>User: print guidance
    else
        Validator->>Validator: if bash, verify bash-completion available
        Validator-->>CLI: validation passed
        CLI->>Generator: generate `oc` and `kubectl-oadp` completions (parallel)
        Generator-->>CLI: completion scripts
        CLI->>FS: create dirs & write files
        FS-->>CLI: write success
        CLI->>User: print success + shell-specific setup instructions
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Command cleanup #140 — Modifies cmd/root.go command wiring; strongly related due to overlapping root command logic changes.

Suggested reviewers

  • kaovilai
  • weshayutin

Poem

🐰 I hop through shells at break of day,
I bake two scripts in parallel play.
Old docs gone, new commands in tune,
Tab-complete dances under the moon.
Nibble a carrot, let auto-complete swoon 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: adding a completion install command for shell autocompletion, which is the primary purpose of this PR.
Description check ✅ Passed The description fully addresses the template requirements with clear explanations of why changes were made and comprehensive testing instructions for all features.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • 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

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

🧹 Nitpick comments (2)
docs/design/139-COMPLETION_INSTALL_DESIGN.md (1)

38-47: Add language specifiers to fenced code blocks.

Several code blocks are missing language specifiers, which affects rendering and syntax highlighting. Consider adding appropriate language identifiers.

📝 Proposed fixes

For line 38 (error message block):

-```
+```text
 Error: bash-completion package is required for bash shell completions.

For line 170 (command structure):

-```
+```text
 kubectl-oadp completion

For line 180 (install flow):

-```
+```text
 1. Detect shell (or use --shell flag)

Also applies to: 170-176, 180-207

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/design/139-COMPLETION_INSTALL_DESIGN.md` around lines 38 - 47, The
fenced code blocks in the design doc lack language specifiers; update each
fenced block that contains the exact strings "Error: bash-completion package is
required for bash shell completions.", "kubectl-oadp completion", and the
numbered step "1. Detect shell (or use --shell flag)" to include an appropriate
language tag (e.g., ```text or ```bash) so they render with proper syntax
highlighting and formatting.
cmd/completion/install.go (1)

89-98: Improve error messaging when shell cannot be detected.

When $SHELL is empty and --shell is not provided, o.Shell remains empty. The subsequent Validate() error message shows "unsupported shell: " with an empty string, which may confuse users.

♻️ Proposed improvement
 // Complete completes the options
 func (o *InstallOptions) Complete(args []string) error {
 	// Auto-detect shell if not specified
 	if o.Shell == "" {
 		shell := os.Getenv("SHELL")
 		if shell != "" {
 			o.Shell = filepath.Base(shell)
+		} else {
+			return fmt.Errorf("could not auto-detect shell from $SHELL environment variable; use --shell to specify")
 		}
 	}
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/completion/install.go` around lines 89 - 98, The Complete method leaves
o.Shell empty if $SHELL and the --shell flag are missing, causing Validate() to
emit "unsupported shell: " with a blank value; update func (o *InstallOptions)
Complete to set a sensible default (e.g., o.Shell = "sh") when both the
environment and flag are unset so Validate() receives a non-empty shell string
(reference: InstallOptions.Complete and the o.Shell field used by Validate()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/completion/install.go`:
- Around line 206-215: getCompletionDir can return a path with no home prefix
when os.UserHomeDir() fails and $HOME is empty; update getCompletionDir to
return (string, error) (or at minimum return empty string on failure) and update
its callers (notably InstallOptions.Run) to check the returned error/empty
string and surface a descriptive error instead of proceeding; reference the
getCompletionDir function, InstallOptions.Run method, shellConfigs[o.Shell] and
config.completionSubdir when locating the code to change so you validate home
(from os.UserHomeDir() or $HOME) and abort with a clear error if it cannot be
determined.
- Around line 263-272: The code currently uses cmd.CombinedOutput() which mixes
stdout and stderr and can corrupt the generated completion file; change to use
cmd.Output() to capture only stdout and direct stderr to a separate buffer for
error diagnostics: create a bytes.Buffer (or similar) and assign it to
cmd.Stderr before calling cmd.Output(), call output, err := cmd.Output(), and on
error include the stderr buffer contents in the returned fmt.Errorf message
while still writing only the stdout bytes to os.WriteFile; references to update:
exec.CommandContext(ctx, command, "completion", o.Shell), cmd.CombinedOutput(),
and os.WriteFile(outputFile, output, 0644).

---

Nitpick comments:
In `@cmd/completion/install.go`:
- Around line 89-98: The Complete method leaves o.Shell empty if $SHELL and the
--shell flag are missing, causing Validate() to emit "unsupported shell: " with
a blank value; update func (o *InstallOptions) Complete to set a sensible
default (e.g., o.Shell = "sh") when both the environment and flag are unset so
Validate() receives a non-empty shell string (reference: InstallOptions.Complete
and the o.Shell field used by Validate()).

In `@docs/design/139-COMPLETION_INSTALL_DESIGN.md`:
- Around line 38-47: The fenced code blocks in the design doc lack language
specifiers; update each fenced block that contains the exact strings "Error:
bash-completion package is required for bash shell completions.", "kubectl-oadp
completion", and the numbered step "1. Detect shell (or use --shell flag)" to
include an appropriate language tag (e.g., ```text or ```bash) so they render
with proper syntax highlighting and formatting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 506b7248-2137-41ce-aceb-e7f271e17a0d

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8d6b9 and b42c3bb.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • COMPLETION.md
  • cmd/completion/completion.go
  • cmd/completion/install.go
  • cmd/root.go
  • docs/design/139-COMPLETION_INSTALL_DESIGN.md
  • docs/design/kubectl-oadp-design.md
  • go.mod
💤 Files with no reviewable changes (1)
  • COMPLETION.md

Updates golangci-lint from v1.63.4 to v2.11.0 which is built with
Go 1.26 and supports Go 1.25 projects. Changes installation method
from 'go install' to official binary download script as v2.x requires.

Adds .golangci.yml config to disable errcheck for CLI tool where
output errors are typically unrecoverable (if writing to stdout fails,
the program is fundamentally broken).

Applies auto-fixes from new linter:
- Use metav1.Time.Format() directly instead of .Time.Format()
- Simplify variable declarations with type inference
- Use fmt.Fprintf for string builder formatting

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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
Makefile (1)

370-374: ⚠️ Potential issue | 🟠 Major

Don't pipe a moving remote installer straight into sh.

Using master/install.sh makes the bootstrap non-reproducible. Additionally, with make's default /bin/sh, a failed curl is silently masked by the pipeline—if the download fails, sh -s -- exits 0 on empty stdin, leaving $(GOLANGCI_LINT) absent while the recipe appears to succeed.

Fetch a version-pinned script first (or vendor it) and execute it as a separate step to ensure failures are properly detected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 370 - 374, The Makefile currently pipes the remote
installer into sh which masks curl failures and uses an unpinned master script;
change the recipe that references GOLANGCI_LINT, GOLANGCI_LINT_VERSION and
LOCALBIN to first download the specific, versioned installer to a temporary file
with curl -fSLo (or vendor a copy), check curl's exit code, make the file
executable, then execute that local script (chmod +x && ./script) so download
failures are detected and the install is reproducible instead of using "curl |
sh".
🧹 Nitpick comments (1)
.golangci.yml (1)

3-5: Scope the errcheck exemption instead of disabling it repo-wide.

The rationale here is about best-effort CLI output, but this switch also turns off ignored-error detection for unrelated file, process, and cleanup paths. A targeted //nolint:errcheck or a narrower exclusion rule keeps that signal where it still matters.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.golangci.yml around lines 3 - 5, Remove the global errcheck disable in
.golangci.yml and instead scope the exemption to the CLI codepaths: delete the
"- errcheck" entry under linters.disable and add targeted suppressions either by
placing //nolint:errcheck comments on the specific functions/files that
intentionally ignore errors in your CLI (e.g., main, cmd/* handlers) or by
adding golangci-lint exclude or linters-settings rules that match those CLI file
patterns; keep the linter enabled for the rest of the repo so errcheck still
flags ignored errors outside the intended CLI output paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.golangci.yml:
- Around line 7-9: The CI lint workflow installs Go 1.24 while go.mod and
.golangci.yml target Go 1.25; update the workflow step that provisions Go (the
action input named "go-version" or the matrix entry used by the setup action in
the lint workflow) to use "1.25" so the runner Go version matches go.mod and
.golangci.yml and prevents mismatched-toolchain failures.

---

Outside diff comments:
In `@Makefile`:
- Around line 370-374: The Makefile currently pipes the remote installer into sh
which masks curl failures and uses an unpinned master script; change the recipe
that references GOLANGCI_LINT, GOLANGCI_LINT_VERSION and LOCALBIN to first
download the specific, versioned installer to a temporary file with curl -fSLo
(or vendor a copy), check curl's exit code, make the file executable, then
execute that local script (chmod +x && ./script) so download failures are
detected and the install is reproducible instead of using "curl | sh".

---

Nitpick comments:
In @.golangci.yml:
- Around line 3-5: Remove the global errcheck disable in .golangci.yml and
instead scope the exemption to the CLI codepaths: delete the "- errcheck" entry
under linters.disable and add targeted suppressions either by placing
//nolint:errcheck comments on the specific functions/files that intentionally
ignore errors in your CLI (e.g., main, cmd/* handlers) or by adding
golangci-lint exclude or linters-settings rules that match those CLI file
patterns; keep the linter enabled for the rest of the repo so errcheck still
flags ignored errors outside the intended CLI output paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 233bed93-8de5-45b8-a164-04f733601597

📥 Commits

Reviewing files that changed from the base of the PR and between b42c3bb and 7cc41fd.

📒 Files selected for processing (8)
  • .golangci.yml
  • Makefile
  • cmd/nabsl-request/describe.go
  • cmd/nabsl-request/get.go
  • cmd/non-admin/backup/describe.go
  • cmd/non-admin/backup/get.go
  • cmd/non-admin/restore/describe.go
  • cmd/non-admin/restore/get.go
✅ Files skipped from review due to trivial changes (1)
  • cmd/nabsl-request/get.go

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.

🧹 Nitpick comments (1)
.github/workflows/lint.yml (1)

46-49: Redundant golangci-lint installation and potential version drift.

The golangci-lint is already installed and executed by the action on lines 19-22. Reinstalling it on line 48 is redundant and could install a different version than the action.

Additionally, version: latest on line 22 may drift from the v2.11.0 specified in the Makefile, causing inconsistent lint results between local development and CI. Consider pinning the version in the action to match.

If the unused linter is needed, enable it in .golangci.yml rather than running a separate invocation.

♻️ Suggested fix: pin version and remove redundant step
     - name: golangci-lint
       uses: golangci/golangci-lint-action@v3
       with:
-        version: latest
+        version: v2.11.0
         args: --timeout=5m
     
     - name: Run go fmt

Then remove the redundant step entirely and configure unused in .golangci.yml:

-    - name: Check for unused dependencies
-      run: |
-        go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
-        golangci-lint run --enable unused 
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/lint.yml around lines 46 - 49, Remove the redundant "name:
Check for unused dependencies" step that runs "go install
github.com/golangci/golangci-lint..." and "golangci-lint run --enable unused";
instead pin the golangci-lint action's "version: latest" to the Makefile's
v2.11.0 so CI uses the same lint binary, and enable the "unused" linter in
.golangci.yml (rather than calling "golangci-lint run --enable unused"
separately) to avoid duplicate installs and version drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/lint.yml:
- Around line 46-49: Remove the redundant "name: Check for unused dependencies"
step that runs "go install github.com/golangci/golangci-lint..." and
"golangci-lint run --enable unused"; instead pin the golangci-lint action's
"version: latest" to the Makefile's v2.11.0 so CI uses the same lint binary, and
enable the "unused" linter in .golangci.yml (rather than calling "golangci-lint
run --enable unused" separately) to avoid duplicate installs and version drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 48a57066-98a0-48e0-ab03-ef542790746d

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc41fd and b15568a.

📒 Files selected for processing (1)
  • .github/workflows/lint.yml

Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.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.

🧹 Nitpick comments (1)
Containerfile.download (1)

4-4: Pin the builder image to an immutable Go toolchain.

golang:1.25 is a moving official tag; Docker Hub currently publishes both 1.25 and patch-specific tags like 1.25.6, so rebuilds can silently pick up a different Go patch release over time. For a stage that produces release artifacts, pinning the exact patch or, ideally, the image digest will keep builds reproducible. (hub.docker.com)

Suggested change
-FROM --platform=$BUILDPLATFORM golang:1.25 AS builder
+FROM --platform=$BUILDPLATFORM golang:1.25.6 AS builder
+# or pin by digest for full reproducibility:
+# FROM --platform=$BUILDPLATFORM golang@sha256:<digest> AS builder
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Containerfile.download` at line 4, The builder stage uses a floating Go tag
in the Dockerfile line "FROM --platform=$BUILDPLATFORM golang:1.25 AS builder",
which makes builds non-reproducible; update that FROM line to pin to a specific
patch release (e.g., golang:1.25.x) or, preferably, pin to the immutable image
digest (sha256:...) for the chosen Go patch so the builder stage always uses the
exact same toolchain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Containerfile.download`:
- Line 4: The builder stage uses a floating Go tag in the Dockerfile line "FROM
--platform=$BUILDPLATFORM golang:1.25 AS builder", which makes builds
non-reproducible; update that FROM line to pin to a specific patch release
(e.g., golang:1.25.x) or, preferably, pin to the immutable image digest
(sha256:...) for the chosen Go patch so the builder stage always uses the exact
same toolchain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0531c820-d64a-48a4-9b13-83a8d86a0881

📥 Commits

Reviewing files that changed from the base of the PR and between b15568a and dfdac43.

📒 Files selected for processing (3)
  • .github/workflows/lint.yml
  • .golangci.yml
  • Containerfile.download
🚧 Files skipped from review as they are similar to previous changes (2)
  • .golangci.yml
  • .github/workflows/lint.yml

Copy link
Copy Markdown
Member

@kaovilai kaovilai left a comment

Choose a reason for hiding this comment

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

Can you confirm if we are following convention as shown in https://void.abn.is/completing-kubectl-plugins/ ? or are we doing something custom here?

@kaovilai
Copy link
Copy Markdown
Member

I don't think we should automate any more than the sample plugin here..

https://github.com/kubernetes/sample-cli-plugin/blob/c28ec6cc0d39e32d1196b30ba4a5a35b780fbcea/README.md#shell-completion

Copy link
Copy Markdown
Member

@kaovilai kaovilai left a comment

Choose a reason for hiding this comment

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

Not bad. fish bash zsh do not hang.

~/git/oadp-cli issue-139-autocomplete
❯ go run . completion zsh
#compdef oadp
compdef _oadp oadp

# zsh completion for oadp                                 -*- shell-script -*-

__oadp_debug()
{
    local file="$BASH_COMP_DEBUG_FILE"
    if [[ -n ${file} ]]; then
        echo "$*" >> "${file}"
    fi
}

_oadp()
{
    local shellCompDirectiveError=1
    local shellCompDirectiveNoSpace=2
    local shellCompDirectiveNoFileComp=4
    local shellCompDirectiveFilterFileExt=8
    local shellCompDirectiveFilterDirs=16
    local shellCompDirectiveKeepOrder=32

    local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder
    local -a completions

    __oadp_debug "\n========= starting completion logic =========="
    __oadp_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}"

    # The user could have moved the cursor backwards on the command-line.
    # We need to trigger completion from the $CURRENT location, so we need
    # to truncate the command-line ($words) up to the $CURRENT location.
    # (We cannot use $CURSOR as its value does not work when a command is an alias.)
    words=("${=words[1,CURRENT]}")
    __oadp_debug "Truncated words[*]: ${words[*]},"

    lastParam=${words[-1]}
    lastChar=${lastParam[-1]}
    __oadp_debug "lastParam: ${lastParam}, lastChar: ${lastChar}"

    # For zsh, when completing a flag with an = (e.g., oadp -n=<TAB>)
    # completions must be prefixed with the flag
    setopt local_options BASH_REMATCH
    if [[ "${lastParam}" =~ '-.*=' ]]; then
        # We are dealing with a flag with an =
        flagPrefix="-P ${BASH_REMATCH}"
    fi

    # Prepare the command to obtain completions
    requestComp="${words[1]} __complete ${words[2,-1]}"
    if [ "${lastChar}" = "" ]; then
        # If the last parameter is complete (there is a space following it)
        # We add an extra empty parameter so we can indicate this to the go completion code.
        __oadp_debug "Adding extra empty parameter"
        requestComp="${requestComp} \"\""
    fi

    __oadp_debug "About to call: eval ${requestComp}"

    # Use eval to handle any environment variables and such
    out=$(eval ${requestComp} 2>/dev/null)
    __oadp_debug "completion output: ${out}"

    # Extract the directive integer following a : from the last line
    local lastLine
    while IFS='\n' read -r line; do
        lastLine=${line}
    done < <(printf "%s\n" "${out[@]}")
    __oadp_debug "last line: ${lastLine}"

    if [ "${lastLine[1]}" = : ]; then
        directive=${lastLine[2,-1]}
        # Remove the directive including the : and the newline
        local suffix
        (( suffix=${#lastLine}+2))
        out=${out[1,-$suffix]}
    else
        # There is no directive specified.  Leave $out as is.
        __oadp_debug "No directive found.  Setting do default"
        directive=0
    fi

    __oadp_debug "directive: ${directive}"
    __oadp_debug "completions: ${out}"
    __oadp_debug "flagPrefix: ${flagPrefix}"

    if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
        __oadp_debug "Completion received error. Ignoring completions."
        return
    fi

    local activeHelpMarker="_activeHelp_ "
    local endIndex=${#activeHelpMarker}
    local startIndex=$((${#activeHelpMarker}+1))
    local hasActiveHelp=0
    while IFS='\n' read -r comp; do
        # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
        if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
            __oadp_debug "ActiveHelp found: $comp"
            comp="${comp[$startIndex,-1]}"
            if [ -n "$comp" ]; then
                compadd -x "${comp}"
                __oadp_debug "ActiveHelp will need delimiter"
                hasActiveHelp=1
            fi

            continue
        fi

        if [ -n "$comp" ]; then
            # If requested, completions are returned with a description.
            # The description is preceded by a TAB character.
            # For zsh's _describe, we need to use a : instead of a TAB.
            # We first need to escape any : as part of the completion itself.
            comp=${comp//:/\\:}

            local tab="$(printf '\t')"
            comp=${comp//$tab/:}

            __oadp_debug "Adding completion: ${comp}"
            completions+=${comp}
            lastComp=$comp
        fi
    done < <(printf "%s\n" "${out[@]}")

    # Add a delimiter after the activeHelp statements, but only if:
    # - there are completions following the activeHelp statements, or
    # - file completion will be performed (so there will be choices after the activeHelp)
    if [ $hasActiveHelp -eq 1 ]; then
        if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
            __oadp_debug "Adding activeHelp delimiter"
            compadd -x "--"
            hasActiveHelp=0
        fi
    fi

    if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
        __oadp_debug "Activating nospace."
        noSpace="-S ''"
    fi

    if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then
        __oadp_debug "Activating keep order."
        keepOrder="-V"
    fi

    if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
        # File extension filtering
        local filteringCmd
        filteringCmd='_files'
        for filter in ${completions[@]}; do
            if [ ${filter[1]} != '*' ]; then
                # zsh requires a glob pattern to do file filtering
                filter="\*.$filter"
            fi
            filteringCmd+=" -g $filter"
        done
        filteringCmd+=" ${flagPrefix}"

        __oadp_debug "File filtering command: $filteringCmd"
        _arguments '*:filename:'"$filteringCmd"
    elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
        # File completion for directories only
        local subdir
        subdir="${completions[1]}"
        if [ -n "$subdir" ]; then
            __oadp_debug "Listing directories in $subdir"
            pushd "${subdir}" >/dev/null 2>&1
        else
            __oadp_debug "Listing directories in ."
        fi

        local result
        _arguments '*:dirname:_files -/'" ${flagPrefix}"
        result=$?
        if [ -n "$subdir" ]; then
            popd >/dev/null 2>&1
        fi
        return $result
    else
        __oadp_debug "Calling _describe"
        if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then
            __oadp_debug "_describe found some completions"

            # Return the success of having called _describe
            return 0
        else
            __oadp_debug "_describe did not find completions."
            __oadp_debug "Checking if we should do file completion."
            if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then
                __oadp_debug "deactivating file completion"

                # We must return an error code here to let zsh know that there were no
                # completions found by _describe; this is what will trigger other
                # matching algorithms to attempt to find completions.
                # For example zsh can match letters in the middle of words.
                return 1
            else
                # Perform file completion
                __oadp_debug "Activating file completion"

                # We must return the result of this command, so it must be the
                # last command, or else we must store its result to return it.
                _arguments '*:filename:_files'" ${flagPrefix}"
            fi
        fi
    fi
}

# don't run the completion function when being source-ed or eval-ed
if [ "$funcstack[1]" = "_oadp" ]; then
    _oadp
fi

@Joeavaikath Joeavaikath merged commit dac6316 into migtools:oadp-dev Mar 10, 2026
16 checks passed
@weshayutin
Copy link
Copy Markdown
Contributor

shoot.. was just testing

@weshayutin
Copy link
Copy Markdown
Contributor

will open a bug

Installing completions for bash...
Error: bash-completion package is required for bash shell completions.

To install:
  macOS:       brew install bash-completion
  Ubuntu:      sudo apt-get install bash-completion
  RHEL/Fedora: sudo dnf install bash-completion

After installing, run: kubectl-oadp completion install
Error: bash-completion not installed
Usage:
  oc oadp completion install [flags]

Examples:
  # Install completions for current shell
  kubectl-oadp completion install

  # Install completions for specific shell
  kubectl-oadp completion install --shell zsh

  # Reinstall/overwrite existing completions
  kubectl-oadp completion install --force

Flags:
      --force          Reinstall completions even if already installed
  -h, --help           help for install
      --shell string   Shell to install completions for (bash, zsh, fish)

Global Flags:
      --add_dir_header                   If true, adds the file directory to the header of the log messages
      --alsologtostderr                  log to standard error as well as files (no effect when -logtostderr=true)
      --kubeconfig string                Path to the kubeconfig file to use to talk to the Kubernetes apiserver. If unset, try the environment variable KUBECONFIG, as well as in-cluster configuration
      --kubecontext string               The context to use to talk to the Kubernetes apiserver. If unset defaults to whatever your current-context is (kubectl config current-context)
      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)
      --log_dir string                   If non-empty, write log files in this directory (no effect when -logtostderr=true)
      --log_file string                  If non-empty, use this log file (no effect when -logtostderr=true)
      --log_file_max_size uint           Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
      --logtostderr                      log to standard error instead of files (default true)
  -n, --namespace string                 The namespace in which Velero should operate (default "openshift-adp")
      --one_output                       If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
      --skip_headers                     If true, avoid header prefixes in the log messages
      --skip_log_headers                 If true, avoid headers when opening log files (no effect when -logtostderr=true)
      --stderrthreshold severity         logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true) (default 2)
  -v, --v Level                          number for the log level verbosity
      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

An error occurred: bash-completion not installed
whayutin@fedora:~/OPENSHIFT/git/OADP/oadp-cli$ rpm -q bash-completion
bash-completion-2.16-2.fc43.noarch
whayutin@fedora:~/OPENSHIFT/git/OADP/oadp-cli$ 

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.

oc oadp completion hangs (bash, fish)

3 participants