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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
81a5a95626ca87305d349d6fdd0cef3c2dd786b0
a2dd81492d93730eb5ce60564ee0e8f87ae4c84c
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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: "image/git-init/go.mod"
cache-dependency-path: "image/git-init/go.sum"
Expand Down
12 changes: 6 additions & 6 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- run: git fetch --prune --unshallow

- uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.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: imjasonh/setup-crane@6da1ae018866400525525ce74ff892880c099987 # v0.5

- uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
- uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1

- 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@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
id: run-goreleaser
with:
version: latest
Expand Down
92 changes: 83 additions & 9 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 @@ -156,6 +167,11 @@ func Fetch(logger *zap.SugaredLogger, spec FetchSpec) error {
}
if spec.Depth > 0 {
fetchArgs = append(fetchArgs, fmt.Sprintf("--depth=%d", spec.Depth))

// Prevent fetching of unrelated git objects with shallow clones.
if _, err := run(logger, "", "config", "--unset", "remote.origin.fetch"); err != nil {
logger.Warnf("Failed to unset remote.origin.fetch in git config: %s", err)
}
}

// Fetch the revision and verify with FETCH_HEAD
Expand All @@ -177,7 +193,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 +222,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 +246,32 @@ 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 buildSubmoduleUpdateArgs(spec FetchSpec) []string {
updateArgs := []string{"submodule", "update", "--recursive", "--init", "--force"}
if spec.Depth > 0 {
updateArgs = append(updateArgs, fmt.Sprintf("--depth=%d", spec.Depth))
}
if len(spec.SubmodulePaths) > 0 {
updateArgs = append(updateArgs, spec.SubmodulePaths...)
}
return updateArgs
}

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"}
if spec.Depth > 0 {
updateArgs = append(updateArgs, fmt.Sprintf("--depth=%d", spec.Depth))
}
if _, err := run(logger, "", updateArgs...); err != nil {
updateArgs := buildSubmoduleUpdateArgs(spec)
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 +374,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