Monorepo for Tangled tangled.org

knotserver: git/merge: separate `applyPatch` and `checkPatch`

- we don't need `MergeOptions` for checking a patch

Signed-off-by: Seongmin Lee <boltlessengineer@proton.me>

authored by boltless.me and committed by Tangled 3c066500 cdac8683

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