Refine error handling of ReadBranchConfig

cmd.Output() will return an error when the git command ran successfully
but had no output. To handle this, we can check Stderr, as we expect it to
be populated for any ExitErrors or otherwise when there is a command
failure.

This allows for propagation of this error handling up the call chain, so
we are now returning errors if the call to git fails instead of just
handing off an empty BranchConfig and suppressing the errors.

Additionally, I've removed some more naked returns that I found in
pkg/cmd/pr/create.go createRun
This commit is contained in:
Tyler McGoffin 2025-01-09 10:08:47 -08:00
parent d4f7576e8b
commit e1423cdbbf
4 changed files with 58 additions and 38 deletions

View file

@ -391,7 +391,13 @@ func (c *Client) ReadBranchConfig(ctx context.Context, branch string) (BranchCon
out, err := cmd.Output()
if err != nil {
return BranchConfig{}, err
// This will error if no matches are found but the git command still ran successfully. We only
// want to return an error if the command failed to run, usually and ExitError, which will be
// indicated by output on Stderr.
if err.(*GitError).Stderr != "" {
return BranchConfig{}, err
}
return BranchConfig{}, nil
}
return parseBranchConfig(outputLines(out)), nil

View file

@ -744,7 +744,7 @@ func TestClientReadBranchConfig(t *testing.T) {
wantError: nil,
},
{
name: "command error",
name: "output error",
cmdExitStatus: 1,
cmdStdout: "",
cmdStderr: "git error message",
@ -752,6 +752,15 @@ func TestClientReadBranchConfig(t *testing.T) {
wantBranchConfig: BranchConfig{},
wantError: &GitError{ExitCode: 1, Stderr: "git error message"},
},
{
name: "git config runs successfully but returns no output",
cmdExitStatus: 1,
cmdStdout: "",
cmdStderr: "",
branch: "trunk",
wantBranchConfig: BranchConfig{},
wantError: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -764,7 +773,10 @@ func TestClientReadBranchConfig(t *testing.T) {
wantCmdArgs := fmt.Sprintf("path/to/git config --get-regexp ^branch\\.%s\\.(remote|merge|gh-merge-base)$", tt.branch)
assert.Equal(t, wantCmdArgs, strings.Join(cmd.Args[3:], " "))
assert.Equal(t, tt.wantBranchConfig, branchConfig)
if tt.wantError != nil {
if err != nil {
if tt.wantError == nil {
t.Fatalf("expected no error but got %v", err)
}
assert.Equal(t, tt.wantError.ExitCode, err.(*GitError).ExitCode)
assert.Equal(t, tt.wantError.Stderr, err.(*GitError).Stderr)
}
@ -774,34 +786,34 @@ func TestClientReadBranchConfig(t *testing.T) {
func Test_parseBranchConfig(t *testing.T) {
tests := []struct {
name string
gitBranchConfigOutput []string
wantBranchConfig BranchConfig
name string
configLines []string
wantBranchConfig BranchConfig
}{
{
name: "remote branch",
gitBranchConfigOutput: []string{"branch.trunk.remote origin"},
name: "remote branch",
configLines: []string{"branch.trunk.remote origin"},
wantBranchConfig: BranchConfig{
RemoteName: "origin",
},
},
{
name: "merge ref",
gitBranchConfigOutput: []string{"branch.trunk.merge refs/heads/trunk"},
name: "merge ref",
configLines: []string{"branch.trunk.merge refs/heads/trunk"},
wantBranchConfig: BranchConfig{
MergeRef: "refs/heads/trunk",
},
},
{
name: "merge base",
gitBranchConfigOutput: []string{"branch.trunk.gh-merge-base gh-merge-base"},
name: "merge base",
configLines: []string{"branch.trunk.gh-merge-base gh-merge-base"},
wantBranchConfig: BranchConfig{
MergeBase: "gh-merge-base",
},
},
{
name: "remote, merge ref, and merge base all specified",
gitBranchConfigOutput: []string{
configLines: []string{
"branch.trunk.remote origin",
"branch.trunk.merge refs/heads/trunk",
"branch.trunk.gh-merge-base gh-merge-base",
@ -814,7 +826,7 @@ func Test_parseBranchConfig(t *testing.T) {
},
{
name: "remote URL",
gitBranchConfigOutput: []string{
configLines: []string{
"branch.Frederick888/main.remote git@github.com:Frederick888/playground.git",
"branch.Frederick888/main.merge refs/heads/main",
},
@ -831,7 +843,7 @@ func Test_parseBranchConfig(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
branchConfig := parseBranchConfig(tt.gitBranchConfigOutput)
branchConfig := parseBranchConfig(tt.configLines)
assert.Equal(t, tt.wantBranchConfig.RemoteName, branchConfig.RemoteName)
assert.Equal(t, tt.wantBranchConfig.MergeRef, branchConfig.MergeRef)
assert.Equal(t, tt.wantBranchConfig.MergeBase, branchConfig.MergeBase)