This repository has no description
0

Configure Feed

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

core / appview / pulls / resubmit.go
4.9 kB 179 lines
1package pulls 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 "tangled.org/core/api/tangled" 10 "tangled.org/core/appview/db" 11 "tangled.org/core/appview/models" 12 "tangled.org/core/appview/oauth" 13 "tangled.org/core/appview/reporesolver" 14 15 comatproto "github.com/bluesky-social/indigo/api/atproto" 16 "github.com/bluesky-social/indigo/atproto/syntax" 17 lexutil "github.com/bluesky-social/indigo/lex/util" 18) 19 20func (s *Pulls) ResubmitPull(w http.ResponseWriter, r *http.Request) { 21 l := s.logger.With("handler", "ResubmitPull") 22 noticeId := "pull-action-error" 23 24 user := s.oauth.GetMultiAccountUser(r) 25 if user != nil { 26 l = l.With("user", user.Did) 27 } 28 29 repo, err := s.repoResolver.Resolve(r) 30 if err != nil { 31 l.Error("failed to get repo and knot", "err", err) 32 return 33 } 34 35 pull, ok := r.Context().Value("pull").(*models.Pull) 36 if !ok { 37 l.Error("failed to get pull") 38 s.pages.Notice(w, noticeId, "Failed to get PR. Try again later.") 39 return 40 } 41 l = l.With("pull_id", pull.PullId, "pull_owner", pull.OwnerDid) 42 43 if pull.OwnerDid != syntax.DID(user.Did) { 44 s.pages.Notice(w, noticeId, "Unauthorized user. Try again later.") 45 return 46 } 47 48 if pull.SourceBranch == nil { 49 // can't resubmit if source is unknown. fail earlier 50 s.pages.Notice(w, noticeId, "PR source branch is unknown.") 51 return 52 } 53 sourceBranch := *pull.SourceBranch 54 55 var sourceRepo *models.Repo 56 if pull.SourceRepo == syntax.DID(repo.RepoDid) { 57 sourceRepo = repo 58 } else { 59 var err error 60 sourceRepo, err = db.GetRepoByDid(s.db, pull.SourceRepo.String()) 61 if err != nil { 62 s.pages.Notice(w, noticeId, fmt.Sprintf("Unknown source repository: %q", pull.SourceRepo)) 63 return 64 } 65 } 66 67 ctx := r.Context() 68 69 var base, head string 70 { 71 xrpcc := s.knotMirrorXRPC 72 branch, err := tangled.GitTempGetBranch(ctx, xrpcc, sourceBranch, pull.RepoDid.String()) 73 if err != nil { 74 s.pages.Notice(w, noticeId, "Failed to get source branch") 75 return 76 } 77 out, err := tangled.GitTempGetMergeBase(ctx, xrpcc, pull.TargetBranch, branch.Hash, pull.RepoDid.String()) 78 if err != nil { 79 s.pages.Notice(w, noticeId, "Failed to compute merge-base.") 80 return 81 } 82 83 head = branch.Hash 84 base = out.Commit 85 } 86 87 newVersion := models.PullVersion{ 88 ID: pull.LatestVersionNumber() + 1, 89 Base: base, 90 Head: head, 91 Created: time.Now(), 92 } 93 pull.Versions = append(pull.Versions, newVersion) 94 95 // keep new version head in Knot 96 { 97 client, err := s.oauth.ServiceClient( 98 r, 99 oauth.WithService(sourceRepo.Knot), 100 oauth.WithLxm(tangled.GitKeepCommitNSID), 101 oauth.WithDev(s.config.Core.Dev), 102 ) 103 if err != nil { 104 l.Error("failed to create service auth", "err", err) 105 s.pages.Notice(w, noticeId, "Failed to create service auth. Try again later.") 106 return 107 } 108 109 _, err = tangled.GitKeepCommit(ctx, client, &tangled.GitKeepCommit_Input{ 110 Repo: sourceRepo.RepoDid, 111 Record: pull.AtUri().String(), 112 Source: &tangled.GitKeepCommit_Input_Source{ 113 GitKeepCommit_Commit: &tangled.GitKeepCommit_Commit{ 114 Repo: sourceRepo.RepoDid, 115 Oid: head, 116 }, 117 }, 118 }) 119 if err != nil { 120 l.Error("failed to keep commit", "err", err) 121 s.pages.Notice(w, noticeId, "Failed to resubmit pull request. Try again later.") 122 return 123 } 124 } 125 126 // update PDS record 127 { 128 client, err := s.oauth.AuthorizedClient(r) 129 if err != nil { 130 s.pages.Notice(w, noticeId, "Unauthorized user. Try again later.") 131 return 132 } 133 134 // NOTE: some old PR records are missing CID 135 if err := s.ensurePullCid(ctx, client, pull); err != nil { 136 s.pages.Notice(w, noticeId, "Failed to get existing PR record. Is PR deleted from PDS?") 137 return 138 } 139 140 record := pull.AsRecord() 141 exCid := pull.Cid.String() 142 out, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 143 Collection: tangled.RepoPullNSID, 144 Repo: pull.OwnerDid.String(), 145 Rkey: pull.Rkey.String(), 146 SwapRecord: &exCid, 147 Record: &lexutil.LexiconTypeDecoder{Val: &record}, 148 }) 149 if err != nil { 150 l.Error("failed to create PDS record", "err", err) 151 s.pages.Notice(w, noticeId, "Failed to resubmit pull request. Try again later.") 152 return 153 } 154 pull.Cid = syntax.CID(out.Cid) 155 } 156 157 if err := db.SubmitPullVersion(ctx, s.db, pull.AtUri(), newVersion); err != nil { 158 l.Error("failed to update PR in DB", "err", err) 159 s.pages.Notice(w, noticeId, "Failed to resubmit pull request. Try again later.") 160 return 161 } 162 163 s.notifier.ResubmitPull(r.Context(), pull) 164 165 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, repo) 166 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) 167} 168 169func (s *Pulls) ensurePullCid(ctx context.Context, client lexutil.LexClient, pull *models.Pull) error { 170 out, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, pull.OwnerDid.String(), pull.Rkey.String()) 171 if err != nil { 172 return err 173 } 174 if out.Cid == nil { 175 return fmt.Errorf("record CID is empty") 176 } 177 pull.Cid = syntax.CID(*out.Cid) 178 return nil 179}