Monorepo for Tangled tangled.org

appview,knotserver: produce combined patch in comparisons

this is calculated by the knotserver in sh.tangled.repo.compare and
cached by the appview in pull submissions, this cannot be calculated on
the appview side with just the format-patch because this calculation
requires a git-index.

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li bd1f54a5 025f751c

verified
Changed files
+92 -58
appview
db
models
pulls
repo
knotserver
types
+9
appview/db/db.go
··· 954 954 return err 955 955 }) 956 956 957 + // knots may report the combined patch for a comparison, we can store that on the appview side 958 + // (but not on the pds record), because calculating the combined patch requires a git index 959 + runMigration(conn, "add-combined-column-submissions", func(tx *sql.Tx) error { 960 + _, err := tx.Exec(` 961 + alter table pull_submissions add column combined text; 962 + `) 963 + return err 964 + }) 965 + 957 966 return &DB{db}, nil 958 967 } 959 968
+18 -8
appview/db/pulls.go
··· 87 87 pull.ID = int(id) 88 88 89 89 _, err = tx.Exec(` 90 - insert into pull_submissions (pull_id, repo_at, round_number, patch, source_rev) 90 + insert into pull_submissions (pull_id, repo_at, round_number, patch, combined, source_rev) 91 91 values (?, ?, ?, ?, ?) 92 - `, pull.PullId, pull.RepoAt, 0, pull.Submissions[0].Patch, pull.Submissions[0].SourceRev) 92 + `, pull.PullId, pull.RepoAt, 0, pull.Submissions[0].Patch, pull.Submissions[0].Combined, pull.Submissions[0].SourceRev) 93 93 return err 94 94 } 95 95 ··· 218 218 inClause := strings.TrimSuffix(strings.Repeat("?, ", len(pulls)), ", ") 219 219 submissionsQuery := fmt.Sprintf(` 220 220 select 221 - id, pull_id, round_number, patch, created, source_rev 221 + id, pull_id, round_number, patch, combined, created, source_rev 222 222 from 223 223 pull_submissions 224 224 where ··· 243 243 244 244 for submissionsRows.Next() { 245 245 var s models.PullSubmission 246 - var sourceRev sql.NullString 246 + var sourceRev, combined sql.NullString 247 247 var createdAt string 248 248 err := submissionsRows.Scan( 249 249 &s.ID, 250 250 &s.PullId, 251 251 &s.RoundNumber, 252 252 &s.Patch, 253 + &combined, 253 254 &createdAt, 254 255 &sourceRev, 255 256 ) ··· 265 266 266 267 if sourceRev.Valid { 267 268 s.SourceRev = sourceRev.String 269 + } 270 + 271 + if combined.Valid { 272 + s.Combined = combined.String 268 273 } 269 274 270 275 if p, ok := pulls[s.PullId]; ok { ··· 412 417 413 418 submissionsQuery := ` 414 419 select 415 - id, pull_id, repo_at, round_number, patch, created, source_rev 420 + id, pull_id, repo_at, round_number, patch, combined, created, source_rev 416 421 from 417 422 pull_submissions 418 423 where ··· 429 434 for submissionsRows.Next() { 430 435 var submission models.PullSubmission 431 436 var submissionCreatedStr string 432 - var submissionSourceRev sql.NullString 437 + var submissionSourceRev, submissionCombined sql.NullString 433 438 err := submissionsRows.Scan( 434 439 &submission.ID, 435 440 &submission.PullId, 436 441 &submission.RepoAt, 437 442 &submission.RoundNumber, 438 443 &submission.Patch, 444 + &submissionCombined, 439 445 &submissionCreatedStr, 440 446 &submissionSourceRev, 441 447 ) ··· 451 457 452 458 if submissionSourceRev.Valid { 453 459 submission.SourceRev = submissionSourceRev.String 460 + } 461 + 462 + if submissionCombined.Valid { 463 + submission.Combined = submissionCombined.String 454 464 } 455 465 456 466 submissionsMap[submission.ID] = &submission ··· 674 684 return err 675 685 } 676 686 677 - func ResubmitPull(e Execer, pull *models.Pull, newPatch, sourceRev string) error { 687 + func ResubmitPull(e Execer, pull *models.Pull, newPatch, combined, sourceRev string) error { 678 688 newRoundNumber := len(pull.Submissions) 679 689 _, err := e.Exec(` 680 - insert into pull_submissions (pull_id, repo_at, round_number, patch, source_rev) 690 + insert into pull_submissions (pull_id, repo_at, round_number, patch, combined, source_rev) 681 691 values (?, ?, ?, ?, ?) 682 692 `, pull.PullId, pull.RepoAt, newRoundNumber, newPatch, sourceRev) 683 693
+9
appview/models/pull.go
··· 134 134 // content 135 135 RoundNumber int 136 136 Patch string 137 + Combined string 137 138 Comments []PullComment 138 139 SourceRev string // include the rev that was used to create this submission: only for branch/fork PRs 139 140 ··· 219 220 } 220 221 221 222 return patches 223 + } 224 + 225 + func (s PullSubmission) CombinedPatch() string { 226 + if s.Combined == "" { 227 + return s.Patch 228 + } 229 + 230 + return s.Combined 222 231 } 223 232 224 233 type Stack []*Pull
+23 -40
appview/pulls/pulls.go
··· 135 135 stack, _ := r.Context().Value("stack").(models.Stack) 136 136 abandonedPulls, _ := r.Context().Value("abandonedPulls").([]*models.Pull) 137 137 138 - totalIdents := 1 139 - for _, submission := range pull.Submissions { 140 - totalIdents += len(submission.Comments) 141 - } 142 - 143 - identsToResolve := make([]string, totalIdents) 144 - 145 - // populate idents 146 - identsToResolve[0] = pull.OwnerDid 147 - idx := 1 148 - for _, submission := range pull.Submissions { 149 - for _, comment := range submission.Comments { 150 - identsToResolve[idx] = comment.OwnerDid 151 - idx += 1 152 - } 153 - } 154 - 155 138 mergeCheckResponse := s.mergeCheck(r, f, pull, stack) 156 139 resubmitResult := pages.Unknown 157 140 if user != nil && user.Did == pull.OwnerDid { ··· 374 357 return 375 358 } 376 359 377 - patch := pull.Submissions[roundIdInt].Patch 360 + patch := pull.Submissions[roundIdInt].CombinedPatch() 378 361 diff := patchutil.AsNiceDiff(patch, pull.TargetBranch) 379 362 380 363 s.pages.RepoPullPatchPage(w, pages.RepoPullPatchParams{ ··· 425 408 return 426 409 } 427 410 428 - currentPatch, err := patchutil.AsDiff(pull.Submissions[roundIdInt].Patch) 411 + currentPatch, err := patchutil.AsDiff(pull.Submissions[roundIdInt].CombinedPatch()) 429 412 if err != nil { 430 413 log.Println("failed to interdiff; current patch malformed") 431 414 s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; current patch is invalid.") 432 415 return 433 416 } 434 417 435 - previousPatch, err := patchutil.AsDiff(pull.Submissions[roundIdInt-1].Patch) 418 + previousPatch, err := patchutil.AsDiff(pull.Submissions[roundIdInt-1].CombinedPatch()) 436 419 if err != nil { 437 420 log.Println("failed to interdiff; previous patch malformed") 438 421 s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; previous patch is invalid.") ··· 617 600 618 601 createdAt := time.Now().Format(time.RFC3339) 619 602 620 - pullAt, err := db.GetPullAt(s.db, f.RepoAt(), pull.PullId) 621 - if err != nil { 622 - log.Println("failed to get pull at", err) 623 - s.pages.Notice(w, "pull-comment", "Failed to create comment.") 624 - return 625 - } 626 - 627 603 client, err := s.oauth.AuthorizedClient(r) 628 604 if err != nil { 629 605 log.Println("failed to get authorized client", err) ··· 636 612 Rkey: tid.TID(), 637 613 Record: &lexutil.LexiconTypeDecoder{ 638 614 Val: &tangled.RepoPullComment{ 639 - Pull: string(pullAt), 615 + Pull: pull.PullAt().String(), 640 616 Body: body, 641 617 CreatedAt: createdAt, 642 618 }, ··· 884 860 } 885 861 886 862 sourceRev := comparison.Rev2 887 - patch := comparison.Patch 863 + patch := comparison.FormatPatchRaw 864 + combined := comparison.CombinedPatchRaw 888 865 889 866 if !patchutil.IsPatchValid(patch) { 890 867 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") ··· 899 876 Sha: comparison.Rev2, 900 877 } 901 878 902 - s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource, isStacked) 879 + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked) 903 880 } 904 881 905 882 func (s *Pulls) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *reporesolver.ResolvedRepo, user *oauth.User, title, body, targetBranch, patch string, isStacked bool) { ··· 908 885 return 909 886 } 910 887 911 - s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil, isStacked) 888 + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", "", nil, nil, isStacked) 912 889 } 913 890 914 891 func (s *Pulls) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *reporesolver.ResolvedRepo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string, isStacked bool) { ··· 991 968 } 992 969 993 970 sourceRev := comparison.Rev2 994 - patch := comparison.Patch 971 + patch := comparison.FormatPatchRaw 972 + combined := comparison.CombinedPatchRaw 995 973 996 974 if !patchutil.IsPatchValid(patch) { 997 975 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") ··· 1011 989 Sha: sourceRev, 1012 990 } 1013 991 1014 - s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource, isStacked) 992 + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked) 1015 993 } 1016 994 1017 995 func (s *Pulls) createPullRequest( ··· 1021 999 user *oauth.User, 1022 1000 title, body, targetBranch string, 1023 1001 patch string, 1002 + combined string, 1024 1003 sourceRev string, 1025 1004 pullSource *models.PullSource, 1026 1005 recordPullSource *tangled.RepoPull_Source, ··· 1076 1055 rkey := tid.TID() 1077 1056 initialSubmission := models.PullSubmission{ 1078 1057 Patch: patch, 1058 + Combined: combined, 1079 1059 SourceRev: sourceRev, 1080 1060 } 1081 1061 pull := &models.Pull{ ··· 1504 1484 1505 1485 patch := r.FormValue("patch") 1506 1486 1507 - s.resubmitPullHelper(w, r, f, user, pull, patch, "") 1487 + s.resubmitPullHelper(w, r, f, user, pull, patch, "", "") 1508 1488 } 1509 1489 1510 1490 func (s *Pulls) resubmitBranch(w http.ResponseWriter, r *http.Request) { ··· 1565 1545 } 1566 1546 1567 1547 sourceRev := comparison.Rev2 1568 - patch := comparison.Patch 1548 + patch := comparison.FormatPatchRaw 1549 + combined := comparison.CombinedPatchRaw 1569 1550 1570 - s.resubmitPullHelper(w, r, f, user, pull, patch, sourceRev) 1551 + s.resubmitPullHelper(w, r, f, user, pull, patch, combined, sourceRev) 1571 1552 } 1572 1553 1573 1554 func (s *Pulls) resubmitFork(w http.ResponseWriter, r *http.Request) { ··· 1660 1641 comparison := forkComparison 1661 1642 1662 1643 sourceRev := comparison.Rev2 1663 - patch := comparison.Patch 1644 + patch := comparison.FormatPatchRaw 1645 + combined := comparison.CombinedPatchRaw 1664 1646 1665 - s.resubmitPullHelper(w, r, f, user, pull, patch, sourceRev) 1647 + s.resubmitPullHelper(w, r, f, user, pull, patch, combined, sourceRev) 1666 1648 } 1667 1649 1668 1650 // validate a resubmission against a pull request ··· 1689 1671 user *oauth.User, 1690 1672 pull *models.Pull, 1691 1673 patch string, 1674 + combined string, 1692 1675 sourceRev string, 1693 1676 ) { 1694 1677 if pull.IsStacked() { ··· 1718 1701 } 1719 1702 defer tx.Rollback() 1720 1703 1721 - err = db.ResubmitPull(tx, pull, patch, sourceRev) 1704 + err = db.ResubmitPull(tx, pull, patch, combined, sourceRev) 1722 1705 if err != nil { 1723 1706 log.Println("failed to create pull request", err) 1724 1707 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") ··· 1933 1916 submission := np.Submissions[np.LastRoundNumber()] 1934 1917 1935 1918 // resubmit the old pull 1936 - err := db.ResubmitPull(tx, op, submission.Patch, submission.SourceRev) 1919 + err := db.ResubmitPull(tx, op, submission.Patch, submission.Combined, submission.SourceRev) 1937 1920 1938 1921 if err != nil { 1939 1922 log.Println("failed to update pull", err, op.PullId)
+6 -1
appview/repo/repo.go
··· 2503 2503 return 2504 2504 } 2505 2505 2506 - diff := patchutil.AsNiceDiff(formatPatch.Patch, base) 2506 + var diff types.NiceDiff 2507 + if formatPatch.CombinedPatchRaw != "" { 2508 + diff = patchutil.AsNiceDiff(formatPatch.CombinedPatchRaw, base) 2509 + } else { 2510 + diff = patchutil.AsNiceDiff(formatPatch.FormatPatchRaw, base) 2511 + } 2507 2512 2508 2513 repoinfo := f.RepoInfo(user) 2509 2514
+20 -4
knotserver/xrpc/repo_compare.go
··· 4 4 "fmt" 5 5 "net/http" 6 6 7 + "github.com/bluekeyes/go-gitdiff/gitdiff" 7 8 "tangled.org/core/knotserver/git" 8 9 "tangled.org/core/types" 9 10 xrpcerr "tangled.org/core/xrpc/errors" ··· 71 72 return 72 73 } 73 74 75 + var combinedPatch []*gitdiff.File 76 + var combinedPatchRaw string 77 + // we need the combined patch 78 + if len(formatPatch) >= 2 { 79 + diffTree, err := gr.DiffTree(commit1, commit2) 80 + if err != nil { 81 + x.Logger.Error("error comparing revisions", "msg", err.Error()) 82 + } else { 83 + combinedPatch = diffTree.Diff 84 + combinedPatchRaw = diffTree.Patch 85 + } 86 + } 87 + 74 88 response := types.RepoFormatPatchResponse{ 75 - Rev1: commit1.Hash.String(), 76 - Rev2: commit2.Hash.String(), 77 - FormatPatch: formatPatch, 78 - Patch: rawPatch, 89 + Rev1: commit1.Hash.String(), 90 + Rev2: commit2.Hash.String(), 91 + FormatPatch: formatPatch, 92 + FormatPatchRaw: rawPatch, 93 + CombinedPatch: combinedPatch, 94 + CombinedPatchRaw: combinedPatchRaw, 79 95 } 80 96 81 97 writeJson(w, response)
+7 -5
types/repo.go
··· 1 1 package types 2 2 3 3 import ( 4 + "github.com/bluekeyes/go-gitdiff/gitdiff" 4 5 "github.com/go-git/go-git/v5/plumbing/object" 5 6 ) 6 7 ··· 33 34 } 34 35 35 36 type RepoFormatPatchResponse struct { 36 - Rev1 string `json:"rev1,omitempty"` 37 - Rev2 string `json:"rev2,omitempty"` 38 - FormatPatch []FormatPatch `json:"format_patch,omitempty"` 39 - MergeBase string `json:"merge_base,omitempty"` // deprecated 40 - Patch string `json:"patch,omitempty"` 37 + Rev1 string `json:"rev1,omitempty"` 38 + Rev2 string `json:"rev2,omitempty"` 39 + FormatPatch []FormatPatch `json:"format_patch,omitempty"` 40 + FormatPatchRaw string `json:"patch,omitempty"` 41 + CombinedPatch []*gitdiff.File `json:"combined_patch,omitempty"` 42 + CombinedPatchRaw string `json:"combined_patch_raw,omitempty"` 41 43 } 42 44 43 45 type RepoTreeResponse struct {