Skip to content
Open
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
2 changes: 1 addition & 1 deletion head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
81a5a95626ca87305d349d6fdd0cef3c2dd786b0
688f02aa76d36c52470ee8e9e1e111d170f529ff
4 changes: 2 additions & 2 deletions upstream/.github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version-file: "image/git-init/go.mod"
cache-dependency-path: "image/git-init/go.sum"
Expand Down
10 changes: 5 additions & 5 deletions upstream/.github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@ jobs:
# run:
# working-directory: ./image/git-init
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1

- run: git fetch --prune --unshallow

- uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
- uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version-file: "image/git-init/go.mod"
cache-dependency-path: "image/git-init/go.sum"

# This installs the current latest release.
- uses: ko-build/setup-ko@d982fec422852203cfb2053a8ec6ad302280d04d # v0.8
- uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9

- uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4

- uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
- uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0

- name: Set tag output
id: tag
run: echo "tag_name=${GITHUB_REF#refs/*/}" >> "$GITHUB_OUTPUT"

- uses: goreleaser/goreleaser-action@90a3faa9d0182683851fbfa97ca1a2cb983bfca3 # v6.2.1
- uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
id: run-goreleaser
with:
version: latest
Expand Down
76 changes: 70 additions & 6 deletions upstream/image/git-init/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ package git
import (
"bytes"
"fmt"
"math"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"

homedir "github.com/mitchellh/go-homedir"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
Expand Down Expand Up @@ -64,15 +67,23 @@ type FetchSpec struct {
Path string
Depth uint
Submodules bool
SubmodulePaths []string
SSLVerify bool
HTTPProxy string
HTTPSProxy string
NOProxy string
SparseCheckoutDirectories string
}

type RetryConfig struct {
Initial time.Duration
Max time.Duration
Factor float64
MaxAttempts int
}

// Fetch fetches the specified git repository at the revision into path, using the refspec to fetch if provided.
func Fetch(logger *zap.SugaredLogger, spec FetchSpec) error {
func Fetch(logger *zap.SugaredLogger, spec FetchSpec, retryConfig RetryConfig) error {
homepath, err := homedir.Dir()
if err != nil {
logger.Errorf("Unexpected error getting the user home directory: %v", err)
Expand Down Expand Up @@ -177,7 +188,14 @@ func Fetch(logger *zap.SugaredLogger, spec FetchSpec) error {
// when the refspec specifies the same destination twice)
fetchArgs = append(fetchArgs, "origin", "--update-head-ok", "--force")
fetchArgs = append(fetchArgs, fetchParam...)
if _, err := run(logger, spec.Path, fetchArgs...); err != nil {
if _, _, err := retryWithBackoff(
func() (string, error) { return run(logger, spec.Path, fetchArgs...) },
retryConfig.Initial,
retryConfig.Max,
retryConfig.Factor,
retryConfig.MaxAttempts,
logger,
); err != nil {
return fmt.Errorf("failed to fetch %v: %v", fetchParam, err)
}
// After performing a fetch, verify that the item to checkout is actually valid
Expand All @@ -199,7 +217,7 @@ func Fetch(logger *zap.SugaredLogger, spec FetchSpec) error {
}
logger.Infof("Successfully cloned %s @ %s (%s) in path %s", trimmedURL, commit, ref, spec.Path)
if spec.Submodules {
if err := submoduleFetch(logger, spec); err != nil {
if err := submoduleFetch(logger, spec, retryConfig); err != nil {
return err
}
}
Expand All @@ -223,17 +241,27 @@ func showRef(logger *zap.SugaredLogger, revision, path string) (string, error) {
return strings.TrimSuffix(output, "\n"), nil
}

func submoduleFetch(logger *zap.SugaredLogger, spec FetchSpec) error {
func submoduleFetch(logger *zap.SugaredLogger, spec FetchSpec, retryConfig RetryConfig) error {
if spec.Path != "" {
if err := os.Chdir(spec.Path); err != nil {
return fmt.Errorf("failed to change directory with path %s; err: %w", spec.Path, err)
}
}
updateArgs := []string{"submodule", "update", "--recursive", "--init"}
updateArgs := []string{"submodule", "update", "--recursive", "--init", "--force"}
if spec.Depth > 0 {
updateArgs = append(updateArgs, fmt.Sprintf("--depth=%d", spec.Depth))
}
if _, err := run(logger, "", updateArgs...); err != nil {
if len(spec.SubmodulePaths) > 0 {
updateArgs = append(updateArgs, spec.SubmodulePaths...)
}
if _, _, err := retryWithBackoff(
func() (string, error) { return run(logger, "", updateArgs...) },
retryConfig.Initial,
retryConfig.Max,
retryConfig.Factor,
retryConfig.MaxAttempts,
logger,
); err != nil {
return err
}
logger.Infof("Successfully initialized and updated submodules in path %s", spec.Path)
Expand Down Expand Up @@ -336,3 +364,39 @@ func configSparseCheckout(logger *zap.SugaredLogger, spec FetchSpec) error {
}
return nil
}

type operation[T any] func() (T, error)

// retryWithBackoff runs `operation` until it succeeds or the context is done,
// with exponential backoff and jitter between retries.
func retryWithBackoff[T any](
operation operation[T],
initial time.Duration,
max time.Duration,
factor float64,
maxAttempts int,
logger *zap.SugaredLogger,
) (T, time.Duration, error) {

waitTime := time.Duration(0)

for attempt := 0; ; attempt++ {
logger.Infof("Retrying operation (attempt %d)", attempt+1)
result, err := operation()
if err == nil {
return result, waitTime, nil
}

if attempt+1 == maxAttempts {
return result, waitTime, err
}

// compute backoff: exponential
backoff := min(time.Duration(float64(initial)*math.Pow(factor, float64(attempt))), max)
// add jitter: random in [0, next)
jitter := time.Duration(rand.Int63n(int64(backoff)))
wait := backoff + jitter/2
time.Sleep(wait)
waitTime += wait
}
}
Loading
Loading