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.
Record the default branch summary when a push lands
8dc56e4e258dd56e2c20776f80d61dbed4993f31 · Keenan Nemetz · 9d ago · parent 20442b59
Record the default branch summary when a push lands The landing card showed the default branch tip and the language it is mostly made of by running `symbolic-ref`, `rev-parse`, `log -1` and `ls-tree -r` per repository on every home page read. Those facts change only when a push moves the branch, so the push now records them. - `repos` carries head_sha, head_subject, head_author, head_when, language and lang_class, and `Index.Entry` returns them with the rest of the row. - `Store.RefreshHead` recomputes the summary and skips the tree walk when the recorded tip is still the branch tip, so a metadata or tag push costs one rev-parse. It runs from post-receive, from the rebuild, and after the default branch changes in settings. - The language mapping moved to `internal/lang`, shared by the web pages and the summary; `fileClass` and `languageFor` are now one table. - The home cards read the head, language, counts, ACL and newest event time from the index. The home page starts no git process at all; the all-git card builder stays as the fallback for a Web without an index. Load harness at concurrency 4 with three repositories: home goes from 243 to 749 req/s, p50 from 16 ms to 5 ms, and the server runs no git child process for those requests.
server/web/home_test.go +1−33
| @@ -1,38 +1,6 @@ | |||
| 1 | 1 | package web | |
| 2 | 2 | ||
| 3 | import ( | ||
| 4 | "testing" | ||
| 5 | |||
| 6 | "github.com/rodent-software/vole/core/git" | ||
| 7 | ) | ||
| 8 | |||
| 9 | func TestTopLanguageCountsFilesNotBytes(t *testing.T) { | ||
| 10 | tree := []git.Entry{ | ||
| 11 | {Type: "blob", Name: "main.go"}, | ||
| 12 | {Type: "blob", Name: "server/server.go"}, | ||
| 13 | {Type: "blob", Name: "README.md"}, | ||
| 14 | {Type: "blob", Name: "big.bin"}, | ||
| 15 | {Type: "tree", Name: "vendor"}, | ||
| 16 | } | ||
| 17 | name, class := topLanguage(tree) | ||
| 18 | if name != "Go" || class != "lang-go" { | ||
| 19 | t.Fatalf("top language = %q (%q), want Go (lang-go)", name, class) | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | func TestTopLanguageIgnoresUnknownWhenAnythingIsKnown(t *testing.T) { | ||
| 24 | tree := []git.Entry{ | ||
| 25 | {Type: "blob", Name: "a.bin"}, | ||
| 26 | {Type: "blob", Name: "b.bin"}, | ||
| 27 | {Type: "blob", Name: "notes.md"}, | ||
| 28 | } | ||
| 29 | if name, _ := topLanguage(tree); name != "Markdown" { | ||
| 30 | t.Fatalf("top language = %q, want Markdown", name) | ||
| 31 | } | ||
| 32 | if name, class := topLanguage([]git.Entry{{Type: "blob", Name: "a.bin"}}); name != "" || class != "" { | ||
| 33 | t.Fatalf("unknown-only tree = %q (%q), want empty", name, class) | ||
| 34 | } | ||
| 35 | } | ||
| 3 | import "testing" | ||
| 36 | 4 | ||
| 37 | 5 | func TestPaginateClampsToTheFeed(t *testing.T) { | |
| 38 | 6 | events := make([]activityEvent, 120) | |