forked from tangled.org/core
this repo has no description

add resubmit hints

unless a branch is updated, resubmit will remain disabled; and when
there are changes added to the branch, a hint is supplied.

Changed files
+230 -52
appview
db
pages
templates
fragments
repo
pulls
state
knotserver
types
+2 -1
appview/db/db.go
··· 264 return err 265 }) 266 267 - runMigration(db, "add-source-info-to-pulls", func(tx *sql.Tx) error { 268 _, err := tx.Exec(` 269 alter table pulls add column source_branch text; 270 alter table pulls add column source_repo_at text; 271 `) 272 return err 273 })
··· 264 return err 265 }) 266 267 + runMigration(db, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error { 268 _, err := tx.Exec(` 269 alter table pulls add column source_branch text; 270 alter table pulls add column source_repo_at text; 271 + alter table pull_submissions add column source_rev text; 272 `) 273 return err 274 })
+15 -8
appview/db/pulls.go
··· 83 RoundNumber int 84 Patch string 85 Comments []PullComment 86 87 // meta 88 Created time.Time ··· 222 } 223 224 _, err = tx.Exec(` 225 - insert into pull_submissions (pull_id, repo_at, round_number, patch) 226 - values (?, ?, ?, ?) 227 - `, pull.PullId, pull.RepoAt, 0, pull.Submissions[0].Patch) 228 if err != nil { 229 return err 230 } ··· 395 396 submissionsQuery := ` 397 select 398 - id, pull_id, repo_at, round_number, patch, created 399 from 400 pull_submissions 401 where ··· 412 for submissionsRows.Next() { 413 var submission PullSubmission 414 var submissionCreatedStr string 415 err := submissionsRows.Scan( 416 &submission.ID, 417 &submission.PullId, ··· 419 &submission.RoundNumber, 420 &submission.Patch, 421 &submissionCreatedStr, 422 ) 423 if err != nil { 424 return nil, err ··· 430 } 431 submission.Created = submissionCreatedTime 432 433 submissionsMap[submission.ID] = &submission 434 } 435 if err = submissionsRows.Close(); err != nil { ··· 604 return err 605 } 606 607 - func ResubmitPull(e Execer, pull *Pull, newPatch string) error { 608 newRoundNumber := len(pull.Submissions) 609 _, err := e.Exec(` 610 - insert into pull_submissions (pull_id, repo_at, round_number, patch) 611 - values (?, ?, ?, ?) 612 - `, pull.PullId, pull.RepoAt, newRoundNumber, newPatch) 613 614 return err 615 }
··· 83 RoundNumber int 84 Patch string 85 Comments []PullComment 86 + SourceRev string // include the rev that was used to create this submission: only for branch PRs 87 88 // meta 89 Created time.Time ··· 223 } 224 225 _, err = tx.Exec(` 226 + insert into pull_submissions (pull_id, repo_at, round_number, patch, source_rev) 227 + values (?, ?, ?, ?, ?) 228 + `, pull.PullId, pull.RepoAt, 0, pull.Submissions[0].Patch, pull.Submissions[0].SourceRev) 229 if err != nil { 230 return err 231 } ··· 396 397 submissionsQuery := ` 398 select 399 + id, pull_id, repo_at, round_number, patch, created, source_rev 400 from 401 pull_submissions 402 where ··· 413 for submissionsRows.Next() { 414 var submission PullSubmission 415 var submissionCreatedStr string 416 + var submissionSourceRev sql.NullString 417 err := submissionsRows.Scan( 418 &submission.ID, 419 &submission.PullId, ··· 421 &submission.RoundNumber, 422 &submission.Patch, 423 &submissionCreatedStr, 424 + &submissionSourceRev, 425 ) 426 if err != nil { 427 return nil, err ··· 433 } 434 submission.Created = submissionCreatedTime 435 436 + if submissionSourceRev.Valid { 437 + submission.SourceRev = submissionSourceRev.String 438 + } 439 + 440 submissionsMap[submission.ID] = &submission 441 } 442 if err = submissionsRows.Close(); err != nil { ··· 611 return err 612 } 613 614 + func ResubmitPull(e Execer, pull *Pull, newPatch, sourceRev string) error { 615 newRoundNumber := len(pull.Submissions) 616 _, err := e.Exec(` 617 + insert into pull_submissions (pull_id, repo_at, round_number, patch, source_rev) 618 + values (?, ?, ?, ?, ?) 619 + `, pull.PullId, pull.RepoAt, newRoundNumber, newPatch, sourceRev) 620 621 return err 622 }
+31 -11
appview/pages/pages.go
··· 586 return p.executeRepo("repo/pulls/pulls", w, params) 587 } 588 589 type RepoSinglePullParams struct { 590 - LoggedInUser *auth.User 591 - RepoInfo RepoInfo 592 - Active string 593 - DidHandleMap map[string]string 594 - Pull *db.Pull 595 - MergeCheck types.MergeCheckResponse 596 } 597 598 func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error { ··· 627 } 628 629 type PullActionsParams struct { 630 - LoggedInUser *auth.User 631 - RepoInfo RepoInfo 632 - Pull *db.Pull 633 - RoundNumber int 634 - MergeCheck types.MergeCheckResponse 635 } 636 637 func (p *Pages) PullActionsFragment(w io.Writer, params PullActionsParams) error {
··· 586 return p.executeRepo("repo/pulls/pulls", w, params) 587 } 588 589 + type ResubmitResult uint64 590 + 591 + const ( 592 + ShouldResubmit ResubmitResult = iota 593 + ShouldNotResubmit 594 + Unknown 595 + ) 596 + 597 + func (r ResubmitResult) Yes() bool { 598 + return r == ShouldResubmit 599 + } 600 + func (r ResubmitResult) No() bool { 601 + return r == ShouldNotResubmit 602 + } 603 + func (r ResubmitResult) Unknown() bool { 604 + return r == Unknown 605 + } 606 + 607 type RepoSinglePullParams struct { 608 + LoggedInUser *auth.User 609 + RepoInfo RepoInfo 610 + Active string 611 + DidHandleMap map[string]string 612 + Pull *db.Pull 613 + MergeCheck types.MergeCheckResponse 614 + ResubmitCheck ResubmitResult 615 } 616 617 func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error { ··· 646 } 647 648 type PullActionsParams struct { 649 + LoggedInUser *auth.User 650 + RepoInfo RepoInfo 651 + Pull *db.Pull 652 + RoundNumber int 653 + MergeCheck types.MergeCheckResponse 654 + ResubmitCheck ResubmitResult 655 } 656 657 func (p *Pages) PullActionsFragment(w io.Writer, params PullActionsParams) error {
+13 -1
appview/pages/templates/fragments/pullActions.html
··· 10 {{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }} 11 {{ $isLastRound := eq $roundNumber $lastIdx }} 12 {{ $isSameRepoBranch := .Pull.IsSameRepoBranch }} 13 <div class="relative w-fit"> 14 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> 15 <div id="actions-{{$roundNumber}}" class="flex flex-wrap gap-2"> ··· 37 {{ end }} 38 39 {{ if and $isPullAuthor $isOpen $isLastRound }} 40 <button id="resubmitBtn" 41 {{ if $isSameRepoBranch }} 42 hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit" ··· 47 {{ end }} 48 49 hx-disabled-elt="#resubmitBtn" 50 - class="btn p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"> 51 {{ i "rotate-ccw" "w-4 h-4" }} 52 <span>resubmit</span> 53 </button>
··· 10 {{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }} 11 {{ $isLastRound := eq $roundNumber $lastIdx }} 12 {{ $isSameRepoBranch := .Pull.IsSameRepoBranch }} 13 + {{ $isUpToDate := .ResubmitCheck.No }} 14 <div class="relative w-fit"> 15 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> 16 <div id="actions-{{$roundNumber}}" class="flex flex-wrap gap-2"> ··· 38 {{ end }} 39 40 {{ if and $isPullAuthor $isOpen $isLastRound }} 41 + {{ $disabled := "" }} 42 + {{ if $isUpToDate }} 43 + {{ $disabled = "disabled" }} 44 + {{ end }} 45 <button id="resubmitBtn" 46 {{ if $isSameRepoBranch }} 47 hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit" ··· 52 {{ end }} 53 54 hx-disabled-elt="#resubmitBtn" 55 + class="btn p-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed" {{ $disabled }} 56 + 57 + {{ if $disabled }} 58 + title="Update this branch to resubmit this pull request" 59 + {{ else }} 60 + title="Resubmit this pull request" 61 + {{ end }} 62 + > 63 {{ i "rotate-ccw" "w-4 h-4" }} 64 <span>resubmit</span> 65 </button>
+14 -1
appview/pages/templates/repo/pulls/pull.html
··· 135 136 {{ if eq $lastIdx .RoundNumber }} 137 {{ block "mergeStatus" $ }} {{ end }} 138 {{ end }} 139 140 {{ if $.LoggedInUser }} 141 - {{ template "fragments/pullActions" (dict "LoggedInUser" $.LoggedInUser "Pull" $.Pull "RepoInfo" $.RepoInfo "RoundNumber" .RoundNumber "MergeCheck" $.MergeCheck) }} 142 {{ else }} 143 <div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm px-6 py-4 w-fit dark:text-white"> 144 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> ··· 209 </div> 210 {{ end }} 211 {{ end }}
··· 135 136 {{ if eq $lastIdx .RoundNumber }} 137 {{ block "mergeStatus" $ }} {{ end }} 138 + {{ block "resubmitStatus" $ }} {{ end }} 139 {{ end }} 140 141 {{ if $.LoggedInUser }} 142 + {{ template "fragments/pullActions" (dict "LoggedInUser" $.LoggedInUser "Pull" $.Pull "RepoInfo" $.RepoInfo "RoundNumber" .RoundNumber "MergeCheck" $.MergeCheck "ResubmitCheck" $.ResubmitCheck) }} 143 {{ else }} 144 <div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm px-6 py-4 w-fit dark:text-white"> 145 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> ··· 210 </div> 211 {{ end }} 212 {{ end }} 213 + 214 + {{ define "resubmitStatus" }} 215 + {{ if .ResubmitCheck.Yes }} 216 + <div class="bg-amber-50 dark:bg-amber-900 border border-amber-500 rounded drop-shadow-sm px-6 py-2 relative w-fit"> 217 + <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> 218 + <div class="flex items-center gap-2 text-amber-500 dark:text-amber-300"> 219 + {{ i "triangle-alert" "w-4 h-4" }} 220 + <span class="font-medium">this branch has been updated, consider resubmitting</span> 221 + </div> 222 + </div> 223 + {{ end }} 224 + {{ end }}
+91 -28
appview/state/pull.go
··· 50 } 51 52 mergeCheckResponse := s.mergeCheck(f, pull) 53 54 s.pages.PullActionsFragment(w, pages.PullActionsParams{ 55 - LoggedInUser: user, 56 - RepoInfo: f.RepoInfo(s, user), 57 - Pull: pull, 58 - RoundNumber: roundNumber, 59 - MergeCheck: mergeCheckResponse, 60 }) 61 return 62 } ··· 105 } 106 107 mergeCheckResponse := s.mergeCheck(f, pull) 108 109 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 110 - LoggedInUser: user, 111 - RepoInfo: f.RepoInfo(s, user), 112 - DidHandleMap: didHandleMap, 113 - Pull: pull, 114 - MergeCheck: mergeCheckResponse, 115 }) 116 } 117 ··· 175 return mergeCheckResponse 176 } 177 178 func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) { 179 user := s.auth.GetUser(r) 180 f, err := fullyResolvedRepo(r) ··· 457 sourceBranch := r.FormValue("sourceBranch") 458 patch := r.FormValue("patch") 459 460 - if patch == "" { 461 - if isPushAllowed && sourceBranch == "" { 462 - s.pages.Notice(w, "pull", "Neither source branch nor patch supplied.") 463 - return 464 - } 465 - s.pages.Notice(w, "pull", "Patch is empty.") 466 return 467 } 468 469 - if patch != "" && sourceBranch != "" { 470 s.pages.Notice(w, "pull", "Cannot select both patch and source branch.") 471 return 472 } ··· 477 } 478 479 // TODO: check if knot has this capability 480 var pullSource *db.PullSource 481 - if sourceBranch != "" && isPushAllowed { 482 pullSource = &db.PullSource{ 483 Branch: sourceBranch, 484 } 485 // generate a patch using /compare 486 ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) 487 if err != nil { ··· 489 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 490 return 491 } 492 - 493 - log.Println(targetBranch, sourceBranch) 494 495 resp, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch) 496 switch resp.StatusCode { ··· 510 err = json.Unmarshal(respBody, &diffTreeResponse) 511 if err != nil { 512 log.Println("failed to unmarshal diff tree response", err) 513 - log.Println(string(respBody)) 514 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 515 } 516 517 patch = diffTreeResponse.DiffTree.Patch 518 } 519 520 - log.Println(patch) 521 - 522 // Validate patch format 523 if !isPatchValid(patch) { 524 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") ··· 535 536 rkey := s.TID() 537 initialSubmission := db.PullSubmission{ 538 - Patch: patch, 539 } 540 err = db.NewPull(tx, &db.Pull{ 541 Title: title, ··· 573 TargetRepo: string(f.RepoAt), 574 TargetBranch: targetBranch, 575 Patch: patch, 576 }, 577 }, 578 }) ··· 613 return 614 case http.MethodPost: 615 patch := r.FormValue("patch") 616 617 // this pull is a branch based pull 618 isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed() 619 if pull.IsSameRepoBranch() && isPushAllowed { 620 sourceBranch := pull.PullSource.Branch 621 targetBranch := pull.TargetBranch 622 // extract patch by performing compare 623 ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) 624 if err != nil { ··· 627 return 628 } 629 630 - log.Println(targetBranch, sourceBranch) 631 - 632 resp, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch) 633 switch resp.StatusCode { 634 case 404: ··· 647 err = json.Unmarshal(respBody, &diffTreeResponse) 648 if err != nil { 649 log.Println("failed to unmarshal diff tree response", err) 650 - log.Println(string(respBody)) 651 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 652 } 653 654 patch = diffTreeResponse.DiffTree.Patch 655 } 656 ··· 664 return 665 } 666 667 // Validate patch format 668 if !isPatchValid(patch) { 669 s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.") ··· 678 } 679 defer tx.Rollback() 680 681 - err = db.ResubmitPull(tx, pull, patch) 682 if err != nil { 683 log.Println("failed to create pull request", err) 684 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") ··· 705 TargetRepo: string(f.RepoAt), 706 TargetBranch: pull.TargetBranch, 707 Patch: patch, // new patch 708 }, 709 }, 710 })
··· 50 } 51 52 mergeCheckResponse := s.mergeCheck(f, pull) 53 + var resubmitResult pages.ResubmitResult 54 + if user.Did == pull.OwnerDid { 55 + resubmitResult = s.resubmitCheck(f, pull) 56 + } 57 58 s.pages.PullActionsFragment(w, pages.PullActionsParams{ 59 + LoggedInUser: user, 60 + RepoInfo: f.RepoInfo(s, user), 61 + Pull: pull, 62 + RoundNumber: roundNumber, 63 + MergeCheck: mergeCheckResponse, 64 + ResubmitCheck: resubmitResult, 65 }) 66 return 67 } ··· 110 } 111 112 mergeCheckResponse := s.mergeCheck(f, pull) 113 + var resubmitResult pages.ResubmitResult 114 + if user.Did == pull.OwnerDid { 115 + resubmitResult = s.resubmitCheck(f, pull) 116 + } 117 118 s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ 119 + LoggedInUser: user, 120 + RepoInfo: f.RepoInfo(s, user), 121 + DidHandleMap: didHandleMap, 122 + Pull: pull, 123 + MergeCheck: mergeCheckResponse, 124 + ResubmitCheck: resubmitResult, 125 }) 126 } 127 ··· 185 return mergeCheckResponse 186 } 187 188 + func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult { 189 + if pull.State == db.PullMerged { 190 + return pages.Unknown 191 + } 192 + 193 + if pull.PullSource == nil { 194 + return pages.Unknown 195 + } 196 + 197 + us, err := NewUnsignedClient(f.Knot, s.config.Dev) 198 + if err != nil { 199 + log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err) 200 + return pages.Unknown 201 + } 202 + 203 + resp, err := us.Branch(f.OwnerDid(), f.RepoName, pull.PullSource.Branch) 204 + if err != nil { 205 + log.Println("failed to reach knotserver", err) 206 + return pages.Unknown 207 + } 208 + 209 + body, err := io.ReadAll(resp.Body) 210 + if err != nil { 211 + log.Printf("Error reading response body: %v", err) 212 + return pages.Unknown 213 + } 214 + 215 + var result types.RepoBranchResponse 216 + err = json.Unmarshal(body, &result) 217 + if err != nil { 218 + log.Println("failed to parse response:", err) 219 + return pages.Unknown 220 + } 221 + 222 + if pull.Submissions[pull.LastRoundNumber()].SourceRev != result.Branch.Hash { 223 + log.Println(pull.Submissions[pull.LastRoundNumber()].SourceRev, result.Branch.Hash) 224 + return pages.ShouldResubmit 225 + } else { 226 + return pages.ShouldNotResubmit 227 + } 228 + } 229 + 230 func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) { 231 user := s.auth.GetUser(r) 232 f, err := fullyResolvedRepo(r) ··· 509 sourceBranch := r.FormValue("sourceBranch") 510 patch := r.FormValue("patch") 511 512 + isBranchBased := isPushAllowed && (sourceBranch != "") 513 + isPatchBased := patch != "" 514 + 515 + if !isBranchBased && !isPatchBased { 516 + s.pages.Notice(w, "pull", "Neither source branch nor patch supplied.") 517 return 518 } 519 520 + if isBranchBased && isPatchBased { 521 s.pages.Notice(w, "pull", "Cannot select both patch and source branch.") 522 return 523 } ··· 528 } 529 530 // TODO: check if knot has this capability 531 + var sourceRev string 532 var pullSource *db.PullSource 533 + var recordPullSource *tangled.RepoPull_Source 534 + if isBranchBased { 535 pullSource = &db.PullSource{ 536 Branch: sourceBranch, 537 } 538 + recordPullSource = &tangled.RepoPull_Source{ 539 + Branch: sourceBranch, 540 + } 541 // generate a patch using /compare 542 ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) 543 if err != nil { ··· 545 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 546 return 547 } 548 549 resp, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch) 550 switch resp.StatusCode { ··· 564 err = json.Unmarshal(respBody, &diffTreeResponse) 565 if err != nil { 566 log.Println("failed to unmarshal diff tree response", err) 567 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 568 } 569 570 + sourceRev = diffTreeResponse.DiffTree.Rev2 571 patch = diffTreeResponse.DiffTree.Patch 572 } 573 574 // Validate patch format 575 if !isPatchValid(patch) { 576 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") ··· 587 588 rkey := s.TID() 589 initialSubmission := db.PullSubmission{ 590 + Patch: patch, 591 + SourceRev: sourceRev, 592 } 593 err = db.NewPull(tx, &db.Pull{ 594 Title: title, ··· 626 TargetRepo: string(f.RepoAt), 627 TargetBranch: targetBranch, 628 Patch: patch, 629 + Source: recordPullSource, 630 }, 631 }, 632 }) ··· 667 return 668 case http.MethodPost: 669 patch := r.FormValue("patch") 670 + var sourceRev string 671 + var recordPullSource *tangled.RepoPull_Source 672 673 // this pull is a branch based pull 674 isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed() 675 if pull.IsSameRepoBranch() && isPushAllowed { 676 sourceBranch := pull.PullSource.Branch 677 targetBranch := pull.TargetBranch 678 + recordPullSource = &tangled.RepoPull_Source{ 679 + Branch: sourceBranch, 680 + } 681 // extract patch by performing compare 682 ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) 683 if err != nil { ··· 686 return 687 } 688 689 resp, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch) 690 switch resp.StatusCode { 691 case 404: ··· 704 err = json.Unmarshal(respBody, &diffTreeResponse) 705 if err != nil { 706 log.Println("failed to unmarshal diff tree response", err) 707 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") 708 } 709 710 + sourceRev = diffTreeResponse.DiffTree.Rev2 711 patch = diffTreeResponse.DiffTree.Patch 712 } 713 ··· 721 return 722 } 723 724 + if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev { 725 + s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.") 726 + return 727 + } 728 + 729 // Validate patch format 730 if !isPatchValid(patch) { 731 s.pages.Notice(w, "resubmit-error", "Invalid patch format. Please provide a valid diff.") ··· 740 } 741 defer tx.Rollback() 742 743 + err = db.ResubmitPull(tx, pull, patch, sourceRev) 744 if err != nil { 745 log.Println("failed to create pull request", err) 746 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") ··· 767 TargetRepo: string(f.RepoAt), 768 TargetBranch: pull.TargetBranch, 769 Patch: patch, // new patch 770 + Source: recordPullSource, 771 }, 772 }, 773 })
+15
appview/state/signer.go
··· 287 return us.client.Do(req) 288 } 289 290 func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*http.Response, error) { 291 const ( 292 Method = "GET"
··· 287 return us.client.Do(req) 288 } 289 290 + func (us *UnsignedClient) Branch(ownerDid, repoName, branch string) (*http.Response, error) { 291 + const ( 292 + Method = "GET" 293 + ) 294 + 295 + endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, branch) 296 + 297 + req, err := us.newRequest(Method, endpoint, nil) 298 + if err != nil { 299 + return nil, err 300 + } 301 + 302 + return us.client.Do(req) 303 + } 304 + 305 func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*http.Response, error) { 306 const ( 307 Method = "GET"
-2
knotserver/git/diff.go
··· 97 return nil, fmt.Errorf("Invalid revision: %s", rev2) 98 } 99 100 - log.Println(commit1, commit2) 101 - 102 tree1, err := commit1.Tree() 103 if err != nil { 104 return nil, err
··· 97 return nil, fmt.Errorf("Invalid revision: %s", rev2) 98 } 99 100 tree1, err := commit1.Tree() 101 if err != nil { 102 return nil, err
+13
knotserver/git/git.go
··· 238 return branches, nil 239 } 240 241 func (g *GitRepo) SetDefaultBranch(branch string) error { 242 ref := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.NewBranchReferenceName(branch)) 243 return g.r.Storer.SetReference(ref)
··· 238 return branches, nil 239 } 240 241 + func (g *GitRepo) Branch(name string) (*plumbing.Reference, error) { 242 + ref, err := g.r.Reference(plumbing.NewBranchReferenceName(name), false) 243 + if err != nil { 244 + return nil, fmt.Errorf("branch: %w", err) 245 + } 246 + 247 + if !ref.Name().IsBranch() { 248 + return nil, fmt.Errorf("branch: %s is not a branch", ref.Name()) 249 + } 250 + 251 + return ref, nil 252 + } 253 + 254 func (g *GitRepo) SetDefaultBranch(branch string) error { 255 ref := plumbing.NewSymbolicReference(plumbing.HEAD, plumbing.NewBranchReferenceName(branch)) 256 return g.r.Storer.SetReference(ref)
+1
knotserver/handler.go
··· 106 r.Get("/tags", h.Tags) 107 r.Route("/branches", func(r chi.Router) { 108 r.Get("/", h.Branches) 109 r.Route("/default", func(r chi.Router) { 110 r.Get("/", h.DefaultBranch) 111 r.With(h.VerifySignature).Put("/", h.SetDefaultBranch)
··· 106 r.Get("/tags", h.Tags) 107 r.Route("/branches", func(r chi.Router) { 108 r.Get("/", h.Branches) 109 + r.Get("/{branch}", h.Branch) 110 r.Route("/default", func(r chi.Router) { 111 r.Get("/", h.DefaultBranch) 112 r.With(h.VerifySignature).Put("/", h.SetDefaultBranch)
+31
knotserver/routes.go
··· 456 return 457 } 458 459 func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) { 460 l := h.l.With("handler", "Keys") 461
··· 456 return 457 } 458 459 + func (h *Handle) Branch(w http.ResponseWriter, r *http.Request) { 460 + path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r)) 461 + branchName := chi.URLParam(r, "branch") 462 + l := h.l.With("handler", "Branch") 463 + 464 + gr, err := git.PlainOpen(path) 465 + if err != nil { 466 + notFound(w) 467 + return 468 + } 469 + 470 + ref, err := gr.Branch(branchName) 471 + if err != nil { 472 + l.Error("getting branches", "error", err.Error()) 473 + writeError(w, err.Error(), http.StatusInternalServerError) 474 + return 475 + } 476 + 477 + resp := types.RepoBranchResponse{ 478 + Branch: types.Branch{ 479 + Reference: types.Reference{ 480 + Name: ref.Name().Short(), 481 + Hash: ref.Hash().String(), 482 + }, 483 + }, 484 + } 485 + 486 + writeJSON(w, resp) 487 + return 488 + } 489 + 490 func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) { 491 l := h.l.With("handler", "Keys") 492
+4
types/repo.go
··· 67 Branches []Branch `json:"branches,omitempty"` 68 } 69 70 type RepoDefaultBranchResponse struct { 71 Branch string `json:"branch,omitempty"` 72 }
··· 67 Branches []Branch `json:"branches,omitempty"` 68 } 69 70 + type RepoBranchResponse struct { 71 + Branch Branch `json:"branch,omitempty"` 72 + } 73 + 74 type RepoDefaultBranchResponse struct { 75 Branch string `json:"branch,omitempty"` 76 }