This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / pulls / create.go
4.5 kB 171 lines
1package pulls 2 3import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "golang.org/x/sync/errgroup" 9 "tangled.org/core/api/tangled" 10 "tangled.org/core/appview/db" 11 "tangled.org/core/appview/knotcompat" 12 "tangled.org/core/appview/models" 13 "tangled.org/core/appview/oauth" 14 "tangled.org/core/appview/reporesolver" 15 "tangled.org/core/tid" 16 17 comatproto "github.com/bluesky-social/indigo/api/atproto" 18 "github.com/bluesky-social/indigo/atproto/syntax" 19) 20 21func (s *Pulls) handlePull( 22 w http.ResponseWriter, 23 r *http.Request, 24 userDid syntax.DID, 25 targetRepo *models.Repo, 26 targetBranch string, 27 sourceRepo *models.Repo, 28 sourceBranch string, 29 title, 30 body string, 31) { 32 l := s.logger.With("handler", "handlePull", "user", userDid) 33 ctx := r.Context() 34 35 client, err := s.oauth.AuthorizedClient(r) 36 if err != nil { 37 l.Error("failed to get authorized client", "err", err) 38 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 39 return 40 } 41 42 // 1. fetch heads of source & target branches 43 var base, head string 44 { 45 xrpcc := s.knotMirrorXRPC 46 g, gctx := errgroup.WithContext(ctx) 47 g.Go(func() error { 48 // find merge-base between targetBranch & sourceBranch 49 out, err := tangled.GitTempGetMergeBase(gctx, xrpcc, targetBranch, sourceBranch, sourceRepo.RepoDid) 50 if err != nil { 51 return err 52 } 53 base = out.Commit 54 return nil 55 }) 56 g.Go(func() error { 57 out, err := tangled.GitTempGetBranch(gctx, xrpcc, sourceBranch, sourceRepo.RepoDid) 58 if err != nil { 59 return err 60 } 61 head = out.Hash 62 return nil 63 }) 64 if err := g.Wait(); err != nil { 65 l.Error("failed to fetch branch heads", "err", err) 66 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 67 return 68 } 69 } 70 71 created := time.Now() 72 pull := &models.Pull{ 73 ID: -1, // uninitialized 74 OwnerDid: userDid, 75 Rkey: syntax.RecordKey(tid.TID()), 76 Cid: "", // uninitialized 77 RepoDid: syntax.DID(targetRepo.RepoDid), 78 PullId: 0, // uninitialized 79 80 Title: title, 81 Body: body, 82 TargetBranch: targetBranch, 83 SourceRepo: syntax.DID(sourceRepo.RepoDid), 84 SourceBranch: &sourceBranch, 85 Versions: []models.PullVersion{ 86 { 87 ID: 0, 88 Base: base, 89 Head: head, 90 Created: created, 91 }, 92 }, 93 Created: created, 94 State: models.PullOpen, 95 96 Repo: targetRepo, 97 } 98 99 // 2. call git.keepCommit 100 { 101 client, err := s.oauth.ServiceClient( 102 r, 103 oauth.WithService(sourceRepo.Knot), 104 oauth.WithLxm(tangled.GitKeepCommitNSID), 105 oauth.WithDev(s.config.Core.Dev), 106 ) 107 if err != nil { 108 l.Error("failed to comment to knot", "err", err) 109 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 110 return 111 } 112 113 _, err = tangled.GitKeepCommit(ctx, client, &tangled.GitKeepCommit_Input{ 114 Repo: sourceRepo.RepoDid, 115 Record: pull.AtUri().String(), 116 Source: &tangled.GitKeepCommit_Input_Source{ 117 GitKeepCommit_Commit: &tangled.GitKeepCommit_Commit{ 118 Repo: sourceRepo.RepoDid, 119 Oid: head, 120 }, 121 }, 122 }) 123 if err != nil { 124 l.Error("failed to keep commit", "err", err) 125 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 126 return 127 } 128 } 129 130 // 3. create PR record 131 record := pull.AsRecord() 132 out, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 133 Collection: tangled.RepoPullNSID, 134 Repo: userDid.String(), 135 Rkey: pull.Rkey.String(), 136 Record: knotcompat.Pull(&record), 137 }) 138 pull.Cid = syntax.CID(out.Cid) 139 140 tx, err := s.db.BeginTx(r.Context(), nil) 141 if err != nil { 142 l.Error("failed to start tx", "err", err) 143 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 144 return 145 } 146 defer tx.Rollback() 147 148 var references []syntax.ATURI 149 if pull.Body != "" { 150 _, references = s.mentionsResolver.Resolve(ctx, pull.Body) 151 } 152 153 if err := db.PutPull(r.Context(), tx, pull, references); err != nil { 154 l.Error("failed to create pull request in database", "err", err) 155 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 156 return 157 } 158 159 if err = tx.Commit(); err != nil { 160 l.Error("failed to commit transaction for pull request", "err", err) 161 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 162 return 163 } 164 165 s.notifier.NewPull(r.Context(), pull) 166 167 s.applyCreationLabels(r.Context(), client, userDid, pull, r.Form, targetRepo) 168 169 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, targetRepo) 170 s.pages.HxRedirect(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) 171}