From 330dea7a37e7bb87d4db1f174dc1e205a96f16f7 Mon Sep 17 00:00:00 2001 From: openshift-pipelines-bot Date: Tue, 2 Dec 2025 02:46:40 +0000 Subject: [PATCH] [bot] Update release-v1.20.x from tektoncd-catalog/git-clone to 688f02aa76d36c52470ee8e9e1e111d170f529ff $ git diff --stat 688f02aa76d36c52470ee8e9e1e111d170f529ff..81a5a95626ca87305d349d6fdd0cef3c2dd786b0 .github/workflows/build.yaml | 4 +- .github/workflows/release.yaml | 10 +- image/git-init/git/git.go | 76 +------- image/git-init/git/git_test.go | 200 +-------------------- image/git-init/go.mod | 12 +- image/git-init/go.sum | 24 +-- image/git-init/main.go | 26 +-- .../vendor/golang.org/x/net/http2/frame.go | 11 -- .../vendor/golang.org/x/net/http2/server.go | 5 +- image/git-init/vendor/golang.org/x/oauth2/pkce.go | 4 +- image/git-init/vendor/modules.txt | 22 +-- task/git-clone/README.md | 3 - task/git-clone/git-clone.yaml | 12 +- task/git-clone/tests/run.yaml | 19 -- 14 files changed, 55 insertions(+), 373 deletions(-) https://github.com/tektoncd-catalog/git-clone/compare/688f02aa76d36c52470ee8e9e1e111d170f529ff..81a5a95626ca87305d349d6fdd0cef3c2dd786b0 --- head | 2 +- upstream/.github/workflows/build.yaml | 4 +- upstream/.github/workflows/release.yaml | 10 +- upstream/image/git-init/git/git.go | 76 ++++++- upstream/image/git-init/git/git_test.go | 200 +++++++++++++++++- upstream/image/git-init/go.mod | 12 +- upstream/image/git-init/go.sum | 24 +-- upstream/image/git-init/main.go | 26 ++- .../vendor/golang.org/x/net/http2/frame.go | 11 + .../vendor/golang.org/x/net/http2/server.go | 5 +- .../vendor/golang.org/x/oauth2/pkce.go | 4 +- upstream/image/git-init/vendor/modules.txt | 22 +- upstream/task/git-clone/README.md | 3 + upstream/task/git-clone/git-clone.yaml | 12 +- upstream/task/git-clone/tests/run.yaml | 19 ++ 15 files changed, 374 insertions(+), 56 deletions(-) diff --git a/head b/head index f68c9e8a..b82fad80 100644 --- a/head +++ b/head @@ -1 +1 @@ -81a5a95626ca87305d349d6fdd0cef3c2dd786b0 +688f02aa76d36c52470ee8e9e1e111d170f529ff diff --git a/upstream/.github/workflows/build.yaml b/upstream/.github/workflows/build.yaml index 41028a95..2d580b45 100644 --- a/upstream/.github/workflows/build.yaml +++ b/upstream/.github/workflows/build.yaml @@ -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" diff --git a/upstream/.github/workflows/release.yaml b/upstream/.github/workflows/release.yaml index 0d14fe58..07caff27 100644 --- a/upstream/.github/workflows/release.yaml +++ b/upstream/.github/workflows/release.yaml @@ -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 diff --git a/upstream/image/git-init/git/git.go b/upstream/image/git-init/git/git.go index 46741f2d..a75cc3c2 100644 --- a/upstream/image/git-init/git/git.go +++ b/upstream/image/git-init/git/git.go @@ -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" @@ -64,6 +67,7 @@ type FetchSpec struct { Path string Depth uint Submodules bool + SubmodulePaths []string SSLVerify bool HTTPProxy string HTTPSProxy string @@ -71,8 +75,15 @@ type FetchSpec struct { 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) @@ -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 @@ -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 } } @@ -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) @@ -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 + } +} diff --git a/upstream/image/git-init/git/git_test.go b/upstream/image/git-init/git/git_test.go index f9433a95..c0568dd9 100644 --- a/upstream/image/git-init/git/git_test.go +++ b/upstream/image/git-init/git/git_test.go @@ -17,10 +17,12 @@ package git import ( "bufio" + "fmt" "os" "path/filepath" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" "go.uber.org/zap" @@ -327,6 +329,38 @@ func TestFetch(t *testing.T) { NOProxy: "", SparseCheckoutDirectories: "", }, + }, { + name: "test-clone-with-submodules-empty-paths", + logMessage: "updated submodules", + wantErr: false, + spec: FetchSpec{ + URL: "", + Revision: "", + Refspec: "", + Path: "", + Depth: 0, + Submodules: true, + SubmodulePaths: []string{}, + HTTPProxy: "", + HTTPSProxy: "", + NOProxy: "", + }, + }, { + name: "test-clone-with-submodules-defined-paths", + logMessage: "updated submodules", + wantErr: false, + spec: FetchSpec{ + URL: "", + Revision: "", + Refspec: "", + Path: "", + Depth: 0, + Submodules: true, + SubmodulePaths: []string{"test_submod"}, + HTTPProxy: "", + HTTPSProxy: "", + NOProxy: "", + }, }, } for _, tt := range tests { @@ -340,19 +374,30 @@ func TestFetch(t *testing.T) { logger := zap.New(observer).Sugar() submodPath := "" + submodName := "default" if tt.spec.Submodules { - submodPath := t.TempDir() - createTempGit(t, logger, submodPath, "") + submodPath = t.TempDir() + createTempGit(t, logger, submodPath, "", "") + } + + if len(tt.spec.SubmodulePaths) > 0 { + // test submodule path, replace template value + submodName = tt.spec.SubmodulePaths[0] } gitDir := t.TempDir() - createTempGit(t, logger, gitDir, submodPath) + createTempGit(t, logger, gitDir, submodPath, submodName) tt.spec.URL = gitDir targetPath := t.TempDir() tt.spec.Path = targetPath - if err := Fetch(logger, tt.spec); (err != nil) != tt.wantErr { + if err := Fetch(logger, tt.spec, RetryConfig{ + Initial: 1 * time.Second, + Max: 10 * time.Second, + Factor: 2.0, + MaxAttempts: 3, + }); (err != nil) != tt.wantErr { t.Errorf("Fetch() error = %v, wantErr %v", err, tt.wantErr) } @@ -376,9 +421,9 @@ func TestFetch(t *testing.T) { t.Errorf("directory patterns and sparse-checkout patterns do not match") } } - logLine := 0 + logLine := 1 if tt.spec.Submodules { - logLine = 1 + logLine = 3 } checkLogMessage(t, tt.logMessage, log, logLine) }) @@ -386,7 +431,7 @@ func TestFetch(t *testing.T) { } // Create a temporary Git dir locally for testing against instead of using a potentially flaky remote URL. -func createTempGit(t *testing.T, logger *zap.SugaredLogger, gitDir string, submodPath string) { +func createTempGit(t *testing.T, logger *zap.SugaredLogger, gitDir string, submodPath string, submodName string) { t.Helper() if _, err := run(logger, "", "init", gitDir); err != nil { t.Fatal(err) @@ -413,7 +458,25 @@ func createTempGit(t *testing.T, logger *zap.SugaredLogger, gitDir string, submo } if submodPath != "" { - if _, err := run(logger, "", "submodule", "add", submodPath); err != nil { + // file protocol is necessary to clone submodules since the fixture is only written to the filesystem + if _, err := run(logger, "", "config", "--global", "protocol.file.allow", "always"); err != nil { + t.Fatal(err) + } + + if submodName != "" { + if _, err := run(logger, "", "submodule", "add", submodPath, submodName); err != nil { + t.Fatal(err.Error()) + } + } else { + if _, err := run(logger, "", "submodule", "add", submodPath); err != nil { + t.Fatal(err.Error()) + } + } + + if _, err := run(logger, "", "add", "."); err != nil { + t.Fatal(err.Error()) + } + if _, err := run(logger, "", "commit", "-m", "Add submodule"); err != nil { t.Fatal(err.Error()) } } @@ -433,3 +496,124 @@ func checkLogMessage(t *testing.T, logMessage string, log *observer.ObservedLogs t.Errorf("log message: '%s'\n should contain: '%s'", logMessage, gotmsg) } } + +type SucceedAfter struct { + try int + callCount int +} + +func (f *SucceedAfter) Run() (string, error) { + f.callCount++ + if f.callCount > f.try { + return "success", nil + } + return "", fmt.Errorf("temporary error") +} + +func TestRetryWithBackoff(t *testing.T) { + withTemporaryGitConfig(t) + tests := []struct { + name string + operation func() (string, error) + initial time.Duration + max time.Duration + factor float64 + maxAttempts int + expectedResult string + expectedError bool + expectedMin time.Duration + expectedMax time.Duration + }{ + { + name: "successful operation on first attempt", + operation: (&SucceedAfter{try: 0}).Run, + initial: 100 * time.Millisecond, + max: 1 * time.Second, + factor: 2.0, + maxAttempts: 3, + expectedResult: "success", + expectedError: false, + expectedMin: 0, + expectedMax: 50 * time.Millisecond, + }, + { + name: "successful operation on second attempt", + operation: (&SucceedAfter{try: 1}).Run, + initial: 100 * time.Millisecond, + max: 1 * time.Second, + factor: 2.0, + maxAttempts: 3, + expectedResult: "success", + expectedError: false, + expectedMin: 100 * time.Millisecond, + expectedMax: 200 * time.Millisecond, + }, + { + name: "operation fails after max attempts", + operation: (&SucceedAfter{try: 10}).Run, + initial: 100 * time.Millisecond, + max: 1 * time.Second, + factor: 2.0, + maxAttempts: 2, + expectedResult: "", + expectedError: true, + expectedMin: 100 * time.Millisecond, + expectedMax: 200 * time.Millisecond, + }, + { + name: "operation fails and max backoff is reached", + operation: (&SucceedAfter{try: 10}).Run, + initial: 100 * time.Millisecond, + max: 1 * time.Millisecond, + factor: 2.0, + maxAttempts: 3, + expectedResult: "", + expectedError: true, + expectedMin: 2 * time.Millisecond, + expectedMax: 4 * time.Millisecond, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + observer, log := observer.New(zap.InfoLevel) + logger := zap.New(observer).Sugar() + + result, waitTime, err := retryWithBackoff( + tt.operation, + tt.initial, + tt.max, + tt.factor, + tt.maxAttempts, + logger, + ) + + if tt.expectedError { + if err == nil { + t.Errorf("Expected error but got none") + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if result != tt.expectedResult { + t.Errorf("Expected result %q, got %q", tt.expectedResult, result) + } + } + + // Verify that retry attempts were logged + logLines := log.All() + if len(logLines) == 0 { + t.Error("Expected retry logs but got none") + } + + // Assert expected duration + if waitTime < tt.expectedMin { + t.Errorf("Expected duration >= %v, got %v", tt.expectedMin, waitTime) + } + if waitTime > tt.expectedMax { + t.Errorf("Expected duration <= %v, got %v", tt.expectedMax, waitTime) + } + }) + } +} diff --git a/upstream/image/git-init/go.mod b/upstream/image/git-init/go.mod index 918df2b7..f3b06988 100644 --- a/upstream/image/git-init/go.mod +++ b/upstream/image/git-init/go.mod @@ -54,12 +54,12 @@ require ( go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect - golang.org/x/net v0.36.0 // indirect - golang.org/x/oauth2 v0.26.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.9.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.217.0 // indirect diff --git a/upstream/image/git-init/go.sum b/upstream/image/git-init/go.sum index e790e1b5..020af110 100644 --- a/upstream/image/git-init/go.sum +++ b/upstream/image/git-init/go.sum @@ -424,8 +424,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -433,8 +433,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -446,8 +446,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -489,12 +489,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -502,8 +502,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/upstream/image/git-init/main.go b/upstream/image/git-init/main.go index 0af2d9c9..63f9ae20 100644 --- a/upstream/image/git-init/main.go +++ b/upstream/image/git-init/main.go @@ -16,7 +16,11 @@ limitations under the License. package main import ( + "encoding/csv" "flag" + "fmt" + "strings" + "time" "github.com/tektoncd-catalog/git-clone/git-init/git" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" @@ -26,6 +30,7 @@ import ( var ( fetchSpec git.FetchSpec + retryConfig git.RetryConfig terminationMessagePath string ) @@ -36,9 +41,28 @@ func init() { flag.StringVar(&fetchSpec.Path, "path", "", "Path of directory under which Git repository will be copied") flag.BoolVar(&fetchSpec.SSLVerify, "sslVerify", true, "Enable/Disable SSL verification in the git config") flag.BoolVar(&fetchSpec.Submodules, "submodules", true, "Initialize and fetch Git submodules") + flag.Func( + "submodulePaths", + "Comma-separated list of submodule paths to be used in git submodule update command. Flag submodules must be set to true to make this parameter applicable.", + func(csvVal string) error { + if csvVal != "" { + reader := csv.NewReader(strings.NewReader(csvVal)) + paths, err := reader.Read() + if err != nil { + return fmt.Errorf("error parsing submodulePaths: %s", err) + } + fetchSpec.SubmodulePaths = paths + } + return nil + }, + ) flag.UintVar(&fetchSpec.Depth, "depth", 1, "Perform a shallow clone to this depth") flag.StringVar(&terminationMessagePath, "terminationMessagePath", "/tekton/termination", "Location of file containing termination message") flag.StringVar(&fetchSpec.SparseCheckoutDirectories, "sparseCheckoutDirectories", "", "String of directory patterns separated by a comma") + flag.DurationVar(&retryConfig.Initial, "retryInitial", 1*time.Second, "Initial retry duration for fetch operations") + flag.DurationVar(&retryConfig.Max, "retryMax", 10*time.Second, "Maximum retry duration for fetch operations") + flag.Float64Var(&retryConfig.Factor, "retryFactor", 2.0, "Retry factor for fetch operations") + flag.IntVar(&retryConfig.MaxAttempts, "retryMaxAttempts", 1, "Maximum number of retry attempts for fetch operations") } func main() { @@ -49,7 +73,7 @@ func main() { _ = logger.Sync() }() - if err := git.Fetch(logger, fetchSpec); err != nil { + if err := git.Fetch(logger, fetchSpec, retryConfig); err != nil { logger.Fatalf("Error fetching git repository: %s", err) } diff --git a/upstream/image/git-init/vendor/golang.org/x/net/http2/frame.go b/upstream/image/git-init/vendor/golang.org/x/net/http2/frame.go index 81faec7e..97bd8b06 100644 --- a/upstream/image/git-init/vendor/golang.org/x/net/http2/frame.go +++ b/upstream/image/git-init/vendor/golang.org/x/net/http2/frame.go @@ -225,6 +225,11 @@ var fhBytes = sync.Pool{ }, } +func invalidHTTP1LookingFrameHeader() FrameHeader { + fh, _ := readFrameHeader(make([]byte, frameHeaderLen), strings.NewReader("HTTP/1.1 ")) + return fh +} + // ReadFrameHeader reads 9 bytes from r and returns a FrameHeader. // Most users should use Framer.ReadFrame instead. func ReadFrameHeader(r io.Reader) (FrameHeader, error) { @@ -503,10 +508,16 @@ func (fr *Framer) ReadFrame() (Frame, error) { return nil, err } if fh.Length > fr.maxReadSize { + if fh == invalidHTTP1LookingFrameHeader() { + return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", err) + } return nil, ErrFrameTooLarge } payload := fr.getReadBuf(fh.Length) if _, err := io.ReadFull(fr.r, payload); err != nil { + if fh == invalidHTTP1LookingFrameHeader() { + return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", err) + } return nil, err } f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload) diff --git a/upstream/image/git-init/vendor/golang.org/x/net/http2/server.go b/upstream/image/git-init/vendor/golang.org/x/net/http2/server.go index b640deb0..51fca38f 100644 --- a/upstream/image/git-init/vendor/golang.org/x/net/http2/server.go +++ b/upstream/image/git-init/vendor/golang.org/x/net/http2/server.go @@ -1068,7 +1068,10 @@ func (sc *serverConn) serve(conf http2Config) { func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) { if sc.pingSent { - sc.vlogf("timeout waiting for PING response") + sc.logf("timeout waiting for PING response") + if f := sc.countErrorFunc; f != nil { + f("conn_close_lost_ping") + } sc.conn.Close() return } diff --git a/upstream/image/git-init/vendor/golang.org/x/oauth2/pkce.go b/upstream/image/git-init/vendor/golang.org/x/oauth2/pkce.go index 50593b6d..6a95da97 100644 --- a/upstream/image/git-init/vendor/golang.org/x/oauth2/pkce.go +++ b/upstream/image/git-init/vendor/golang.org/x/oauth2/pkce.go @@ -21,7 +21,7 @@ const ( // // A fresh verifier should be generated for each authorization. // S256ChallengeOption(verifier) should then be passed to Config.AuthCodeURL -// (or Config.DeviceAccess) and VerifierOption(verifier) to Config.Exchange +// (or Config.DeviceAuth) and VerifierOption(verifier) to Config.Exchange // (or Config.DeviceAccessToken). func GenerateVerifier() string { // "RECOMMENDED that the output of a suitable random number generator be @@ -51,7 +51,7 @@ func S256ChallengeFromVerifier(verifier string) string { } // S256ChallengeOption derives a PKCE code challenge derived from verifier with -// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAccess +// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAuth // only. func S256ChallengeOption(verifier string) AuthCodeOption { return challengeOption{ diff --git a/upstream/image/git-init/vendor/modules.txt b/upstream/image/git-init/vendor/modules.txt index 58514760..89e4fce4 100644 --- a/upstream/image/git-init/vendor/modules.txt +++ b/upstream/image/git-init/vendor/modules.txt @@ -239,7 +239,7 @@ go.uber.org/zap/zaptest/observer ## explicit; go 1.20 golang.org/x/exp/constraints golang.org/x/exp/slices -# golang.org/x/net v0.36.0 +# golang.org/x/net v0.38.0 ## explicit; go 1.23.0 golang.org/x/net/http/httpguts golang.org/x/net/http2 @@ -248,23 +248,23 @@ golang.org/x/net/idna golang.org/x/net/internal/httpcommon golang.org/x/net/internal/timeseries golang.org/x/net/trace -# golang.org/x/oauth2 v0.26.0 -## explicit; go 1.18 +# golang.org/x/oauth2 v0.27.0 +## explicit; go 1.23.0 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sync v0.11.0 -## explicit; go 1.18 +# golang.org/x/sync v0.12.0 +## explicit; go 1.23.0 golang.org/x/sync/semaphore -# golang.org/x/sys v0.30.0 -## explicit; go 1.18 +# golang.org/x/sys v0.31.0 +## explicit; go 1.23.0 golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.29.0 -## explicit; go 1.18 +# golang.org/x/term v0.30.0 +## explicit; go 1.23.0 golang.org/x/term -# golang.org/x/text v0.22.0 -## explicit; go 1.18 +# golang.org/x/text v0.23.0 +## explicit; go 1.23.0 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi diff --git a/upstream/task/git-clone/README.md b/upstream/task/git-clone/README.md index 408f00a6..1d6c1387 100644 --- a/upstream/task/git-clone/README.md +++ b/upstream/task/git-clone/README.md @@ -91,6 +91,9 @@ spec: * **revision**: Revision to checkout. (branch, tag, sha, ref, etc...) (_default_: "") * **refspec**: Refspec to fetch before checking out revision. (_default_:"") * **submodules**: Initialize and fetch git submodules. (_default_: true) +* **submodulePaths**: Comma-separated list of specific submodule paths to initialize and fetch. + Only submodules in the specified directories and their subdirectories will be fetched. + Empty string fetches all submodules. Parameter `submodules` must be set to `true` to make this parameter applicable. (_default_:"") * **depth**: Perform a shallow clone, fetching only the most recent N commits. (_default_: 1) * **sslVerify**: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote. (_default_: true) * **crtFileName**: If `sslVerify` is **true** and `ssl-ca-directory` workspace is given then set `crtFileName` if mounted file name is different than `ca-bundle.crt`. (_default_: "ca-bundle.crt") diff --git a/upstream/task/git-clone/git-clone.yaml b/upstream/task/git-clone/git-clone.yaml index aba46608..d964b879 100644 --- a/upstream/task/git-clone/git-clone.yaml +++ b/upstream/task/git-clone/git-clone.yaml @@ -59,6 +59,12 @@ spec: description: Initialize and fetch git submodules. type: string default: "true" + - name: submodulePaths + description: | + Comma-separated list of specific submodule paths to initialize and fetch. Only submodules in the specified directories and their subdirectories will be fetched. + Empty string fetches all submodules. Parameter "submodules" must be set to "true" to make this parameter applicable. + type: string + default: "" - name: depth description: Perform a shallow clone, fetching only the most recent N commits. type: string @@ -129,6 +135,8 @@ spec: value: $(params.refspec) - name: PARAM_SUBMODULES value: $(params.submodules) + - name: PARAM_SUBMODULE_PATHS + value: $(params.submodulePaths) - name: PARAM_DEPTH value: $(params.depth) - name: PARAM_SSL_VERIFY @@ -221,6 +229,7 @@ spec: test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}" git config --global --add safe.directory "${WORKSPACE_OUTPUT_PATH}" + /ko-app/git-init \ -url="${PARAM_URL}" \ -revision="${PARAM_REVISION}" \ @@ -229,7 +238,8 @@ spec: -sslVerify="${PARAM_SSL_VERIFY}" \ -submodules="${PARAM_SUBMODULES}" \ -depth="${PARAM_DEPTH}" \ - -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}" + -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}" \ + -submodulePaths="${PARAM_SUBMODULE_PATHS}" cd "${CHECKOUT_DIR}" RESULT_SHA="$(git rev-parse HEAD)" EXIT_CODE="$?" diff --git a/upstream/task/git-clone/tests/run.yaml b/upstream/task/git-clone/tests/run.yaml index 18b688db..d5c59970 100644 --- a/upstream/task/git-clone/tests/run.yaml +++ b/upstream/task/git-clone/tests/run.yaml @@ -56,6 +56,25 @@ spec: --- apiVersion: tekton.dev/v1beta1 kind: TaskRun +metadata: + name: git-clone-run-submodules-with-paths +spec: + workspaces: + - name: output + emptyDir: {} + taskRef: + name: git-clone + podTemplate: + securityContext: + fsGroup: 65532 + params: + - name: url + value: https://github.com/githubtraining/example-dependency + - name: submodulePaths + value: "js" +--- +apiVersion: tekton.dev/v1beta1 +kind: TaskRun metadata: name: git-clone-run-no-depth-2 spec: