vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Open a deleted file instead of failing the page
bef0c093da662024c936eb2c230cf2a3521ecbb9 · Keenan Nemetz · 8d ago · parent f64c77e4
Open a deleted file instead of failing the page A deletion has an old path and no new one, and pathspec returned both sides to git. Git refuses an empty pathspec outright, so opening a deleted file on a commit page answered 500 and the file could not be reviewed at all. The per-file read this branch gives the Files tab would have extended that to every deleted file in a change. Return one path for a deletion, both only for a rename, and none when a row has no paths at all. No paths means there is no patch to ask for, which is not the same as every path: callers stop before asking git instead of printing the whole commit into a single file's pane. TestPathspecNamesTheSideThatExists pins the four shapes, and TestCommitPageShowsADeletedFile is the page that used to 500. The request Files test now carries a deletion too, and opens it.
server/issues_changes_test.go +18−2
| @@ -718,6 +718,14 @@ func TestRequestFilesListsEveryChangedFile(t *testing.T) { | |||
| 718 | 718 | files[name] = name + "\n" | |
| 719 | 719 | } | |
| 720 | 720 | feature, _ := f.cloneWithChange(t, files, "a big change") | |
| 721 | // A deletion rides along: it has one path and no new one, which is the shape | ||
| 722 | // that used to make the page fail when it was opened. | ||
| 723 | if _, errs, err := runGit(t, feature, "rm", "-q", "readme.md"); err != nil { | ||
| 724 | t.Fatalf("rm: %s", errs) | ||
| 725 | } | ||
| 726 | if _, errs, err := runGit(t, feature, "commit", "-qm", "drop the readme"); err != nil { | ||
| 727 | t.Fatalf("commit: %s", errs) | ||
| 728 | } | ||
| 721 | 729 | if _, errs, err := f.git(feature, "push", f.sshURL(f.repo), "HEAD:refs/heads/feature"); err != nil { | |
| 722 | 730 | t.Fatalf("feature push: %s", errs) | |
| 723 | 731 | } | |
| @@ -733,10 +741,10 @@ func TestRequestFilesListsEveryChangedFile(t *testing.T) { | |||
| 733 | 741 | ||
| 734 | 742 | filesURL := "/r/" + f.repo + "/requests/" + id + "/files" | |
| 735 | 743 | _, page := f.browserGet(t, filesURL, cookie) | |
| 736 | if !strings.Contains(page, "4 changed") { | ||
| 744 | if !strings.Contains(page, "5 changed") { | ||
| 737 | 745 | t.Errorf("the tree does not count every file:\n%.2000s", page) | |
| 738 | 746 | } | |
| 739 | for _, name := range []string{"a-big.txt", "b.txt", "docs/c.txt", "z.txt"} { | ||
| 747 | for _, name := range []string{"a-big.txt", "b.txt", "docs/c.txt", "readme.md", "z.txt"} { | ||
| 740 | 748 | if !strings.Contains(page, filesURL+"/"+name) { | |
| 741 | 749 | t.Errorf("the tree is missing %s:\n%.2000s", name, page) | |
| 742 | 750 | } | |
| @@ -747,6 +755,14 @@ func TestRequestFilesListsEveryChangedFile(t *testing.T) { | |||
| 747 | 755 | !strings.Contains(page, `data-highlight-side="new">z.txt<`) { | |
| 748 | 756 | t.Fatalf("the selected file has no patch:\n%.2000s", page) | |
| 749 | 757 | } | |
| 758 | // The deletion opens too: one path, no new one, and its removed lines. | ||
| 759 | resp, page = f.browserGet(t, filesURL+"/readme.md", cookie) | ||
| 760 | if resp.StatusCode != http.StatusOK { | ||
| 761 | t.Fatalf("deleted file = %d:\n%.2000s", resp.StatusCode, page) | ||
| 762 | } | ||
| 763 | if !strings.Contains(page, `data-highlight-side="old">v1<`) { | ||
| 764 | t.Fatalf("the deleted file has no patch:\n%.2000s", page) | ||
| 765 | } | ||
| 750 | 766 | } | |
| 751 | 767 | ||
| 752 | 768 | func TestLineAnchoredReviewCommentFromTheWeb(t *testing.T) { | |