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