knotserver: git/merge: separate applyPatch and checkPatch #527

merged
opened by boltless.me targeting master from boltless.me/core: push-skprtmnmwuqn
Changed files
+62 -60
knotserver
git
+62 -60
knotserver/git/merge.go
··· 143 return tmpDir, nil 144 } 145 146 - func (g *GitRepo) applyPatch(tmpDir, patchFile string, checkOnly bool, opts *MergeOptions) error { 147 var stderr bytes.Buffer 148 - var cmd *exec.Cmd 149 150 - if checkOnly { 151 - cmd = exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile) 152 - } else { 153 - // if patch is a format-patch, apply using 'git am' 154 - if opts.FormatPatch { 155 - amCmd := exec.Command("git", "-C", tmpDir, "am", patchFile) 156 - amCmd.Stderr = &stderr 157 - if err := amCmd.Run(); err != nil { 158 - return fmt.Errorf("patch application failed: %s", stderr.String()) 159 - } 160 - return nil 161 } 162 163 - // else, apply using 'git apply' and commit it manually 164 - exec.Command("git", "-C", tmpDir, "config", "advice.mergeConflict", "false").Run() 165 - if opts != nil { 166 - applyCmd := exec.Command("git", "-C", tmpDir, "apply", patchFile) 167 - applyCmd.Stderr = &stderr 168 - if err := applyCmd.Run(); err != nil { 169 - return fmt.Errorf("patch application failed: %s", stderr.String()) 170 - } 171 172 - stageCmd := exec.Command("git", "-C", tmpDir, "add", ".") 173 - if err := stageCmd.Run(); err != nil { 174 - return fmt.Errorf("failed to stage changes: %w", err) 175 - } 176 177 - commitArgs := []string{"-C", tmpDir, "commit"} 178 179 - // Set author if provided 180 - authorName := opts.AuthorName 181 - authorEmail := opts.AuthorEmail 182 183 - if authorEmail == "" { 184 - authorEmail = "noreply@tangled.sh" 185 - } 186 187 - if authorName == "" { 188 - authorName = "Tangled" 189 - } 190 191 - if authorName != "" { 192 - commitArgs = append(commitArgs, "--author", fmt.Sprintf("%s <%s>", authorName, authorEmail)) 193 - } 194 195 - commitArgs = append(commitArgs, "-m", opts.CommitMessage) 196 197 - if opts.CommitBody != "" { 198 - commitArgs = append(commitArgs, "-m", opts.CommitBody) 199 - } 200 201 - cmd = exec.Command("git", commitArgs...) 202 - } else { 203 - // If no commit message specified, use git-am which automatically creates a commit 204 - cmd = exec.Command("git", "-C", tmpDir, "am", patchFile) 205 } 206 } 207 208 cmd.Stderr = &stderr 209 210 if err := cmd.Run(); err != nil { 211 - if checkOnly { 212 - conflicts := parseGitApplyErrors(stderr.String()) 213 - return &ErrMerge{ 214 - Message: "patch cannot be applied cleanly", 215 - Conflicts: conflicts, 216 - HasConflict: len(conflicts) > 0, 217 - OtherError: err, 218 - } 219 - } 220 return fmt.Errorf("patch application failed: %s", stderr.String()) 221 } 222 ··· 228 return val 229 } 230 231 - var opts MergeOptions 232 - opts.FormatPatch = patchutil.IsFormatPatch(string(patchData)) 233 - 234 patchFile, err := g.createTempFileWithPatch(patchData) 235 if err != nil { 236 return &ErrMerge{ ··· 249 } 250 defer os.RemoveAll(tmpDir) 251 252 - result := g.applyPatch(tmpDir, patchFile, true, &opts) 253 mergeCheckCache.Set(g, patchData, targetBranch, result) 254 return result 255 } ··· 277 } 278 defer os.RemoveAll(tmpDir) 279 280 - if err := g.applyPatch(tmpDir, patchFile, false, opts); err != nil { 281 return err 282 } 283
··· 143 return tmpDir, nil 144 } 145 146 + func (g *GitRepo) checkPatch(tmpDir, patchFile string) error { 147 var stderr bytes.Buffer 148 149 + cmd := exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile) 150 + cmd.Stderr = &stderr 151 + 152 + if err := cmd.Run(); err != nil { 153 + conflicts := parseGitApplyErrors(stderr.String()) 154 + return &ErrMerge{ 155 + Message: "patch cannot be applied cleanly", 156 + Conflicts: conflicts, 157 + HasConflict: len(conflicts) > 0, 158 + OtherError: err, 159 } 160 + } 161 + return nil 162 + } 163 164 + func (g *GitRepo) applyPatch(tmpDir, patchFile string, opts *MergeOptions) error { 165 + var stderr bytes.Buffer 166 + var cmd *exec.Cmd 167 168 + // if patch is a format-patch, apply using 'git am' 169 + if opts.FormatPatch { 170 + amCmd := exec.Command("git", "-C", tmpDir, "am", patchFile) 171 + amCmd.Stderr = &stderr 172 + if err := amCmd.Run(); err != nil { 173 + return fmt.Errorf("patch application failed: %s", stderr.String()) 174 + } 175 + return nil 176 + } 177 178 + // else, apply using 'git apply' and commit it manually 179 + exec.Command("git", "-C", tmpDir, "config", "advice.mergeConflict", "false").Run() 180 + if opts != nil { 181 + applyCmd := exec.Command("git", "-C", tmpDir, "apply", patchFile) 182 + applyCmd.Stderr = &stderr 183 + if err := applyCmd.Run(); err != nil { 184 + return fmt.Errorf("patch application failed: %s", stderr.String()) 185 + } 186 187 + stageCmd := exec.Command("git", "-C", tmpDir, "add", ".") 188 + if err := stageCmd.Run(); err != nil { 189 + return fmt.Errorf("failed to stage changes: %w", err) 190 + } 191 192 + commitArgs := []string{"-C", tmpDir, "commit"} 193 194 + // Set author if provided 195 + authorName := opts.AuthorName 196 + authorEmail := opts.AuthorEmail 197 198 + if authorEmail == "" { 199 + authorEmail = "noreply@tangled.sh" 200 + } 201 202 + if authorName == "" { 203 + authorName = "Tangled" 204 + } 205 206 + if authorName != "" { 207 + commitArgs = append(commitArgs, "--author", fmt.Sprintf("%s <%s>", authorName, authorEmail)) 208 + } 209 + 210 + commitArgs = append(commitArgs, "-m", opts.CommitMessage) 211 212 + if opts.CommitBody != "" { 213 + commitArgs = append(commitArgs, "-m", opts.CommitBody) 214 } 215 + 216 + cmd = exec.Command("git", commitArgs...) 217 + } else { 218 + // If no commit message specified, use git-am which automatically creates a commit 219 + cmd = exec.Command("git", "-C", tmpDir, "am", patchFile) 220 } 221 222 cmd.Stderr = &stderr 223 224 if err := cmd.Run(); err != nil { 225 return fmt.Errorf("patch application failed: %s", stderr.String()) 226 } 227 ··· 233 return val 234 } 235 236 patchFile, err := g.createTempFileWithPatch(patchData) 237 if err != nil { 238 return &ErrMerge{ ··· 251 } 252 defer os.RemoveAll(tmpDir) 253 254 + result := g.checkPatch(tmpDir, patchFile) 255 mergeCheckCache.Set(g, patchData, targetBranch, result) 256 return result 257 } ··· 279 } 280 defer os.RemoveAll(tmpDir) 281 282 + if err := g.applyPatch(tmpDir, patchFile, opts); err != nil { 283 return err 284 } 285