···4545 <a href="/{{ .RepoInfo.FullName }}/tree/{{ .Pull.TargetBranch }}" class="no-underline hover:underline">{{ .Pull.TargetBranch }}</a>4646 </span>4747 </span>4848- {{ if not .Pull.IsPatch }}4848+ {{ if not .Pull.IsPatchBased }}4949 <span>from5050- {{ if not .Pull.IsSameRepoBranch }}5050+ {{ if not .Pull.IsBranchBased }}5151 <a href="/{{ $owner }}/{{ .PullSourceRepo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .PullSourceRepo.Name }}</a>5252 {{ end }}53535454 {{ $fullRepo := .RepoInfo.FullName }}5555- {{ if not .Pull.IsSameRepoBranch }}5555+ {{ if not .Pull.IsBranchBased }}5656 {{ $fullRepo = printf "%s/%s" $owner .PullSourceRepo.Name }}5757 {{ end }}5858 <span class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center">
+2-2
appview/pages/templates/repo/pulls/pulls.html
···7878 {{ .TargetBranch }}7979 </span>8080 </span>8181- {{ if not .IsPatch }}8181+ {{ if not .IsPatchBased }}8282 <span>from8383- {{ if not .IsSameRepoBranch }}8383+ {{ if not .IsBranchBased }}8484 <a href="/{{ $owner }}/{{ .PullSource.Repo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .PullSource.Repo.Name }}</a>8585 {{ end }}8686
+417-169
appview/state/pull.go
···10151015 })10161016 return10171017 case http.MethodPost:10181018- patch := r.FormValue("patch")10191019- var sourceRev string10201020- var recordPullSource *tangled.RepoPull_Source10211021-10221022- var ownerDid, repoName, knotName string10231023- var isSameRepo bool = pull.IsSameRepoBranch()10241024- sourceBranch := pull.PullSource.Branch10251025- targetBranch := pull.TargetBranch10261026- recordPullSource = &tangled.RepoPull_Source{10271027- Branch: sourceBranch,10281028- }10291029-10301030- isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed()10311031- if isSameRepo && isPushAllowed {10321032- ownerDid = f.OwnerDid()10331033- repoName = f.RepoName10341034- knotName = f.Knot10351035- } else if !isSameRepo {10361036- sourceRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())10371037- if err != nil {10381038- log.Println("failed to get source repo", err)10391039- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10401040- return10411041- }10421042- ownerDid = sourceRepo.Did10431043- repoName = sourceRepo.Name10441044- knotName = sourceRepo.Knot10451045- }10461046-10471047- if sourceBranch != "" && knotName != "" {10481048- // extract patch by performing compare10491049- ksClient, err := NewUnsignedClient(knotName, s.config.Dev)10501050- if err != nil {10511051- log.Printf("failed to create client for %s: %s", knotName, err)10521052- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10531053- return10541054- }10551055-10561056- if !isSameRepo {10571057- secret, err := db.GetRegistrationKey(s.db, knotName)10581058- if err != nil {10591059- log.Printf("failed to get registration key for %s: %s", knotName, err)10601060- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10611061- return10621062- }10631063- // update the hidden tracking branch to latest10641064- signedClient, err := NewSignedClient(knotName, secret, s.config.Dev)10651065- if err != nil {10661066- log.Printf("failed to create signed client for %s: %s", knotName, err)10671067- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10681068- return10691069- }10701070- resp, err := signedClient.NewHiddenRef(ownerDid, repoName, sourceBranch, targetBranch)10711071- if err != nil || resp.StatusCode != http.StatusNoContent {10721072- log.Printf("failed to update tracking branch: %s", err)10731073- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10741074- return10751075- }10761076- }10771077-10781078- var compareResp *http.Response10791079- if !isSameRepo {10801080- hiddenRef := url.QueryEscape(fmt.Sprintf("hidden/%s/%s", sourceBranch, targetBranch))10811081- compareResp, err = ksClient.Compare(ownerDid, repoName, hiddenRef, sourceBranch)10821082- } else {10831083- compareResp, err = ksClient.Compare(ownerDid, repoName, targetBranch, sourceBranch)10841084- }10851085- if err != nil {10861086- log.Printf("failed to compare branches: %s", err)10871087- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")10881088- return10891089- }10901090- defer compareResp.Body.Close()10911091-10921092- switch compareResp.StatusCode {10931093- case 404:10941094- case 400:10951095- s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")10961096- return10971097- }10981098-10991099- respBody, err := io.ReadAll(compareResp.Body)11001100- if err != nil {11011101- log.Println("failed to compare across branches")11021102- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11031103- return11041104- }11051105- defer compareResp.Body.Close()11061106-11071107- var diffTreeResponse types.RepoDiffTreeResponse11081108- err = json.Unmarshal(respBody, &diffTreeResponse)11091109- if err != nil {11101110- log.Println("failed to unmarshal diff tree response", err)11111111- s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11121112- return11131113- }11141114-11151115- sourceRev = diffTreeResponse.DiffTree.Rev211161116- patch = diffTreeResponse.DiffTree.Patch11171117- }11181118-11191119- if patch == "" {11201120- s.pages.Notice(w, "resubmit-error", "Patch is empty.")10181018+ if pull.IsPatchBased() {10191019+ s.resubmitPatch(w, r)10201020+ return10211021+ } else if pull.IsBranchBased() {10221022+ s.resubmitBranch(w, r)10231023+ return10241024+ } else if pull.IsForkBased() {10251025+ s.resubmitFork(w, r)11211026 return11221027 }10281028+ }10291029+}1123103011241124- if patch == pull.LatestPatch() {11251125- s.pages.Notice(w, "resubmit-error", "Patch is identical to previous submission.")11261126- return11271127- }10311031+func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {10321032+ user := s.auth.GetUser(r)1128103311291129- if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {11301130- s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")11311131- return11321132- }11331133-11341134- if !isPatchValid(patch) {11351135- s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.")11361136- return11371137- }11381138-11391139- tx, err := s.db.BeginTx(r.Context(), nil)11401140- if err != nil {11411141- log.Println("failed to start tx")11421142- s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")11431143- return11441144- }11451145- defer tx.Rollback()11461146-11471147- err = db.ResubmitPull(tx, pull, patch, sourceRev)11481148- if err != nil {11491149- log.Println("failed to create pull request", err)11501150- s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")11511151- return11521152- }11531153- client, _ := s.auth.AuthorizedClient(r)11541154-11551155- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)11561156- if err != nil {11571157- // failed to get record11581158- s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")11591159- return11601160- }11611161-11621162- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{11631163- Collection: tangled.RepoPullNSID,11641164- Repo: user.Did,11651165- Rkey: pull.Rkey,11661166- SwapRecord: ex.Cid,11671167- Record: &lexutil.LexiconTypeDecoder{11681168- Val: &tangled.RepoPull{11691169- Title: pull.Title,11701170- PullId: int64(pull.PullId),11711171- TargetRepo: string(f.RepoAt),11721172- TargetBranch: pull.TargetBranch,11731173- Patch: patch, // new patch11741174- Source: recordPullSource,11751175- },11761176- },11771177- })11781178- if err != nil {11791179- log.Println("failed to update record", err)11801180- s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")11811181- return11821182- }11831183-11841184- if err = tx.Commit(); err != nil {11851185- log.Println("failed to commit transaction", err)11861186- s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")11871187- return11881188- }11891189-11901190- s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))10341034+ pull, ok := r.Context().Value("pull").(*db.Pull)10351035+ if !ok {10361036+ log.Println("failed to get pull")10371037+ s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")11911038 return11921039 }10401040+10411041+ f, err := fullyResolvedRepo(r)10421042+ if err != nil {10431043+ log.Println("failed to get repo and knot", err)10441044+ return10451045+ }10461046+10471047+ if user.Did != pull.OwnerDid {10481048+ log.Println("unauthorized user")10491049+ w.WriteHeader(http.StatusUnauthorized)10501050+ return10511051+ }10521052+10531053+ patch := r.FormValue("patch")10541054+10551055+ if patch == "" {10561056+ s.pages.Notice(w, "resubmit-error", "Patch is empty.")10571057+ return10581058+ }10591059+10601060+ if patch == pull.LatestPatch() {10611061+ s.pages.Notice(w, "resubmit-error", "Patch is identical to previous submission.")10621062+ return10631063+ }10641064+10651065+ if !isPatchValid(patch) {10661066+ s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.")10671067+ return10681068+ }10691069+10701070+ tx, err := s.db.BeginTx(r.Context(), nil)10711071+ if err != nil {10721072+ log.Println("failed to start tx")10731073+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")10741074+ return10751075+ }10761076+ defer tx.Rollback()10771077+10781078+ err = db.ResubmitPull(tx, pull, patch, "")10791079+ if err != nil {10801080+ log.Println("failed to resubmit pull request", err)10811081+ s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")10821082+ return10831083+ }10841084+ client, _ := s.auth.AuthorizedClient(r)10851085+10861086+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)10871087+ if err != nil {10881088+ // failed to get record10891089+ s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")10901090+ return10911091+ }10921092+10931093+ _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{10941094+ Collection: tangled.RepoPullNSID,10951095+ Repo: user.Did,10961096+ Rkey: pull.Rkey,10971097+ SwapRecord: ex.Cid,10981098+ Record: &lexutil.LexiconTypeDecoder{10991099+ Val: &tangled.RepoPull{11001100+ Title: pull.Title,11011101+ PullId: int64(pull.PullId),11021102+ TargetRepo: string(f.RepoAt),11031103+ TargetBranch: pull.TargetBranch,11041104+ Patch: patch, // new patch11051105+ },11061106+ },11071107+ })11081108+ if err != nil {11091109+ log.Println("failed to update record", err)11101110+ s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")11111111+ return11121112+ }11131113+11141114+ if err = tx.Commit(); err != nil {11151115+ log.Println("failed to commit transaction", err)11161116+ s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")11171117+ return11181118+ }11191119+11201120+ s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))11211121+ return11221122+}11231123+11241124+func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {11251125+ user := s.auth.GetUser(r)11261126+11271127+ pull, ok := r.Context().Value("pull").(*db.Pull)11281128+ if !ok {11291129+ log.Println("failed to get pull")11301130+ s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")11311131+ return11321132+ }11331133+11341134+ f, err := fullyResolvedRepo(r)11351135+ if err != nil {11361136+ log.Println("failed to get repo and knot", err)11371137+ return11381138+ }11391139+11401140+ if user.Did != pull.OwnerDid {11411141+ log.Println("unauthorized user")11421142+ w.WriteHeader(http.StatusUnauthorized)11431143+ return11441144+ }11451145+11461146+ if !f.RepoInfo(s, user).Roles.IsPushAllowed() {11471147+ log.Println("unauthorized user")11481148+ w.WriteHeader(http.StatusUnauthorized)11491149+ return11501150+ }11511151+11521152+ ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)11531153+ if err != nil {11541154+ log.Printf("failed to create client for %s: %s", f.Knot, err)11551155+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11561156+ return11571157+ }11581158+11591159+ compareResp, err := ksClient.Compare(f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.PullSource.Branch)11601160+ if err != nil {11611161+ log.Printf("failed to compare branches: %s", err)11621162+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11631163+ return11641164+ }11651165+ defer compareResp.Body.Close()11661166+11671167+ switch compareResp.StatusCode {11681168+ case 404:11691169+ case 400:11701170+ s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")11711171+ return11721172+ }11731173+11741174+ respBody, err := io.ReadAll(compareResp.Body)11751175+ if err != nil {11761176+ log.Println("failed to compare across branches")11771177+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11781178+ return11791179+ }11801180+ defer compareResp.Body.Close()11811181+11821182+ var diffTreeResponse types.RepoDiffTreeResponse11831183+ err = json.Unmarshal(respBody, &diffTreeResponse)11841184+ if err != nil {11851185+ log.Println("failed to unmarshal diff tree response", err)11861186+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")11871187+ return11881188+ }11891189+11901190+ sourceRev := diffTreeResponse.DiffTree.Rev211911191+ patch := diffTreeResponse.DiffTree.Patch11921192+11931193+ if patch == "" {11941194+ s.pages.Notice(w, "resubmit-error", "Patch is empty.")11951195+ return11961196+ }11971197+11981198+ if patch == pull.LatestPatch() {11991199+ s.pages.Notice(w, "resubmit-error", "Patch is identical to previous submission.")12001200+ return12011201+ }12021202+12031203+ if !isPatchValid(patch) {12041204+ s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.")12051205+ return12061206+ }12071207+12081208+ if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {12091209+ s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")12101210+ return12111211+ }12121212+12131213+ tx, err := s.db.BeginTx(r.Context(), nil)12141214+ if err != nil {12151215+ log.Println("failed to start tx")12161216+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")12171217+ return12181218+ }12191219+ defer tx.Rollback()12201220+12211221+ err = db.ResubmitPull(tx, pull, patch, sourceRev)12221222+ if err != nil {12231223+ log.Println("failed to create pull request", err)12241224+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")12251225+ return12261226+ }12271227+ client, _ := s.auth.AuthorizedClient(r)12281228+12291229+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)12301230+ if err != nil {12311231+ // failed to get record12321232+ s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")12331233+ return12341234+ }12351235+12361236+ recordPullSource := &tangled.RepoPull_Source{12371237+ Branch: pull.PullSource.Branch,12381238+ }12391239+ _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{12401240+ Collection: tangled.RepoPullNSID,12411241+ Repo: user.Did,12421242+ Rkey: pull.Rkey,12431243+ SwapRecord: ex.Cid,12441244+ Record: &lexutil.LexiconTypeDecoder{12451245+ Val: &tangled.RepoPull{12461246+ Title: pull.Title,12471247+ PullId: int64(pull.PullId),12481248+ TargetRepo: string(f.RepoAt),12491249+ TargetBranch: pull.TargetBranch,12501250+ Patch: patch, // new patch12511251+ Source: recordPullSource,12521252+ },12531253+ },12541254+ })12551255+ if err != nil {12561256+ log.Println("failed to update record", err)12571257+ s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")12581258+ return12591259+ }12601260+12611261+ if err = tx.Commit(); err != nil {12621262+ log.Println("failed to commit transaction", err)12631263+ s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")12641264+ return12651265+ }12661266+12671267+ s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))12681268+ return12691269+}12701270+12711271+func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {12721272+ user := s.auth.GetUser(r)12731273+12741274+ pull, ok := r.Context().Value("pull").(*db.Pull)12751275+ if !ok {12761276+ log.Println("failed to get pull")12771277+ s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")12781278+ return12791279+ }12801280+12811281+ f, err := fullyResolvedRepo(r)12821282+ if err != nil {12831283+ log.Println("failed to get repo and knot", err)12841284+ return12851285+ }12861286+12871287+ if user.Did != pull.OwnerDid {12881288+ log.Println("unauthorized user")12891289+ w.WriteHeader(http.StatusUnauthorized)12901290+ return12911291+ }12921292+12931293+ forkRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String())12941294+ if err != nil {12951295+ log.Println("failed to get source repo", err)12961296+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")12971297+ return12981298+ }12991299+13001300+ // extract patch by performing compare13011301+ ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev)13021302+ if err != nil {13031303+ log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)13041304+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13051305+ return13061306+ }13071307+13081308+ secret, err := db.GetRegistrationKey(s.db, forkRepo.Knot)13091309+ if err != nil {13101310+ log.Printf("failed to get registration key for %s: %s", forkRepo.Knot, err)13111311+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13121312+ return13131313+ }13141314+ // update the hidden tracking branch to latest13151315+ signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev)13161316+ if err != nil {13171317+ log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)13181318+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13191319+ return13201320+ }13211321+ resp, err := signedClient.NewHiddenRef(forkRepo.Did, forkRepo.Name, pull.PullSource.Branch, pull.TargetBranch)13221322+ if err != nil || resp.StatusCode != http.StatusNoContent {13231323+ log.Printf("failed to update tracking branch: %s", err)13241324+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13251325+ return13261326+ }13271327+13281328+ hiddenRef := url.QueryEscape(fmt.Sprintf("hidden/%s/%s", pull.PullSource.Branch, pull.TargetBranch))13291329+ compareResp, err := ksClient.Compare(forkRepo.Did, forkRepo.Name, hiddenRef, pull.PullSource.Branch)13301330+ if err != nil {13311331+ log.Printf("failed to compare branches: %s", err)13321332+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13331333+ return13341334+ }13351335+ defer compareResp.Body.Close()13361336+13371337+ switch compareResp.StatusCode {13381338+ case 404:13391339+ case 400:13401340+ s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.")13411341+ return13421342+ }13431343+13441344+ respBody, err := io.ReadAll(compareResp.Body)13451345+ if err != nil {13461346+ log.Println("failed to compare across branches")13471347+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13481348+ return13491349+ }13501350+ defer compareResp.Body.Close()13511351+13521352+ var diffTreeResponse types.RepoDiffTreeResponse13531353+ err = json.Unmarshal(respBody, &diffTreeResponse)13541354+ if err != nil {13551355+ log.Println("failed to unmarshal diff tree response", err)13561356+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")13571357+ return13581358+ }13591359+13601360+ sourceRev := diffTreeResponse.DiffTree.Rev213611361+ patch := diffTreeResponse.DiffTree.Patch13621362+13631363+ if patch == "" {13641364+ s.pages.Notice(w, "resubmit-error", "Patch is empty.")13651365+ return13661366+ }13671367+13681368+ if patch == pull.LatestPatch() {13691369+ s.pages.Notice(w, "resubmit-error", "Patch is identical to previous submission.")13701370+ return13711371+ }13721372+13731373+ if !isPatchValid(patch) {13741374+ s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.")13751375+ return13761376+ }13771377+13781378+ if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev {13791379+ s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.")13801380+ return13811381+ }13821382+13831383+ tx, err := s.db.BeginTx(r.Context(), nil)13841384+ if err != nil {13851385+ log.Println("failed to start tx")13861386+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")13871387+ return13881388+ }13891389+ defer tx.Rollback()13901390+13911391+ err = db.ResubmitPull(tx, pull, patch, sourceRev)13921392+ if err != nil {13931393+ log.Println("failed to create pull request", err)13941394+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")13951395+ return13961396+ }13971397+ client, _ := s.auth.AuthorizedClient(r)13981398+13991399+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)14001400+ if err != nil {14011401+ // failed to get record14021402+ s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")14031403+ return14041404+ }14051405+14061406+ repoAt := pull.PullSource.RepoAt.String()14071407+ recordPullSource := &tangled.RepoPull_Source{14081408+ Branch: pull.PullSource.Branch,14091409+ Repo: &repoAt,14101410+ }14111411+ _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{14121412+ Collection: tangled.RepoPullNSID,14131413+ Repo: user.Did,14141414+ Rkey: pull.Rkey,14151415+ SwapRecord: ex.Cid,14161416+ Record: &lexutil.LexiconTypeDecoder{14171417+ Val: &tangled.RepoPull{14181418+ Title: pull.Title,14191419+ PullId: int64(pull.PullId),14201420+ TargetRepo: string(f.RepoAt),14211421+ TargetBranch: pull.TargetBranch,14221422+ Patch: patch, // new patch14231423+ Source: recordPullSource,14241424+ },14251425+ },14261426+ })14271427+ if err != nil {14281428+ log.Println("failed to update record", err)14291429+ s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.")14301430+ return14311431+ }14321432+14331433+ if err = tx.Commit(); err != nil {14341434+ log.Println("failed to commit transaction", err)14351435+ s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.")14361436+ return14371437+ }14381438+14391439+ s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))14401440+ return11931441}1194144211951443func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {