mirror of
https://github.com/moby/buildkit.git
synced 2026-08-04 23:00:51 +00:00
git: fix possible conflict on mutated branches
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
@@ -500,8 +500,8 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (cach
|
||||
ref, err := gs.trySnapshot(ctx, g, false)
|
||||
if err != nil {
|
||||
var wce *wouldClobberExistingTagError
|
||||
if errors.As(err, &wce) {
|
||||
// try once more with a fresh repo
|
||||
var ulre *unableToUpdateLocalRefError
|
||||
if errors.As(err, &wce) || errors.As(err, &ulre) {
|
||||
ref, err = gs.trySnapshot(ctx, g, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -581,6 +581,11 @@ func (gs *gitSourceHandler) trySnapshot(ctx context.Context, g session.Group, re
|
||||
// only hope is to abandon the existing shared repo and start a fresh one
|
||||
return nil, &wouldClobberExistingTagError{err}
|
||||
}
|
||||
if strings.Contains(err.Error(), "(unable to update local ref)") && strings.Contains(err.Error(), "some local refs could not be updated;") {
|
||||
// this can happen if a branch updated in remote so that old branch
|
||||
// is now a parent dir of a new branch
|
||||
return nil, &unableToUpdateLocalRefError{err}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@@ -794,6 +799,14 @@ func (e *wouldClobberExistingTagError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
type unableToUpdateLocalRefError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e *unableToUpdateLocalRefError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
func (gs *gitSourceHandler) emptyGitCli(ctx context.Context, g session.Group, opts ...gitutil.Option) (*gitutil.GitCLI, func() error, error) {
|
||||
var cleanups []func() error
|
||||
cleanup := func() error {
|
||||
|
||||
@@ -915,6 +915,89 @@ func testFetchMutatedTag(t *testing.T, format string, keepGitDir bool) {
|
||||
ref.Release(context.TODO())
|
||||
}
|
||||
|
||||
func TestFetchMutatedBranchSHA1(t *testing.T) {
|
||||
testFetchMutatedBranch(t, "sha1", false)
|
||||
}
|
||||
|
||||
func TestFetchMutatedBranchKeepGitDirSHA1(t *testing.T) {
|
||||
testFetchMutatedBranch(t, "sha1", true)
|
||||
}
|
||||
|
||||
func TestFetchMutatedBranchSHA256(t *testing.T) {
|
||||
testFetchMutatedBranch(t, "sha256", false)
|
||||
}
|
||||
|
||||
func TestFetchMutatedBranchKeepGitDirSHA256(t *testing.T) {
|
||||
testFetchMutatedBranch(t, "sha256", true)
|
||||
}
|
||||
|
||||
// testFetchMutatedBranch tests that if a branch is mutated in a way that previous
|
||||
// ref becomes parent directory of new ref, causing collision to existing checkouts
|
||||
func testFetchMutatedBranch(t *testing.T, format string, keepGitDir bool) {
|
||||
ctx := t.Context()
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Depends on unimplemented containerd bind-mount support on Windows")
|
||||
}
|
||||
repo := setupGitRepo(t, format)
|
||||
cmd := exec.Command("git", "rev-parse", "feature")
|
||||
cmd.Dir = repo.mainPath
|
||||
|
||||
out, err := cmd.Output()
|
||||
require.NoError(t, err)
|
||||
|
||||
expLen := 40
|
||||
if format == "sha256" {
|
||||
expLen = 64
|
||||
}
|
||||
shaBranch := strings.TrimSpace(string(out))
|
||||
require.Equal(t, expLen, len(shaBranch))
|
||||
|
||||
id := &GitIdentifier{Remote: repo.mainURL, Ref: "feature", KeepGitDir: keepGitDir}
|
||||
gs := setupGitSource(t, t.TempDir())
|
||||
|
||||
g, err := gs.Resolve(ctx, id, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
key1, pin1, _, done, err := g.CacheKey(ctx, nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.True(t, done)
|
||||
|
||||
ref, err := g.Snapshot(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
ref.Release(context.TODO())
|
||||
|
||||
// mutate the branch to point to become parent dir
|
||||
cmd = exec.Command("git", "branch", "-D", "feature")
|
||||
cmd.Dir = repo.mainPath
|
||||
out, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
cmd = exec.Command("git", "branch", "feature/new", shaBranch)
|
||||
cmd.Dir = repo.mainPath
|
||||
out, err = cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(out))
|
||||
|
||||
id = &GitIdentifier{Remote: repo.mainURL, Ref: "feature/new", KeepGitDir: keepGitDir}
|
||||
|
||||
g, err = gs.Resolve(ctx, id, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
key2, pin2, _, done, err := g.CacheKey(ctx, nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.True(t, done)
|
||||
|
||||
if keepGitDir {
|
||||
require.NotEqual(t, key1, key2) // key contains new ref
|
||||
} else {
|
||||
require.Equal(t, key1, key2)
|
||||
}
|
||||
require.Equal(t, pin1, pin2)
|
||||
|
||||
ref, err = g.Snapshot(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
ref.Release(context.TODO())
|
||||
}
|
||||
|
||||
func TestMultipleTagAccessKeepGitDirSHA1(t *testing.T) {
|
||||
testMultipleTagAccess(t, true, "sha1")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user