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
26 changes: 20 additions & 6 deletions cmd/repo-brancher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func main() {
continue
}

for depth := 1; depth < 9; depth += 1 {
for depth := 1; depth <= 9; depth += 1 {
retry, err := pushBranch(logger, remote, futureBranch, gitCmd)
if err != nil {
logger.WithError(err).Error("Failed to push branch")
Expand All @@ -193,13 +193,19 @@ func main() {
break
}

if depth == 8 && retry {
logger.Error("Could not push branch even with retries.")
if depth == 9 {
logger.Error("Could not push branch even after unshallowing.")
appendFailedConfig(configuration)
break
}

if err := fetchDeeper(logger, remote, gitCmd, repoInfo, int(math.Exp2(float64(depth)))); err != nil {
if depth == 8 {
logger.Warn("Progressive deepening was not enough, fetching full history...")
if err := fetchUnshallow(logger, remote, gitCmd, repoInfo); err != nil {
appendFailedConfig(configuration)
Comment thread
petr-muller marked this conversation as resolved.
return nil
}
} else if err := fetchDeeper(logger, remote, gitCmd, repoInfo, int(math.Exp2(float64(depth-1)))); err != nil {
appendFailedConfig(configuration)
return nil
}
Expand Down Expand Up @@ -235,8 +241,16 @@ func pushBranch(logger *logrus.Entry, remote *url.URL, futureBranch string, gitC
return false, nil
}

func fetchDeeper(logger *logrus.Entry, remote *url.URL, gitCmd gitCmd, repoInfo *config.Info, depth int) error {
command := []string{"fetch", "--depth", strconv.Itoa(depth), remote.String(), repoInfo.Branch}
func fetchDeeper(logger *logrus.Entry, remote *url.URL, gitCmd gitCmd, repoInfo *config.Info, deepenBy int) error {
command := []string{"fetch", "--deepen", strconv.Itoa(deepenBy), remote.String(), repoInfo.Branch}
if err := gitCmd(logger, command...); err != nil {
return err
}
return nil
}

func fetchUnshallow(logger *logrus.Entry, remote *url.URL, gitCmd gitCmd, repoInfo *config.Info) error {
command := []string{"fetch", "--unshallow", remote.String(), repoInfo.Branch}
if err := gitCmd(logger, command...); err != nil {
return err
}
Expand Down
135 changes: 135 additions & 0 deletions cmd/repo-brancher/main_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package main

import (
"errors"
"flag"
"fmt"
"net/url"
"reflect"
"strings"
"testing"

"github.com/sirupsen/logrus"

"sigs.k8s.io/prow/pkg/flagutil"

"github.com/openshift/ci-tools/pkg/api"
"github.com/openshift/ci-tools/pkg/config"
"github.com/openshift/ci-tools/pkg/promotion"
)
Expand Down Expand Up @@ -105,3 +112,131 @@ func TestOptions_Bind(t *testing.T) {
})
}
}

func TestPushBranch(t *testing.T) {
remote, _ := url.Parse("https://github.com/org/repo")
Comment thread
petr-muller marked this conversation as resolved.
logger := logrus.NewEntry(logrus.StandardLogger())

testCases := []struct {
name string
gitErr error
expectedRetry bool
expectedErr bool
}{
{
name: "successful push",
gitErr: nil,
expectedRetry: false,
expectedErr: false,
},
{
name: "too shallow error triggers retry",
gitErr: fmt.Errorf("Updates were rejected because the remote contains work that you do"),
expectedRetry: true,
expectedErr: false,
},
{
name: "other push error is fatal",
gitErr: fmt.Errorf("permission denied"),
expectedRetry: false,
expectedErr: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockGit := func(_ *logrus.Entry, args ...string) error {
if args[0] != "push" {
t.Errorf("expected push command, got %v", args)
Comment thread
petr-muller marked this conversation as resolved.
}
return tc.gitErr
}
retry, err := pushBranch(logger, remote, "release-4.18", mockGit)
if retry != tc.expectedRetry {
t.Errorf("expected retry=%v, got %v", tc.expectedRetry, retry)
}
if (err != nil) != tc.expectedErr {
t.Errorf("expected error=%v, got %v", tc.expectedErr, err)
}
})
}
}

func TestFetchDeeper(t *testing.T) {
remote, _ := url.Parse("https://github.com/org/repo")
logger := logrus.NewEntry(logrus.StandardLogger())
repoInfo := &config.Info{Metadata: api.Metadata{Branch: "main"}}

testCases := []struct {
name string
deepenBy int
gitErr error
expectedErr bool
}{
{
name: "successful deepen",
deepenBy: 4,
},
{
name: "fetch error propagated",
deepenBy: 8,
gitErr: errors.New("network error"),
expectedErr: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockGit := func(_ *logrus.Entry, args ...string) error {
expected := fmt.Sprintf("fetch --deepen %d %s main", tc.deepenBy, remote.String())
got := strings.Join(args, " ")
if got != expected {
t.Errorf("expected command %q, got %q", expected, got)
}
return tc.gitErr
}
err := fetchDeeper(logger, remote, mockGit, repoInfo, tc.deepenBy)
if (err != nil) != tc.expectedErr {
t.Errorf("expected error=%v, got %v", tc.expectedErr, err)
}
})
}
}

func TestFetchUnshallow(t *testing.T) {
remote, _ := url.Parse("https://github.com/org/repo")
logger := logrus.NewEntry(logrus.StandardLogger())
repoInfo := &config.Info{Metadata: api.Metadata{Branch: "main"}}

testCases := []struct {
name string
gitErr error
expectedErr bool
}{
{
name: "successful unshallow",
},
{
name: "fetch error propagated",
gitErr: errors.New("network error"),
expectedErr: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockGit := func(_ *logrus.Entry, args ...string) error {
expected := fmt.Sprintf("fetch --unshallow %s main", remote.String())
got := strings.Join(args, " ")
if got != expected {
t.Errorf("expected command %q, got %q", expected, got)
}
return tc.gitErr
}
err := fetchUnshallow(logger, remote, mockGit, repoInfo)
if (err != nil) != tc.expectedErr {
t.Errorf("expected error=%v, got %v", tc.expectedErr, err)
}
})
}
}