Monorepo for Tangled
1package xrpc
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "net/http"
8
9 "tangled.org/core/api/tangled"
10 "tangled.org/core/knotserver/git"
11 "tangled.org/core/patchutil"
12 xrpcerr "tangled.org/core/xrpc/errors"
13)
14
15func (x *Xrpc) MergeCheck(w http.ResponseWriter, r *http.Request) {
16 l := x.Logger.With("handler", "MergeCheck")
17 fail := func(e xrpcerr.XrpcError) {
18 l.Error("failed", "kind", e.Tag, "error", e.Message)
19 writeError(w, e, http.StatusBadRequest)
20 }
21
22 var data tangled.RepoMergeCheck_Input
23 if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
24 fail(xrpcerr.GenericError(err))
25 return
26 }
27
28 did := data.Did
29 name := data.Name
30
31 if did == "" || name == "" {
32 fail(xrpcerr.GenericError(fmt.Errorf("did and name are required")))
33 return
34 }
35
36 repoDid, err := x.Db.GetRepoDid(did, name)
37 if err != nil {
38 fail(xrpcerr.RepoNotFoundError)
39 return
40 }
41 repoPath, _, _, err := x.Db.ResolveRepoDIDOnDisk(x.Config.Repo.ScanPath, repoDid)
42 if err != nil {
43 fail(xrpcerr.RepoNotFoundError)
44 return
45 }
46
47 gr, err := git.Open(repoPath, data.Branch)
48 if err != nil {
49 fail(xrpcerr.GenericError(fmt.Errorf("failed to open repository: %w", err)))
50 return
51 }
52
53 mo := git.MergeOptions{}
54 mo.CommitMessage = "merge check"
55 mo.CommitterName = x.Config.Git.UserName
56 mo.CommitterEmail = x.Config.Git.UserEmail
57 mo.FormatPatch = patchutil.IsFormatPatch(data.Patch)
58
59 err = gr.MergeCheckWithOptions(data.Patch, data.Branch, mo)
60
61 response := tangled.RepoMergeCheck_Output{
62 Is_conflicted: false,
63 }
64
65 if err != nil {
66 var mergeErr *git.ErrMerge
67 if errors.As(err, &mergeErr) {
68 response.Is_conflicted = true
69
70 conflicts := make([]*tangled.RepoMergeCheck_ConflictInfo, len(mergeErr.Conflicts))
71 for i, conflict := range mergeErr.Conflicts {
72 conflicts[i] = &tangled.RepoMergeCheck_ConflictInfo{
73 Filename: conflict.Filename,
74 Reason: conflict.Reason,
75 }
76 }
77 response.Conflicts = conflicts
78
79 if mergeErr.Message != "" {
80 response.Message = &mergeErr.Message
81 }
82 } else {
83 response.Is_conflicted = true
84 errMsg := err.Error()
85 response.Error = &errMsg
86 }
87 }
88
89 l.Debug("merge check response", "isConflicted", response.Is_conflicted, "err", response.Error, "conflicts", response.Conflicts)
90
91 w.Header().Set("Content-Type", "application/json")
92 w.WriteHeader(http.StatusOK)
93 json.NewEncoder(w).Encode(response)
94}