forked from tangled.org/core
this repo has no description

knotserver/git/merge: merge options use git apply

authored by anirudh.fi and committed by oppi.li 5949cdf5 a588049f

Changed files
+75 -9
knotserver
types
+57 -4
knotserver/git/merge.go
··· 24 24 Reason string 25 25 } 26 26 27 + // MergeOptions specifies the configuration for a merge operation 28 + type MergeOptions struct { 29 + CommitMessage string 30 + CommitBody string 31 + AuthorName string 32 + AuthorEmail string 33 + } 34 + 27 35 func (e ErrMerge) Error() string { 28 36 if e.HasConflict { 29 37 return fmt.Sprintf("merge failed due to conflicts: %s (%d conflicts)", e.Message, len(e.Conflicts)) ··· 74 82 return tmpDir, nil 75 83 } 76 84 77 - func (g *GitRepo) applyPatch(tmpDir, patchFile string, checkOnly bool) error { 85 + func (g *GitRepo) applyPatch(tmpDir, patchFile string, checkOnly bool, opts *MergeOptions) error { 78 86 var stderr bytes.Buffer 79 87 var cmd *exec.Cmd 80 88 ··· 82 90 cmd = exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile) 83 91 } else { 84 92 exec.Command("git", "-C", tmpDir, "config", "advice.mergeConflict", "false").Run() 85 - cmd = exec.Command("git", "-C", tmpDir, "am", patchFile) 93 + 94 + if opts != nil { 95 + applyCmd := exec.Command("git", "-C", tmpDir, "apply", patchFile) 96 + applyCmd.Stderr = &stderr 97 + if err := applyCmd.Run(); err != nil { 98 + return fmt.Errorf("patch application failed: %s", stderr.String()) 99 + } 100 + 101 + stageCmd := exec.Command("git", "-C", tmpDir, "add", ".") 102 + if err := stageCmd.Run(); err != nil { 103 + return fmt.Errorf("failed to stage changes: %w", err) 104 + } 105 + 106 + commitArgs := []string{"-C", tmpDir, "commit"} 107 + 108 + // Set author if provided 109 + authorName := opts.AuthorName 110 + authorEmail := opts.AuthorEmail 111 + 112 + if authorEmail == "" { 113 + authorEmail = "noreply@tangled.sh" 114 + } 115 + 116 + if authorName == "" { 117 + authorName = "Tangled" 118 + } 119 + 120 + if authorName != "" { 121 + commitArgs = append(commitArgs, "--author", fmt.Sprintf("%s <%s>", authorName, authorEmail)) 122 + } 123 + 124 + commitArgs = append(commitArgs, "-m", opts.CommitMessage) 125 + 126 + if opts.CommitBody != "" { 127 + commitArgs = append(commitArgs, "-m", opts.CommitBody) 128 + } 129 + 130 + cmd = exec.Command("git", commitArgs...) 131 + } else { 132 + // If no commit message specified, use git-am which automatically creates a commit 133 + cmd = exec.Command("git", "-C", tmpDir, "am", patchFile) 134 + } 86 135 } 87 136 88 137 cmd.Stderr = &stderr ··· 122 171 } 123 172 defer os.RemoveAll(tmpDir) 124 173 125 - return g.applyPatch(tmpDir, patchFile, true) 174 + return g.applyPatch(tmpDir, patchFile, true, nil) 126 175 } 127 176 128 177 func (g *GitRepo) Merge(patchData []byte, targetBranch string) error { 178 + return g.MergeWithOptions(patchData, targetBranch, nil) 179 + } 180 + 181 + func (g *GitRepo) MergeWithOptions(patchData []byte, targetBranch string, opts *MergeOptions) error { 129 182 patchFile, err := g.createTempFileWithPatch(patchData) 130 183 if err != nil { 131 184 return &ErrMerge{ ··· 144 197 } 145 198 defer os.RemoveAll(tmpDir) 146 199 147 - if err := g.applyPatch(tmpDir, patchFile, false); err != nil { 200 + if err := g.applyPatch(tmpDir, patchFile, false, opts); err != nil { 148 201 return err 149 202 } 150 203
+9 -5
knotserver/routes.go
··· 559 559 func (h *Handle) Merge(w http.ResponseWriter, r *http.Request) { 560 560 path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r)) 561 561 562 - var data struct { 563 - Patch string `json:"patch"` 564 - Branch string `json:"branch"` 565 - } 562 + data := types.MergeRequest{} 566 563 567 564 if err := json.NewDecoder(r.Body).Decode(&data); err != nil { 568 565 writeError(w, err.Error(), http.StatusBadRequest) ··· 570 567 return 571 568 } 572 569 570 + mo := &git.MergeOptions{ 571 + AuthorName: data.AuthorName, 572 + AuthorEmail: data.AuthorEmail, 573 + CommitBody: data.CommitBody, 574 + CommitMessage: data.CommitMessage, 575 + } 576 + 573 577 patch := data.Patch 574 578 branch := data.Branch 575 579 gr, err := git.Open(path, branch) ··· 577 581 notFound(w) 578 582 return 579 583 } 580 - if err := gr.Merge([]byte(patch), branch); err != nil { 584 + if err := gr.MergeWithOptions([]byte(patch), branch, mo); err != nil { 581 585 var mergeErr *git.ErrMerge 582 586 if errors.As(err, &mergeErr) { 583 587 conflicts := make([]types.ConflictInfo, len(mergeErr.Conflicts))
+9
types/merge.go
··· 11 11 Message string `json:"message"` 12 12 Error string `json:"error"` 13 13 } 14 + 15 + type MergeRequest struct { 16 + Patch string `json:"patch"` 17 + AuthorName string `json:"authorName,omitempty"` 18 + AuthorEmail string `json:"authorEmail,omitempty"` 19 + CommitBody string `json:"commitBody,omitempty"` 20 + CommitMessage string `json:"commitMessage,omitempty"` 21 + Branch string `json:"branch"` 22 + }