1package xrpc
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "net/http"
8
9 securejoin "github.com/cyphar/filepath-securejoin"
10 "tangled.sh/tangled.sh/core/api/tangled"
11 "tangled.sh/tangled.sh/core/knotserver/git"
12 xrpcerr "tangled.sh/tangled.sh/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 relativeRepoPath, err := securejoin.SecureJoin(did, name)
37 if err != nil {
38 fail(xrpcerr.GenericError(err))
39 return
40 }
41
42 repoPath, err := securejoin.SecureJoin(x.Config.Repo.ScanPath, relativeRepoPath)
43 if err != nil {
44 fail(xrpcerr.GenericError(err))
45 return
46 }
47
48 gr, err := git.Open(repoPath, data.Branch)
49 if err != nil {
50 fail(xrpcerr.GenericError(fmt.Errorf("failed to open repository: %w", err)))
51 return
52 }
53
54 err = gr.MergeCheck([]byte(data.Patch), data.Branch)
55
56 response := tangled.RepoMergeCheck_Output{
57 Is_conflicted: false,
58 }
59
60 if err != nil {
61 var mergeErr *git.ErrMerge
62 if errors.As(err, &mergeErr) {
63 response.Is_conflicted = true
64
65 conflicts := make([]*tangled.RepoMergeCheck_ConflictInfo, len(mergeErr.Conflicts))
66 for i, conflict := range mergeErr.Conflicts {
67 conflicts[i] = &tangled.RepoMergeCheck_ConflictInfo{
68 Filename: conflict.Filename,
69 Reason: conflict.Reason,
70 }
71 }
72 response.Conflicts = conflicts
73
74 if mergeErr.Message != "" {
75 response.Message = &mergeErr.Message
76 }
77 } else {
78 response.Is_conflicted = true
79 errMsg := err.Error()
80 response.Error = &errMsg
81 }
82 }
83
84 w.Header().Set("Content-Type", "application/json")
85 w.WriteHeader(http.StatusOK)
86 json.NewEncoder(w).Encode(response)
87}