Skip to content

Commit 34df9d2

Browse files
ilya-lesikovalexey-igrychev
authored andcommitted
feat(dev-mode): less rebuilds due to better cache handling
Single persistent dev-mode service branch instead of multiple. This branch now constantly merges user working branch in itself, which allows for better utilization of cached stages and less rebuilds. `--dev-branch-prefix` flag replaced with `--dev-branch` flag. Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
1 parent 3a87b24 commit 34df9d2

File tree

4 files changed

+65
-52
lines changed

4 files changed

+65
-52
lines changed

cmd/werf/common/common.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ type CmdData struct {
9393
LooseGiterminism *bool
9494
Dev *bool
9595
DevIgnore *[]string
96-
DevBranchPrefix *string
96+
DevBranch *string
9797

9898
IntrospectBeforeError *bool
9999
IntrospectAfterError *bool
@@ -178,7 +178,7 @@ func SetupGiterminismOptions(cmdData *CmdData, cmd *cobra.Command) {
178178
setupLooseGiterminism(cmdData, cmd)
179179
setupDev(cmdData, cmd)
180180
setupDevIgnore(cmdData, cmd)
181-
setupDevBranchPrefix(cmdData, cmd)
181+
setupDevBranch(cmdData, cmd)
182182
}
183183

184184
func setupLooseGiterminism(cmdData *CmdData, cmd *cobra.Command) {
@@ -198,16 +198,16 @@ func setupDevIgnore(cmdData *CmdData, cmd *cobra.Command) {
198198
Also, can be specified with $WERF_DEV_IGNORE_* (e.g. $WERF_DEV_IGNORE_TESTS=*_test.go, $WERF_DEV_IGNORE_DOCS=path/to/docs)`)
199199
}
200200

201-
func setupDevBranchPrefix(cmdData *CmdData, cmd *cobra.Command) {
202-
cmdData.DevBranchPrefix = new(string)
201+
func setupDevBranch(cmdData *CmdData, cmd *cobra.Command) {
202+
cmdData.DevBranch = new(string)
203203

204-
defaultValue := "werf-dev-"
205-
envValue := os.Getenv("WERF_DEV_BRANCH_PREFIX")
204+
defaultValue := "_werf-dev"
205+
envValue := os.Getenv("WERF_DEV_BRANCH")
206206
if envValue != "" {
207207
defaultValue = envValue
208208
}
209209

210-
cmd.Flags().StringVarP(cmdData.DevBranchPrefix, "dev-branch-prefix", "", defaultValue, `Set dev git branch prefix (default $WERF_DEV_BRANCH_PREFIX or werf-dev-)`)
210+
cmd.Flags().StringVarP(cmdData.DevBranch, "dev-branch", "", defaultValue, fmt.Sprintf("Set dev git branch name (default $WERF_DEV_BRANCH or %q)", defaultValue))
211211
}
212212

213213
func SetupHomeDir(cmdData *CmdData, cmd *cobra.Command) {
@@ -1179,7 +1179,7 @@ func GetGiterminismManager(ctx context.Context, cmdData *CmdData) (giterminism_m
11791179
var openLocalRepoOptions git_repo.OpenLocalRepoOptions
11801180
if *cmdData.Dev {
11811181
openLocalRepoOptions.WithServiceHeadCommit = true
1182-
openLocalRepoOptions.ServiceBranchOptions.Prefix = *cmdData.DevBranchPrefix
1182+
openLocalRepoOptions.ServiceBranchOptions.Name = *cmdData.DevBranch
11831183
openLocalRepoOptions.ServiceBranchOptions.GlobExcludeList = GetDevIgnore(cmdData)
11841184
}
11851185

pkg/git_repo/local.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type OpenLocalRepoOptions struct {
4040
}
4141

4242
type ServiceBranchOptions struct {
43-
Prefix string
43+
Name string
4444
GlobExcludeList []string
4545
}
4646

@@ -71,29 +71,22 @@ func OpenLocalRepo(ctx context.Context, name, workTreeDir string, opts OpenLocal
7171
defer werf.ReleaseHostLock(lock)
7272
}
7373

74-
gitStatusResult, err := l.status(ctx)
74+
devHeadCommit, err := true_git.SyncSourceWorktreeWithServiceBranch(
75+
context.Background(),
76+
l.GitDir,
77+
l.WorkTreeDir,
78+
l.getRepoWorkTreeCacheDir(l.getRepoID()),
79+
l.headCommitHash,
80+
true_git.SyncSourceWorktreeWithServiceBranchOptions{
81+
ServiceBranch: opts.ServiceBranchOptions.Name,
82+
GlobExcludeList: opts.ServiceBranchOptions.GlobExcludeList,
83+
},
84+
)
7585
if err != nil {
76-
return nil, fmt.Errorf("unable to get git status: %s", err)
86+
return l, err
7787
}
7888

79-
if len(gitStatusResult.PathListWithSubmodules()) != 0 {
80-
devHeadCommit, err := true_git.SyncSourceWorktreeWithServiceBranch(
81-
context.Background(),
82-
l.GitDir,
83-
l.WorkTreeDir,
84-
l.getRepoWorkTreeCacheDir(l.getRepoID()),
85-
l.headCommitHash,
86-
true_git.SyncSourceWorktreeWithServiceBranchOptions{
87-
ServiceBranchPrefix: opts.ServiceBranchOptions.Prefix,
88-
GlobExcludeList: opts.ServiceBranchOptions.GlobExcludeList,
89-
},
90-
)
91-
if err != nil {
92-
return l, err
93-
}
94-
95-
l.headCommitHash = devHeadCommit
96-
}
89+
l.headCommitHash = devHeadCommit
9790
}
9891

9992
return l, nil

pkg/true_git/repository.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ func Fetch(ctx context.Context, path string, options FetchOptions) error {
5757
return gitCmd.Run(ctx)
5858
}
5959

60+
func GetLastBranchCommitSHA(ctx context.Context, repoPath, branch string) (string, error) {
61+
revParseCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: repoPath}, "rev-parse", branch)
62+
if err := revParseCmd.Run(ctx); err != nil {
63+
return "", fmt.Errorf("git rev parse branch command failed: %s", err)
64+
}
65+
66+
return strings.TrimSpace(revParseCmd.OutBuf.String()), nil
67+
}
68+
6069
func IsShallowClone(ctx context.Context, path string) (bool, error) {
6170
if gitVersion.LessThan(semver.MustParse("2.15.0")) {
6271
exist, err := util.FileExists(filepath.Join(path, ".git", "shallow"))

pkg/true_git/service_branch.go

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
)
1414

1515
type SyncSourceWorktreeWithServiceBranchOptions struct {
16-
ServiceBranchPrefix string
17-
GlobExcludeList []string
16+
ServiceBranch string
17+
GlobExcludeList []string
1818
}
1919

2020
func SyncSourceWorktreeWithServiceBranch(ctx context.Context, gitDir, sourceWorktreeDir, worktreeCacheDir, commit string, opts SyncSourceWorktreeWithServiceBranchOptions) (string, error) {
@@ -39,10 +39,9 @@ func SyncSourceWorktreeWithServiceBranch(ctx context.Context, gitDir, sourceWork
3939
return fmt.Errorf("unable to remove %s: %s", currentCommitPath, err)
4040
}
4141

42-
branchName := fmt.Sprintf("%s%s", opts.ServiceBranchPrefix, commit)
43-
resultCommit, err = syncWorktreeWithServiceWorktreeBranch(ctx, sourceWorktreeDir, serviceWorktreeDir, commit, branchName, opts.GlobExcludeList)
42+
resultCommit, err = syncWorktreeWithServiceWorktreeBranch(ctx, sourceWorktreeDir, serviceWorktreeDir, commit, opts.ServiceBranch, opts.GlobExcludeList)
4443
if err != nil {
45-
return fmt.Errorf("unable to sync worktree with service branch %q: %s", branchName, err)
44+
return fmt.Errorf("unable to sync worktree with service branch %q: %s", opts.ServiceBranch, err)
4645
}
4746

4847
return nil
@@ -54,14 +53,13 @@ func SyncSourceWorktreeWithServiceBranch(ctx context.Context, gitDir, sourceWork
5453
}
5554

5655
func syncWorktreeWithServiceWorktreeBranch(ctx context.Context, sourceWorktreeDir, serviceWorktreeDir, sourceCommit, branchName string, globExcludeList []string) (string, error) {
57-
serviceBranchHeadCommit, err := getOrPrepareServiceBranchHeadCommit(ctx, serviceWorktreeDir, sourceCommit, branchName)
58-
if err != nil {
56+
if err := prepareAndCheckoutServiceBranch(ctx, serviceWorktreeDir, sourceCommit, branchName); err != nil {
5957
return "", fmt.Errorf("unable to get or prepare service branch head commit: %s", err)
6058
}
6159

62-
checkoutCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir}, "checkout", branchName)
63-
if err = checkoutCmd.Run(ctx); err != nil {
64-
return "", fmt.Errorf("git checkout command failed: %s", err)
60+
serviceBranchHeadCommit, err := GetLastBranchCommitSHA(ctx, serviceWorktreeDir, branchName)
61+
if err != nil {
62+
return "", fmt.Errorf("unable to get service worktree commit SHA: %s", err)
6563
}
6664

6765
revertedChangesExist, err := revertExcludedChangesInServiceWorktreeIndex(ctx, sourceWorktreeDir, serviceWorktreeDir, sourceCommit, serviceBranchHeadCommit, globExcludeList)
@@ -90,31 +88,44 @@ func syncWorktreeWithServiceWorktreeBranch(ctx context.Context, sourceWorktreeDi
9088
return newCommit, nil
9189
}
9290

93-
func getOrPrepareServiceBranchHeadCommit(ctx context.Context, serviceWorktreeDir string, sourceCommit string, branchName string) (string, error) {
91+
func prepareAndCheckoutServiceBranch(ctx context.Context, serviceWorktreeDir string, sourceCommit string, branchName string) error {
9492
branchListCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir}, "branch", "--list", branchName)
9593
if err := branchListCmd.Run(ctx); err != nil {
96-
return "", fmt.Errorf("git branch list command failed: %s", err)
94+
return fmt.Errorf("git branch list command failed: %s", err)
9795
}
9896

99-
var isServiceBranchExist bool
100-
isServiceBranchExist = branchListCmd.OutBuf.Len() != 0
101-
102-
if !isServiceBranchExist {
97+
if branchListCmd.OutBuf.Len() == 0 {
10398
checkoutCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir}, "checkout", "-b", branchName, sourceCommit)
10499
if err := checkoutCmd.Run(ctx); err != nil {
105-
return "", fmt.Errorf("git checkout command failed: %s", err)
100+
return fmt.Errorf("git checkout command failed: %s", err)
106101
}
107102

108-
return sourceCommit, nil
103+
return nil
109104
}
110105

111-
revParseCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir}, "rev-parse", branchName)
112-
if err := revParseCmd.Run(ctx); err != nil {
113-
return "", fmt.Errorf("git rev parse branch command failed: %s", err)
106+
checkoutCmd := NewGitCmd(ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir}, "checkout", branchName)
107+
if err := checkoutCmd.Run(ctx); err != nil {
108+
return fmt.Errorf("git checkout command failed: %s", err)
109+
}
110+
111+
isSourceCommitInServiceBranch, err := IsAncestor(ctx, sourceCommit, branchName, serviceWorktreeDir)
112+
if err != nil {
113+
return fmt.Errorf("unable to detect whether sourceCommit %q is in service branch: %s", sourceCommit, err)
114+
}
115+
if isSourceCommitInServiceBranch {
116+
return nil
117+
}
118+
119+
mergeCmd := NewGitCmd(
120+
ctx, &GitCmdOptions{RepoDir: serviceWorktreeDir},
121+
"-c", "user.email=werf@werf.io", "-c", "user.name=werf",
122+
"merge", "--no-edit", "--no-ff", "--allow-unrelated-histories", "-s", "recursive", "-X", "theirs", sourceCommit,
123+
)
124+
if err = mergeCmd.Run(ctx); err != nil {
125+
return fmt.Errorf("git merge of source commit %q into service branch failed: %s", sourceCommit, err)
114126
}
115127

116-
serviceBranchHeadCommit := strings.TrimSpace(revParseCmd.OutBuf.String())
117-
return serviceBranchHeadCommit, nil
128+
return nil
118129
}
119130

120131
func revertExcludedChangesInServiceWorktreeIndex(ctx context.Context, sourceWorktreeDir string, serviceWorktreeDir string, sourceCommit string, serviceBranchHeadCommit string, globExcludeList []string) (bool, error) {

0 commit comments

Comments
 (0)