From 91a829b341fe3da2064f8e3e25d3394783089c2e Mon Sep 17 00:00:00 2001 From: Timofey Kirillov Date: Thu, 23 Jun 2022 16:53:28 +0300 Subject: [PATCH] fix(submodules): auto handle "commits not present" patch creation error When "commits not present" error occurs during patch creation between FROM and TO commits, then reset service git worktree to the FROM commit (which in turn fetches lost submodule commit) and retry patch creation procedure. Signed-off-by: Timofey Kirillov --- pkg/git_repo/base.go | 24 ++++++++++++++++++++++++ pkg/true_git/diff_parser.go | 9 ++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pkg/git_repo/base.go b/pkg/git_repo/base.go index 04204e3216..df85eb8fa4 100644 --- a/pkg/git_repo/base.go +++ b/pkg/git_repo/base.go @@ -225,7 +225,31 @@ func (repo *Base) createPatch(ctx context.Context, repoPath, gitDir, repoID, wor var desc *true_git.PatchDescriptor if hasSubmodules { + var retryCount int + + TryCreatePatch: desc, err = true_git.PatchWithSubmodules(ctx, fileHandler, gitDir, workTreeCacheDir, true_git.PatchOptions(opts)) + + if true_git.IsCommitsNotPresentError(err) && retryCount == 0 { + logboek.Context(ctx).Default().LogF("Detected not present commits when creating patch: %s\n", err) + logboek.Context(ctx).Default().LogF("Will switch worktree to original commit %q and retry\n", opts.FromCommit) + + if err := fileHandler.Truncate(0); err != nil { + return nil, fmt.Errorf("unable to truncate file %s: %w", tmpFile, err) + } + if _, err := fileHandler.Seek(0, 0); err != nil { + return nil, fmt.Errorf("unable to reset file %s: %w", tmpFile, err) + } + + if err := true_git.WithWorkTree(ctx, gitDir, workTreeCacheDir, opts.FromCommit, true_git.WithWorkTreeOptions{HasSubmodules: true}, func(workTreeDir string) error { + return nil + }); err != nil { + return nil, fmt.Errorf("unable to switch worktree to commit %q: %w", opts.FromCommit, err) + } + + retryCount++ + goto TryCreatePatch + } } else { desc, err = true_git.Patch(ctx, fileHandler, gitDir, true_git.PatchOptions(opts)) } diff --git a/pkg/true_git/diff_parser.go b/pkg/true_git/diff_parser.go index fdbdf9ab77..eba2b0a869 100644 --- a/pkg/true_git/diff_parser.go +++ b/pkg/true_git/diff_parser.go @@ -2,6 +2,7 @@ package true_git import ( "bytes" + "errors" "fmt" "io" "os" @@ -13,6 +14,12 @@ import ( "github.com/werf/werf/pkg/util" ) +var ErrCommitsNotPresent = errors.New("commits not present") + +func IsCommitsNotPresentError(err error) bool { + return err != nil && strings.HasSuffix(err.Error(), ErrCommitsNotPresent.Error()) +} + func makeDiffParser(out io.Writer, pathScope string, pathMatcher path_matcher.PathMatcher, fileRenames map[string]string) *diffParser { return &diffParser{ PathScope: pathScope, @@ -379,7 +386,7 @@ func (p *diffParser) handleModifyFilePathB(line string) error { func (p *diffParser) handleSubmoduleLine(line string) error { p.state = unrecognized if strings.HasSuffix(line, " (commits not present)") { - return fmt.Errorf("cannot handle \"commits not present\" in git diff line %q, check specified submodule commits are correct", line) + return fmt.Errorf("cannot handle git diff line %q, check specified commits are correct: %w", line, ErrCommitsNotPresent) } return nil }