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

knotserver/git/merge: merge options use git apply

Changed files
+75 -9
knotserver
types
+57 -4
knotserver/git/merge.go
···
Reason string
}
+
// MergeOptions specifies the configuration for a merge operation
+
type MergeOptions struct {
+
CommitMessage string
+
CommitBody string
+
AuthorName string
+
AuthorEmail string
+
}
+
func (e ErrMerge) Error() string {
if e.HasConflict {
return fmt.Sprintf("merge failed due to conflicts: %s (%d conflicts)", e.Message, len(e.Conflicts))
···
return tmpDir, nil
}
-
func (g *GitRepo) applyPatch(tmpDir, patchFile string, checkOnly bool) error {
+
func (g *GitRepo) applyPatch(tmpDir, patchFile string, checkOnly bool, opts *MergeOptions) error {
var stderr bytes.Buffer
var cmd *exec.Cmd
···
cmd = exec.Command("git", "-C", tmpDir, "apply", "--check", "-v", patchFile)
} else {
exec.Command("git", "-C", tmpDir, "config", "advice.mergeConflict", "false").Run()
-
cmd = exec.Command("git", "-C", tmpDir, "am", patchFile)
+
+
if opts != nil {
+
applyCmd := exec.Command("git", "-C", tmpDir, "apply", patchFile)
+
applyCmd.Stderr = &stderr
+
if err := applyCmd.Run(); err != nil {
+
return fmt.Errorf("patch application failed: %s", stderr.String())
+
}
+
+
stageCmd := exec.Command("git", "-C", tmpDir, "add", ".")
+
if err := stageCmd.Run(); err != nil {
+
return fmt.Errorf("failed to stage changes: %w", err)
+
}
+
+
commitArgs := []string{"-C", tmpDir, "commit"}
+
+
// Set author if provided
+
authorName := opts.AuthorName
+
authorEmail := opts.AuthorEmail
+
+
if authorEmail == "" {
+
authorEmail = "noreply@tangled.sh"
+
}
+
+
if authorName == "" {
+
authorName = "Tangled"
+
}
+
+
if authorName != "" {
+
commitArgs = append(commitArgs, "--author", fmt.Sprintf("%s <%s>", authorName, authorEmail))
+
}
+
+
commitArgs = append(commitArgs, "-m", opts.CommitMessage)
+
+
if opts.CommitBody != "" {
+
commitArgs = append(commitArgs, "-m", opts.CommitBody)
+
}
+
+
cmd = exec.Command("git", commitArgs...)
+
} else {
+
// If no commit message specified, use git-am which automatically creates a commit
+
cmd = exec.Command("git", "-C", tmpDir, "am", patchFile)
+
}
}
cmd.Stderr = &stderr
···
}
defer os.RemoveAll(tmpDir)
-
return g.applyPatch(tmpDir, patchFile, true)
+
return g.applyPatch(tmpDir, patchFile, true, nil)
}
func (g *GitRepo) Merge(patchData []byte, targetBranch string) error {
+
return g.MergeWithOptions(patchData, targetBranch, nil)
+
}
+
+
func (g *GitRepo) MergeWithOptions(patchData []byte, targetBranch string, opts *MergeOptions) error {
patchFile, err := g.createTempFileWithPatch(patchData)
if err != nil {
return &ErrMerge{
···
}
defer os.RemoveAll(tmpDir)
-
if err := g.applyPatch(tmpDir, patchFile, false); err != nil {
+
if err := g.applyPatch(tmpDir, patchFile, false, opts); err != nil {
return err
}
+9 -5
knotserver/routes.go
···
func (h *Handle) Merge(w http.ResponseWriter, r *http.Request) {
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
-
var data struct {
-
Patch string `json:"patch"`
-
Branch string `json:"branch"`
-
}
+
data := types.MergeRequest{}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
writeError(w, err.Error(), http.StatusBadRequest)
···
return
}
+
mo := &git.MergeOptions{
+
AuthorName: data.AuthorName,
+
AuthorEmail: data.AuthorEmail,
+
CommitBody: data.CommitBody,
+
CommitMessage: data.CommitMessage,
+
}
+
patch := data.Patch
branch := data.Branch
gr, err := git.Open(path, branch)
···
notFound(w)
return
}
-
if err := gr.Merge([]byte(patch), branch); err != nil {
+
if err := gr.MergeWithOptions([]byte(patch), branch, mo); err != nil {
var mergeErr *git.ErrMerge
if errors.As(err, &mergeErr) {
conflicts := make([]types.ConflictInfo, len(mergeErr.Conflicts))
+9
types/merge.go
···
Message string `json:"message"`
Error string `json:"error"`
}
+
+
type MergeRequest struct {
+
Patch string `json:"patch"`
+
AuthorName string `json:"authorName,omitempty"`
+
AuthorEmail string `json:"authorEmail,omitempty"`
+
CommitBody string `json:"commitBody,omitempty"`
+
CommitMessage string `json:"commitMessage,omitempty"`
+
Branch string `json:"branch"`
+
}