forked from tangled.org/core
this repo has no description
at knot-xrpc 2.5 kB view raw
1package xrpc 2 3import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 securejoin "github.com/cyphar/filepath-securejoin" 11 "tangled.sh/tangled.sh/core/api/tangled" 12 "tangled.sh/tangled.sh/core/knotserver/git" 13 "tangled.sh/tangled.sh/core/rbac" 14 xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors" 15) 16 17func (x *Xrpc) MergeCheck(w http.ResponseWriter, r *http.Request) { 18 l := x.Logger.With("handler", "MergeCheck") 19 fail := func(e xrpcerr.XrpcError) { 20 l.Error("failed", "kind", e.Tag, "error", e.Message) 21 writeError(w, e, http.StatusBadRequest) 22 } 23 24 actorDid, ok := r.Context().Value(ActorDid).(syntax.DID) 25 if !ok { 26 fail(xrpcerr.MissingActorDidError) 27 return 28 } 29 30 isMember, err := x.Enforcer.IsKnotMember(actorDid.String(), rbac.ThisServer) 31 if err != nil { 32 fail(xrpcerr.GenericError(err)) 33 return 34 } 35 if !isMember { 36 fail(xrpcerr.AccessControlError(actorDid.String())) 37 return 38 } 39 40 var data tangled.RepoMergeCheck_Input 41 if err := json.NewDecoder(r.Body).Decode(&data); err != nil { 42 fail(xrpcerr.GenericError(err)) 43 return 44 } 45 46 did := data.Did 47 name := data.Name 48 49 if did == "" || name == "" { 50 fail(xrpcerr.GenericError(fmt.Errorf("did and name are required"))) 51 return 52 } 53 54 relativeRepoPath, err := securejoin.SecureJoin(did, name) 55 if err != nil { 56 fail(xrpcerr.GenericError(err)) 57 return 58 } 59 60 repoPath, err := securejoin.SecureJoin(x.Config.Repo.ScanPath, relativeRepoPath) 61 if err != nil { 62 fail(xrpcerr.GenericError(err)) 63 return 64 } 65 66 gr, err := git.Open(repoPath, data.Branch) 67 if err != nil { 68 fail(xrpcerr.GenericError(fmt.Errorf("failed to open repository: %w", err))) 69 return 70 } 71 72 err = gr.MergeCheck([]byte(data.Patch), data.Branch) 73 74 response := tangled.RepoMergeCheck_Output{ 75 Is_conflicted: false, 76 } 77 78 if err != nil { 79 var mergeErr *git.ErrMerge 80 if errors.As(err, &mergeErr) { 81 response.Is_conflicted = true 82 83 conflicts := make([]*tangled.RepoMergeCheck_ConflictInfo, len(mergeErr.Conflicts)) 84 for i, conflict := range mergeErr.Conflicts { 85 conflicts[i] = &tangled.RepoMergeCheck_ConflictInfo{ 86 Filename: conflict.Filename, 87 Reason: conflict.Reason, 88 } 89 } 90 response.Conflicts = conflicts 91 92 if mergeErr.Message != "" { 93 response.Message = &mergeErr.Message 94 } 95 } else { 96 response.Is_conflicted = true 97 errMsg := err.Error() 98 response.Error = &errMsg 99 } 100 } 101 102 w.Header().Set("Content-Type", "application/json") 103 w.WriteHeader(http.StatusOK) 104 json.NewEncoder(w).Encode(response) 105}