Skip to content

Commit

Permalink
make git push detect non-fast-forwards
Browse files Browse the repository at this point in the history
Signed-off-by: Kent Rancourt <[email protected]>
  • Loading branch information
krancour committed Dec 16, 2024
1 parent 4233dd5 commit 15d0580
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
10 changes: 10 additions & 0 deletions internal/controller/git/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ var ErrMergeConflict = errors.New("merge conflict")
func IsMergeConflict(err error) bool {
return errors.Is(err, ErrMergeConflict)
}

// ErrNonFastForward is returned when a push is rejected because it is not a
// fast-forward or needs to be fetched first.
var ErrNonFastForward = errors.New("non-fast-forward")

// IsNonFastForward returns true if the error is a non-fast-forward or wraps one
// and false otherwise.
func IsNonFastForward(err error) bool {
return errors.Is(err, ErrNonFastForward)
}
37 changes: 36 additions & 1 deletion internal/controller/git/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestIsMergeConflict(t *testing.T) {
expected: false,
},
{
name: "not a a merge conflict",
name: "not a merge conflict",
err: errors.New("something went wrong"),
expected: false,
},
Expand All @@ -42,3 +42,38 @@ func TestIsMergeConflict(t *testing.T) {
})
}
}

func TestIsNonFastForward(t *testing.T) {
testCases := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "not a non-fast-forward error",
err: errors.New("something went wrong"),
expected: false,
},
{
name: "a non-fast-forward error",
err: ErrNonFastForward,
expected: true,
},
{
name: "a wrapped fast forward error",
err: fmt.Errorf("an error occurred: %w", ErrNonFastForward),
expected: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
actual := IsNonFastForward(testCase.err)
require.Equal(t, testCase.expected, actual)
})
}
}
11 changes: 10 additions & 1 deletion internal/controller/git/work_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -516,6 +517,11 @@ type PushOptions struct {
PullRebase bool
}

// https://regex101.com/r/aNYjHP/1
//
// nolint: lll
var nonFastForwardRegex = regexp.MustCompile(`(?m)^\s*!\s+\[(?:remote )?rejected].+\((?:non-fast-forward|fetch first|cannot lock ref.*)\)\s*$`)

func (w *workTree) Push(opts *PushOptions) error {
if opts == nil {
opts = &PushOptions{}
Expand Down Expand Up @@ -551,7 +557,10 @@ func (w *workTree) Push(opts *PushOptions) error {
if opts.Force {
args = append(args, "--force")
}
if _, err := libExec.Exec(w.buildGitCommand(args...)); err != nil {
if res, err := libExec.Exec(w.buildGitCommand(args...)); err != nil {
if nonFastForwardRegex.MatchString(string(res)) {
return fmt.Errorf("error pushing branch: %w", ErrNonFastForward)
}
return fmt.Errorf("error pushing branch: %w", err)
}
return nil
Expand Down

0 comments on commit 15d0580

Please sign in to comment.