1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-02-03 13:11:48 +02:00

feat(git): retry git clone on retriable error (#4725)

This PR adds retry logic to the process of cloning a git repository.
Currently, it retries only if the output of the git clone command
contains the string `Connection reset`.
Probably, there are more cases where retry is reasonable, but I'm not
sure what they are.

The number of retries is hardcoded to 10 with increasing delay between
retries — in the same way as it is done in #4265, which served me as an
example.

The initial use case is described in #4724.
This commit is contained in:
German Lashevich 2024-03-27 03:41:25 +01:00 committed by GitHub
parent a00bf7e5d6
commit ec7106fdea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"
"sync"
"time"
"github.com/caarlos0/log"
"github.com/charmbracelet/x/exp/ordered"
@ -85,10 +86,8 @@ func (g *gitClient) CreateFiles(
return fmt.Errorf("git: failed to create parent: %w", err)
}
if err := runGitCmds(ctx, parent, env, [][]string{
{"clone", url, name},
}); err != nil {
return fmt.Errorf("git: failed to clone local repository: %w", err)
if err := cloneRepoWithRetries(ctx, parent, url, name, env); err != nil {
return err
}
if err := runGitCmds(ctx, cwd, env, [][]string{
@ -200,6 +199,31 @@ func isPasswordError(err error) bool {
return errors.As(err, &kerr)
}
func cloneRepoWithRetries(ctx *context.Context, parent, url, name string, env []string) error {
var try int
for try < 10 {
try++
err := runGitCmds(ctx, parent, env, [][]string{{"clone", url, name}})
if err == nil {
return nil
}
if isRetriableCloneError(err) {
log.WithField("try", try).
WithField("image", name).
WithError(err).
Warnf("failed to push image, will retry")
time.Sleep(time.Duration(try*10) * time.Second)
continue
}
return fmt.Errorf("failed to clone local repository: %w", err)
}
return fmt.Errorf("failed to push %s after %d tries", name, try)
}
func isRetriableCloneError(err error) bool {
return strings.Contains(err.Error(), "Connection reset")
}
func runGitCmds(ctx *context.Context, cwd string, env []string, cmds [][]string) error {
for _, cmd := range cmds {
args := append([]string{"-C", cwd}, cmd...)