Skip to content

test(ssh): cover helper error classification - #1073

Open
devsy-app[bot] wants to merge 3 commits into
mainfrom
pkg-ssh-git/helper-runerror-tests
Open

test(ssh): cover helper error classification#1073
devsy-app[bot] wants to merge 3 commits into
mainfrom
pkg-ssh-git/helper-runerror-tests

Conversation

@devsy-app

@devsy-app devsy-app Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Package reviewed

pkg/ssh (helper.go) - SSH/git/credentials category.

Issue found

helper.go had no test file. Its core helpers were entirely untested:

  • ExitError (the package's exit-status error type: Error(), Unwrap())
  • RunOptions.validate (client/command precondition checks)
  • handleRunError (error classification: cancelled context -> ctx.Err(), io.EOF -> wrapped, generic -> wrapped, *ssh.ExitError -> wrapped in ExitError)
  • setupContextCancellation (context watcher lifecycle + already-cancelled fast path)

The most subtle logic - the signal-exit-code classification inside handleRunError (exit codes 130/129/143 => nil, i.e. SIGINT/SIGHUP/SIGTERM are treated as normal interactive-session exits) - was inline and unreachable by a direct unit test, because *ssh.ExitError embeds the unexported ssh.Waitmsg and cannot be constructed from outside the package with a custom exit status.

Change

One behavior-preserving refactor + tests (no behavioral change):

  1. pkg/ssh/helper.go - extracted the inline 130 || 129 || 143 check into a small pure function isSignalInterrupt(exitCode int) bool, called from the same spot in handleRunError. The classification semantics are identical; only the shape changed so the logic is independently testable.
  2. pkg/ssh/helper_test.go (new) - 12 focused tests:
    • ExitError.Error() with/without a wrapped err; Unwrap() round-trips via errors.Is/errors.Unwrap.
    • RunOptions.validate rejects missing client, rejects missing command, accepts both present.
    • isSignalInterrupt: 130/129/143 => true; 0/1/2/127/128/131/142/144/255/-1 => false.
    • handleRunError: cancelled context returns context.Canceled; io.EOF is wrapped with the command and stays errors.Is(io.EOF); a generic error is wrapped and stays errors.Is(inner); a *ssh.ExitError (zero Waitmsg => ExitStatus()==0, not a signal interrupt) is wrapped in our ExitError with the right code and preserves errors.Is(sshExitErr).
    • setupContextCancellation: already-cancelled context returns context.Canceled with nil cleanup; a fresh context returns a non-nil cleanup that is safe to call once.

Verification

  • task cli:format - clean.
  • task cli:lint:ci - 0 issues (new-from-patch against origin/main).
  • task cli:test - pkg/ssh passes (ok github.com/devsy-org/devsy/pkg/ssh, coverage 51.2%). The only failure is pkg/git TestRepoClone*, which is the known pre-existing failure on origin/main (confirmed by checking out origin/main and reproducing the identical failures) and is unrelated to this change (touches pkg/ssh only).
  • go test ./pkg/ssh/ (focused) - all 12 new tests pass.

This PR was created by an AI agent as part of an automated daily package review job.

Extract isSignalInterrupt pure function from handleRunError (behavior-preserving) and add helper_test.go covering ExitError, RunOptions.validate, isSignalInterrupt, handleRunError, and setupContextCancellation.
@netlify

netlify Bot commented Aug 16, 2026

Copy link
Copy Markdown

Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit b3eb4a8
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a829e3c67745700086be73a

@netlify

netlify Bot commented Aug 16, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev ready!

Name Link
🔨 Latest commit b3eb4a8
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a829e3cb5a69b00077b0ac9
😎 Deploy Preview https://deploy-preview-1073--devsydev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 16 complexity · 0 duplication

Metric Results
Complexity 16
Duplication 0

View in Codacy

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@github-actions github-actions Bot added size/m and removed size/l labels Aug 17, 2026
@skevetter
skevetter marked this pull request as ready for review August 17, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant